Article
OO
Oliver Orangers
02/06/25
Урок 04. Коллизия

Привет, друг!

Продолжаем наш цикл руководств для разработки своей SmashTV-style игры в Gamemaker!

Урок 04. - Коллизия.

В прошлом руководстве мы рассмотрели вопрос тайлов и лвл-дизайна. Теперь займемся кодом. Сделаем непроходимые невидимые стенки, которые будем использовать в наших уровнях!

Первым делом для удобства наших тестов, чтобы не приходилось закрывать и открывать постоянно наш тест, мы сделаем перезапуск, рестарт на кнопку R. Удобно? Очень. А для этого всего придется создать событие нажатия на кнопку R и сказать game_restart()

Эта функция, как легко догадаться, быстро перезапускает нашу игру, как-будто мы ее заново включили.



Затем займемся коллизией. Я хочу, чтобы она была в виде тайлов. Чтобы можно было рисовать удобно квадратики и они не давали нам проходить.

Зальем весь спрайт цветом, например красным. А чтобы было удобно рисовать коллизию, сделаем альфу(так в гейммейкере называется прозрачность) сделаем не 255, а меньше.

Таким образом, наши стенки для редактирования будут удобного полупрозрачного красного цвета.

Теперь создадим новый набор плиток. И поместим туда наш спрайт!

Теперь в самой комнате нарисуем на будущее стенки!

Обращу внимание, что назовем этот слой с коллизией “Col”. От английского слова “collision” - “столкновение”. Именно со слоев с названием “Col” у нас будет считываться информация о том, куда нельзя ходить игроку. Где невозможно ему быть. Имей это ввиду, друг. Называй все слои с коллизией “Col”!

Далее зайдем в oPlayer. В событие “создать”.

Напишем здесь вот такую конструкцию:

Можно прям на самом верху.

collisionMap = layer_tilemap_get_id(layer_get_id("Col"));

Что это значит? Мы поместили в новую переменную collisionMap тайлы, которые находятся на слое с названием “Col”. Грубо говоря, всю информацию о тайлах из слоя поместили в одну переменную.

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


Теперь вспомним, в каком событии наш герой перемещается по оси x и y.

Конечно, в событии, которое выполняется каждый кадр. Событие “Шаг”.


В этом событии мы написали, что перемещаемся по x и y с помощью hSpeed и vSpeed. Значит, теперь мы должны урегулировать это. Что наш hSpeed и vSpeed не может увеличиваться свободно! Если мы уперлись в стенку, значит эти скорости должны быть равны 0. Давайте их сотрем, а вместо них напишем новый скрипт. Скрипт может вмещать в себя функции, который программисты могут написать для себя. Что такое функции?

Функция - это самописный код, который можно вызывать когда-угодно. Например! У нас есть враг. Зомби. Он умеет ходить, атаковать и всё такое. И мы решили написать код для еще одного зомби. Но теперь красного! Он такой же как и обычный, зеленый, но цветом отличается, хп у него побольше, и скорость помедленнее. Чтобы не писать один и тот же код сто раз для разных нужд мы можем повторяющиеся фрагменты закинуть в функцию. И просто вызывать ее названием функции.

Так, поведение все врагов, которые просто идут за игроком можно будет просто поместить в одну функцию и не писать одно и тоже миллион раз. Это удобно, а главное, занимает меньше места, значит, меньше весит!

Давайте заменим наши 2 строчки на название новой функции PlayerCollision.

Так как это функция, пишем две скобки в конце. Это важно!


Теперь в ресурсах справа найдем папку “Скрипты” - “Scripts” и создадим там новый скрипт.

Назовем этот скрипт аналогично.

Откроем его.


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

Тут есть шапка с названием и фигурные скобки, которые “содержат” внутри код.

Давайте внутри этих скобок начнем писать код!


var _collision = false;

Этой строчкой скажем, что наша локальная переменная коллизион равна по умолчанию 0. То есть, по умолчанию мы не сталкиваемся ни с чем!

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

Если…

if (tilemap_get_at_pixel(collisionMap, x + hSpeed, y))


Если игрок сталкивается с пикселем у тайла (название слоя, где лежат нужные нам тайлы, x, y).

Добавим для x еще проверку на скорость горизонтальную, чтобы случайно не застрять внутри коллизии! Мы же не стоим на месте!


x -= x mod 16;

if (sign(hSpeed) == 1) x += 16 - 1;

hSpeed = 0;

_collision = true;

Тут мы добавляем, что если столкновение прошло, то по оси x мы чуток отодвигаемся, а hSpeed становится равным 0. Коллизия равна правде, 1.


Не забудем за этими скобками, за условием сказать, что к x прибавляется hSpeed. То есть, мы будем ходить, всегда. Просто, если мы столкнемся со стенкой, то скорость будет равна 0. Логично!

Но помним, что мы написали только часть для горизонтального движения. Остается что? Правильно! Еще и вертикальная!


Тут немного меняются x,y и hSpeed с vSpeed. Будь внимателен, друг!


А в конце пусть функция нам вернет коллизион. Он станет опять 0. То есть, даже если мы стоим у стенки, нас на условный 1 пиксель откинет назад, а коллизия будет равна неправде. Мы никогда не застрянем!

Теперь нужно проверять это!

Запускаем билд!

Всё работает шикарно!


Напомню, что столкновение проверяется только для точки основания, которая ставится у спрайта!


Полный код из скрипта для проверки:


function PlayerCollision()

{

var _collision = false;

//Horizontal Tiles

if (tilemap_get_at_pixel(collisionMap, x + hSpeed, y))

{

x -= x mod 16;

if (sign(hSpeed) == 1) x += 16 - 1;

hSpeed = 0;

_collision = true;

}

x += hSpeed;

//Vertical Tiles

if (tilemap_get_at_pixel(collisionMap, x, y + vSpeed))

{

y -= y mod 16;

if (sign(vSpeed) == 1) y += 16 -1;

vSpeed = 0;

_collision = true;

}

y += vSpeed;

return _collision;

}


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

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


Comments