Привет, друзья! Продолжаем наш цикл статей про разработку своего рогалика. На прошлом занятии мы с вами сделали и настроили UI - пользовательский интерфейс, а сегодня узнаем, как физические обломки от монстров усиливают чувство вознаграждения и воздействия.
Представьте две сцены:
Лут — это награда. Но что, если самая важная награда — не опыт в цифрах и не случайный предмет в инвентаре, а мгновенное, визуальное удовлетворение? Психология игрока устроена так, что мы обожаем наблюдать прямую связь между действием и результатом. Когда после убийства монстра из него высыпаются фрагменты — будь то клыки, куски хитина, брызги слизи или осколки доспехов — мы видим материальное доказательство нашего успеха. Это лут-бокс, который вскрывается автоматически и дарит не предмет, а чистый, концентрированный fun. В этом руководстве мы поговорим о том, как правильно «настроить» этот процесс.
Сегодня мы узнаем, как добавить немного больше фана в такое обычное действие... как убийство монстра!
Для начала нарисуем спрайт, который я назову sFragmentEnemy.
Это очень простой спрайт 6 на 6, с разными кадрами.
Именно этот объект со случайным кадров будем выпадать из нашего противника после смерти.
Далее создадим новый объект oFragmentEnemy и привяжем этот спрайт к нему.
У этого объекта будет 3 события. В "Создать" мы заинициализируем все необходимые переменные, в "Шаге" добавим анимацию - bounce от пола, время пропадания и т.п., в "Изобразить" будем корректно отображать наш объект, например его высоту.
Давайте для начала добавим все необходимые переменные в "Создать"
GMLbounce = 0; //Количество уже совершенных прыжков
deteriorate = 0; //Время, которое объект существует. Со временем он исчезнет
z = 0; //Текущая высота от точки старта, для прыжков
spd = 0; //Скорость
fric = 0; //Разброс
image_speed = 0; //Скорость анимации
image_index = irandom(image_number-1); //Рандомное выпадение кадра
collisionMap = layer_tilemap_get_id(layer_get_id("Col")); //Коллизия, чтобы наши фрагменты не вышли за пределы
image_xscale = choose(-1,1); //Случайное отзеркаливание по оси X, для разнообразия
depth = oPlayer.depth+100; //Глубина всегда под игрокомТеперь мы можем также заинициализировать несколько особых переменных, которые мы, вероятно, захотим менять часто и в разных других аналогичных "Фрагментов".
Запишем эти переменные в "Определение переменных под объектом":
bounceCount - частота прыжков нашего фрагмента, его отскоки;
bounceSpeed - скорость прыжков;
bounceHeight - их высота;
deteriorateAfter - через сколько кадров начнет исчезать;
deteriorateTime - сколько кадров будет исчезать;
Вот теперь добавим код в "Шаг":
GML//Bounce
if (bounceCount != 0)
{
bounce += (pi * bounceSpeed);
if (bounce > pi)
{
bounce -= pi;
bounceHeight *= 0.6;
bounceCount--;
}
z = sin(bounce) * bounceHeight;
}
else z = 0;В приведенном выше коде мы видим, что если наш объект еще не прыгал, то он начнем прыгать, пока bounceCount не станет равный 0.
Теперь добавим и исчезновение фрагмента там же, в "Шаге", но чуть ниже.
GML//Deteriorate
deteriorate++;
if (deteriorate > deteriorateAfter)
{
image_alpha -= 1/deteriorateTime;
if (image_alpha <= 0) instance_destroy();
}Тут всё легко, каждый кадр наша переменная deteriorate увеличивается на 1.
Если она станет больше deteriorateAfter, то каждый кадр непрозрачность будет уменьшаться, доведя объект до 0 видимости.
Затем фрагмент уничтожится.
А теперь к фрикшину.
Без него все наши фрагменты будут выпадать строго в одной точке, слипаясь.
А мы хотим, чтобы они разлетались в разные стороны.
GML//Friction
fric = 0.05;
if (z == 0) fric = 0.10;
//Move
x+= lengthdir_x(spd, direction);
y+= lengthdir_y(spd, direction);
if (tilemap_get_at_pixel(collisionMap, x, y) > 0) spd = 0;
spd = max(spd-fric, 0);Отлично!
Теперь осталось только добавить одну маленькую вещь. В Gamemaker нет понятия 3 координата. Там нет z - высоты, так как движок заточен для 2д игр, не 3д.
Поэтому мы сделаем свое отображение z. В событии "Изобразить":
GMLdraw_sprite_ext(
sprite_index,
image_index,
x,
y-z,
image_xscale,
image_yscale,
image_angle,
image_blend,
image_alpha
) С помощью draw_sprite_ext мы легко смогли выдать все важные данные о том, как корректно отображать наш объект, его позицию z и прозрачность.
Половина сделана. Теперь нужно зайти в наших монстров и настроить им выпадение этих самых фрагментов после их уничтожения. Начнем с двух вещей:
Создадим событие "Уничтожить", ведь именно в нем должен срабатывать код выпадения фрагментов. Именно после уничтожения противника.
И добавим еще 3 определенных переменных, опять же, для удобного редактирования вне событий.
entityFragmentCoun - количество объектов, выпадающих из противника
entityFragment - название объекта, который должен выпадать из противника
soundDeath - звук смерти монстра (опционально)
А теперь запишем код в новосозданное событие "Уничтожить":
GML//Проигрывается звук смерти
audio_play_sound(soundDeath,1,-1,global.soundVolume);
//Скрип выпадения фрагментов после смерти
if (entityFragmentCount > 0)
{
fragmentArray = array_create(entityFragmentCount, entityFragment);
DropItems(x,y,fragmentArray);
}
if (entityDropList != -1)
{
DropItems(x,y,entityDropList);
}Тут всё просто, мы будем проверять наличие entityFragmentCount. Если должно выпасть больше 0, то создастся список "fragmentArray", который будет хранить название и количество фрагментов. Сейчас мы добавим этот скрипт - DropItems, но сначала не забудем добавить новую переменную "entityDropList" в событие "Создать".
Отлично, создаем теперь новую функцию в папке "Скрипты".
Назовем ее DropItems
GMLfunction DropItems(){
var _items = array_length_1d(argument2);
if (_items > 1)
{
var _anglePerItem = 360/_items;
var _angle = random(360);
for (var i = 0; i < _items; i++)
{
with (instance_create_layer(argument0, argument1, "Instances", argument2[i]))
{
direction = _angle;
spd = 0.75 + (_items * 0.1) + random(0.1);
}
_angle += _anglePerItem;
}
}else instance_create_layer(argument0, argument1, "Instances", argument2[0]);
}Тут тоже ничего сложного нет! Просто каждому фрагменту при появлении присвоится угол, куда он отскочит и с нужной скоростью он полетит в ту часть. Ну и самое важное - сам фрагмент появится. Мы же для этого и писали этот код, верно?
Давайте попробуем запустить игру на F5!
Вот такая красота у нас вышла, а если ты, разработчик, добавил еще и звук смерти, то вообще умничка!
Ссылка на следующую статью: https://cr5.space/h/ru-gamemaker/post/22
Всем peace!
Статью подготовил Oliver Orangers специально для ims.
Ссылка на vk: https://vk.com/oliora
Ссылка на telegram: https://t.me/oliver_orangers