Article
OO
Oliver Orangers
02/12/25
Урок 06. Враги

Привет! Мы продолжаем наш цикл разработки своей игры в жанре рогалик в Gamemaker!

Сегодня мы займемся созданием врагов для нашей игры, их появлением и поведением.

Для начала создадим спрайт врага. Сразу с анимацией, так как враги у нас будут всегда в движении.

Получился у меня вот такой незамысловатый sGoblin.


Теперь мы создадим для нашего гоблина новый объект. В дальнейшем мы можем добавить родительский объект для всех врагов, чтобы он выступал их шаблоном, но пока у нас мало объектов, об этом можно не думать.

Новый объект для врага назовем как хотим, я назову oGoblin.


Для врагом поставим галочку слева “Твердый”. Это нам понадобится для одной функции, чтобы враги сталкивались друг с другом и имели размер, а не просто сливались в одну массу.

Для врагов для удобства мы будем делать события в “PreCreate” - это “Определения переменных”. Работает это как событие “создать”, но позволяет редактировать значения удобнее для дочерних объектов или даже вручную для каждого отдельного экземпляра(объекта). Удобно!


Нажмем слева внизу у нашего гоблина на “Определение переменных” и затем “Добавить”. Добавим две переменные, без которых наш враг точно не сможет. Переменную “enemySpeed” и “enemyHP” - скорость врага и его очки здоровья.


Теперь укажем, чему они будут равны. В любой момент мы сможем это отредактировать, так что экспериментируем. Я хочу чтобы скорость была 0.5, а здоровье на 2 пули.


Событие “Создать”, в таком случае, нам пока не нужно, а вот ходить врагов заставить мы можем уже сейчас.

Сделаем для этого событие “шаг”.

И укажем простую вещь.

if (instance_exists(oPlayer))

{

mp_potential_step(oPlayer.x, oPlayer.y, enemySpeed, false);

}


На самом деле, сделать преследование можно очень и очень по-разному. Тут и пути можно задействовать и move_toward и сложные коды. Однако из всех вариантов этот мне показался весьма простым и достаточно адекватным по своему исполнению. Посмотрим, как он работает, добавив парочку гоблинов в комнату и запустив ее тест!


Естественно, у этой функции есть и свои минусы, но нам пока вполне хватит и того, что она предлагает.

Чтобы наши гоблины имели глубину, в шаге укажем уже знакомый с прошлого занятия “depth = -bbox_bottom”, который укажет, что глубина всегда зависит от положения нижней линии хитбокса.

Получение урона можно реализовать очень просто, но мы немного усложним для того, чтобы добавить врагам кадры неуязвимости после получения урона. Это нам поможет в ситуациях, когда враг должен получить именно 1 удар, а без кадров сможет получить случайно больше, чем нужно.


Итак, добавим две строчки с переменными hurt и hurtTimer.

hurt будет отвечать за то, получил ли монстр урон, а hurtTimer вернее было бы назвать “Количество кадров неуязвимости у монстра после получения урона”.

Находим новое событие в объекте нашего врага, которое работает супер легко. Столкновение с объектом oBullet.

Как понятно по названию, код в этом событии срабатывает когда? При столкновении с oBullet, с нашей пулей.

Давайте там напишем следующий код:


hurt = 1;

id.enemyHP -= global.bulletDmg;

if enemyHP <= 0

{

instance_destroy();

}


При столкновении с пулей мы говорим, что переменная hurt становится равной 1, мол, он ранен, больше по нему урон не пройдет, а затем из переменной enemyHP вычитаем переменную, которая хранит данные об уроне нашей пули. Это может быть и глобальная переменная и обычная, которая записана в самой пуле. Может быть и просто число, которое не получится уже настроить, но тем не менее. Итак, мы вычли число. Условную единицу(1). Теперь проверим, сколько ХП осталось у врага. и если меньше или равное 0, то удаляем объект из комнаты, уничтожая его.

Теперь вопрос. Зачем нам hurt?

Затем, чтобы сделать покрас ударенный врагов и предотвратить урон по ним не в нужное время. Зайдем в “шаг” гоблина и напишем следующее:

//Получение урона

if hurt = 1

{

image_blend = c_red;

if hurtTimer > 0 hurtTimer--;

if hurtTimer <= 0

{

image_blend = c_white;

hurt = 0;

hurtTimer = 5;

}

}


Мы написали, что если наша переменная hurt равна 1, что происходит при столкновении с пулей, то враг меняет свой image_blend со стандартного белого на красный, а значит, на него наложится красный слой умножения, значительно перекрасив его в красный.

Затем, пока hurtTimer больше 0, он будет уменьшается на 1.

И если он равен или меньше 0, то враг вернется в обычный цвет и сделает hurt опять равным 0. Круто!

Теперь мы хотим, чтобы монстры лезли из спаунеров. Неких невидимых объектов, которые создают монстров через какой-то промежуток.

Давайте нарисуем для него удобным спрайт обычного прямоугольника 16 на 16!

Это будет обычная ячейка для спауна нашего монстра.

Объект назовем oSpawner, сделаем его невидимым игроку в комнате, убрав галочку с “Видимый” и создадим этому объекту событие создать!

В нем запишем: timer = random_range(100,200);

Это значит, что при создании этого объекта его переменная timer получит случайное число от 100 до 200.

Это будет время до появление монстра в кадрах.


Теперь создадим “Шаг” и укажем там:

if timer > 0 timer--;

if room = rForest1 and !place_meeting(x,y,oEnemy)

Это значит, что таймер будет уменьшаться, если он больше 0. Если комната равна (название комнаты) и этот объект не сталкивается с другим гоблином (а потом сделаем, что в целом с любым монстром), то что-то будет происходить. А именно - создание монстра!

Проверку на комнату добавляем, так как у нас будут разные комнаты по наполнению и сложности, а проверка на столкновение ради того, чтобы монстры не застряли друг в друге из-за того, что мы поставили им “твердый”.

Внутри добавляем код до состояния:

if timer > 0 timer--;

if room = rForest1 and !place_meeting(x,y,oGoblin)

{

if (timer <= 0)

{

timer = random_range(100,200);

instance_create_layer(x,y,"Instances",oGoblin);

}

}


Выходит, что если мы в комнате rForest и гоблин не сталкивается со спаунером, то еще раз проверяет на то, чему равен таймер. Если меньше или равен 0, то задает новое значение(обновляет) таймер на случайное значение от 100 до 200 и создает гоблина на слое Instances.

Таким образом можно сделать создание и время для любого монстра!

Разместим oSpawner в комнате по краям и протестируем!


Я удалил старых врагов, и поставил по 4 спайнера с каждой стороны.

Наверное, будет тяжело!


Подредактируем значения и тестируем!

Выходит прекрасно, друг мой.

В следующем руководстве мы займемся добавлением звуков, а скоро и лутом, который будет выпадать с монстров!

Ссылка на следующее руководство: https://cr5.space/h/ru-gamemaker/post/8

Peace!


Comments