Программа реализовывает простую шутер-игру. Персонаж игрока – зеленый квадрат в центре окна, управление им производится с помощью клавиш W, A, S, D. Враги игрока – красные круги, которые постоянно появляются и требуют уничтожения. Игрок умирает, когда он касается врага.
В программе реализована возможность уничтожения врагов через стрельбу, которая производится нажатием левой кнопки мыши. Программа начинается заново при нажатии клавиши ПРОБЕЛ.
Видео с демонстрацией работы программы.
Данный шутер является бесконечной игрой на получение рекорда. Количество уничтоженных врагов запоминается, при проигрыше является показателем установки рекорда.
За основу взято видео: Язык Си – Пишем простую игру шутер с помощью WinAPI =).
Программа реализована в среде Microsoft Visual Studio 2019. При клонировании репозитория в MS VS запуск программы необходимо осуществлять с помощью WinAPI_shooter.sln. После запуска программы в папке WinAPI_WinAPI_shooter/Debug будет создан файл WinAPI_shooter.exe, работающий отдельно.
Для реализации программы был создан класс object, описывающий каждый объект. Файл object.h содержит описание класса, а файл object.cpp его реализацию. Класс содержит методы для инициализации объекта, отображения на экране, подсчета сдвига объекта и задания скорости в зависимости от конечной точки. Также осуществляется возвращение некоторых данных класса с помощью методов get. Был реализован конструктор копирования и перегрузка оператора присваивания.
Была создана дружественная функция для проверки пересечения двух объектов. Проверка осуществляется между врагами и пулями, также между врагами и игроком.
Данные организованы в программе с помощью динамического массива, содержащего объекты класса. Для пуль и врагов массив один. При создании и удалении объектов массив перезаписывается.
Создание и удаление элемента динамического массива с количеством элементов, равных masCnt.
// Производится создание копии массива с количеством элементов, на единицу больше
object* buf = new object[masCnt + 1];
// Изначальный массив копируется в новый, а старый удаляется
for (int i = 0; i < masCnt; i++)
buf[i] = masObject[i];
delete[] masObject;
masObject = buf;
...
masCnt--;
// Элемент, подлежащий удалению затирается последним
masObject[i] = masObject[masCnt];
// Производится создание копии массива с количеством элементов, на единицу меньше
object* buf = new object[masCnt];
// Изначальный массив копируется в новый, а старый удаляется
for (int j = 0; j < masCnt; j++)
buf[j] = masObject[j];
delete[] masObject;
masObject = buf;Для отрисовки объектов был создан виртуальный контекст для рисования в памяти и изображение. После отрисовки изображение было скопировано из виртуальной памяти на форму.
HDC memDC = CreateCompatibleDC(dc);
HBITMAP memBM = CreateCompatibleBitmap(dc, rct.right - rct.left, rct.bottom - rct.top);
SelectObject(memDC, memBM);
...
BitBlt(dc, 0, 0, rct.right - rct.left, rct.bottom - rct.top, memDC, 0, 0, SRCCOPY);
DeleteDC(memDC);
DeleteObject(memBM);Отрисовка всех объектов производится с помощью графических примитивов: квадратов и эллипсов. Вывод текста производится с помощью функций TextOut и DrawTextA. С помощью CreateFont производится создание необходимого шрифта. При выводе текста на экран выбирается необходимый шрифт, в конце удаляется.
BeginPaint(hwnd, &ps);
SelectObject(memDC, font);
TextOut(memDC, 10, 10, (LPWSTR)buff, numChar);
DeleteObject(font);
EndPaint(hwnd, &ps);При каждом изменении положения игрока производится вычисление сдвига по осям и положение всех объектов корректируется так, чтобы игрок оставался в центре экрана.
Добавление врагов производится два раза в определенное количество тактов (rate) с использованием рандомных чисел. Количество тактов постепенно уменьшается при увеличении количества убитых врагов.
int k = rand() % rate;
if (k == 1)
NewObject(pos1 + x, pos2 + y, 40, 40, ENEMY);
if (k == 2)
NewObject(pos2 + x, pos1 + y, 40, 40, ENEMY);