Приветствую всех вас, уважаемые читатели! В прошлой статье мы начали собирать простую игру типа Арканоид. Сегодня постараемся доработать ее. Если вы еще не читали первую часть даного урока, то очень советую предварительно прочиать его.
Учимся проверять коллизии
В прошлый раз мы сделали так, что бита, доезжая до стены, останавливалась. Но что если поставить стену посреди уровня и попробовать запустить игру? Бита будет игнорировать данную стену и проезжать сквозь нее, пока не доедет до самой крайней стены, где и остановится.
И что же нам делать? Каждый раз вручную менять координату для проверки? Нет. Есть более универсальный способ. Давайте сделаем так, чтобы бита, прежде чем сдвинуться, проверяла нет ли на пути движения стены. Т.е. мы будем проверять коллизии (столкновения) биты с объектом стены. Для этого в GMS2 есть функция place_meeting, которая как раз и проверяет, будет ли столкновение, если поставить биту в указанные в функции координаты. Давайте немного изменим наш первоначальный код в шаге биты. Напомню, изначально он был таким:
if keyboard_check(vk_right) {
if x<891 {x+=spd}
}
if keyboard_check(vk_left) {
if x>67 {x-=spd}
}
Т.е. сначала мы проверяли, нажата ли определенная клавиша, затем мы проверяли, положение координаты x биты по отношению к какой-то крайней координаты (дальше которой бита не должна ехать) и только тогда сдвигали биту. Так воттеперь мы попробуем применить в коде нашу новую функцию place_meeting.
if keyboard_check(vk_right) {
if not place_meeting(x+spd,y,Wall) {x+=spd}
}
if keyboard_check(vk_left) {
if not place_meeting(x-spd,y,Wall) {x-=spd}
}
Меняем код на вышеуказанный и запускаем игру. Теперь мы видим, что бита всегда упирается в стену, где бы мы ее не поставили. Давайте подробнее разберем этот участок кода, для движения вправо:
if keyboard_check(vk_right) {
if not place_meeting(x+spd,y,Wall) {x+=spd}
}
Первая строка проверяет нажата ли клавиша "стрелка вправо". Если да, то будет выполняться тот код, что идет между скобками {}.
А в них далее как раз идет еще одна проверка:
if not place_meeting(x+spd,y,Wall)
Где not, читается как не, т.е. оно инвертирует следующую за ним функцию. И дословно данное условие можно прочитать как "если поместить биту в координаты x+spd и y и в них НЕ будет столкновения с объектом Wall".
Т.е. бита пока не перемещается на spd пикселей вправо, а лишь проверяет, нет ли в тех координатах стены, и если их нет тогда и выполнится сам сдвиг биты, т.е. код, что идет в следующих скобках {}, а именно: x+=spd .
В GMS2 допускается сокращение, можно не писать слово not перед функцией, а заменить его на восклицательный знак перед ней. Так писать гораздо удобнее и быстрее. Так что если вы увидете где-то в коде:
!place_meeting(x+spd,y,Wall)
знайте, что это тоже самое что и
not place_meeting(x+spd,y,Wall)
По этому давайте сразу сделаем наш код чуть короче и удобнее для чтения:
if keyboard_check(vk_right) {
if !place_meeting(x+spd,y,Wall) {x+=spd}
}
if keyboard_check(vk_left) {
if !place_meeting(x-spd,y,Wall) {x-=spd}
}
Все, теперь можно убрать объекты стены с середины комнаты, которые мы вставляли для тестирования в начале урока. Теперь давайте перейдем непосредственно к мячу.
Создание объектов с помощью кода
Помните в первом уроке, когда мы расставляли объекты в редакторе комнат, мы создали слой "Ball", на который пока ничего не ставили? Так вот пришло время. Давайте зайдем в событие создания биты (событие Create) и дополним немного код.
Если вы помните, данное событие выполняется лишь раз. По этому тут мы и пропишем код для создания мяча. Если же мы напишем код создания мяча в событии шага (Step), то мячей у нас будет создаваться бесконечное кол-во, что в итоге может подвесить игру через какое-то время из за большого кол-ва созданных объектов.
Итак, в событии Create мы уже писали с вами код. Там должна быть всего одна строчка, в которой мы создали переменную скорости и присвоили ей значение 5:
spd=5
Давайте чуть ниже этой строчки пропишем код создания самого объекта мяча. Создавать его будем прямо над битой, как будто он лежит на ней.
Для создания объектов кодом в GMS2 есть функция instance_create_layer.
Тут думаю важно объяснить, что такое инстанс (instance) объекта. Дело в том, что те объекты, которые мы создавали в первом уроке и которые у нас находятся в дереве ресурсов - это просто шаблоны. А в самом игровом мире мы создаем их копии, т.е. инстансы данных объектов. Важно сразу уметь понимать и отличать эти понятия. Т.е. в GMS2 есть понятие и объекта (object) и инстанса (instance). Давайте разберем на примере.
Например, мы создали объект какого-то врага, скажем скелета. Он находится у нас в дереве ресурсов. В данном объекте мы прописали весь код для движения скелета, его ИИ и т.д. Т.е. мы создали сам ОБЪЕКТ. По сути это шаблон. Далее мы в редакторе комнат начинаем вытягивать скелета из дерева ресурсов и расставлять их по уровню (как мы это делали с объектами стен в нашем арканоиде). Так вот, мы расставляем уже копии данного объекта, т.е. ИНСТАНСЫ. В каждом отдельном инстансе мы уже можем менять код независимо от других копий. Т.е. мы можем в одном инстансе скелета сделать так, чтобы он был одет в шлем, при этом остальные скелеты будут без шлемов, так как мы прописали код только в одном инстансе. Если же мы пропишем, чтобы шлем был одет в коде самомго объекта скелета, т.е. в коде шаблона, то шлем появится сразу на всех скелетах. Т.е. тут нужно уяснить, что замена кода в объекте влияет на код инстансов, но замена в коде инстанса, не меняет сам код объекта. Это важно знать и понимать. Итак, вернемся к коду создания мяча.
Добавляем в событии создания биты еще одну строчку кода:
spd=5
instance_create_layer(x,y-20,"Ball",Ball)
Данной строчкой кода мы создаем в координатах x и y-20 на слое "Ball" объект Ball (ну правильнее говорить создаем инстанс объекта, как мы уже выяснили, но можно говорить, что создаем объект). Обратитье внимание, что название слоя указываем в кавычках, а название объекта без. А то у нас и слой и объект имеют одинаковые названия и может возникнуть путаница. Называть их одинаково конечно не обязательно.
Почему мы создаем мяч в координатах x и y-20 ? Еще немного математики.
Так как мы пишем данный код в объекте биты, то x и y будут являтся цетром биты. Мы это установили в первой части урока.
Так вот, от центра биты до ее верха получается 12 пикселей (так как сама бита у нас 24 пикселя в высоту), а сам мяч у нас 16 пикселей в высоту и половина это 8. 12 + 8 = 20. Отсюда координата y-20. Создаются же объекты всегда в тех координатах, которые мы указали в самом спрайте (тот самый серый крестик, который видно на рисунке выше у мяча и биты).
Код написан. Запускаем игру.
Отлично, мяч появился стоит прямо над битой! Но, если начать двигать биту, то мяч остается висеть на том же самом месте. Что делать?
Логично предположить, что x координата мяча, должна каждый шаг сменяться и должна быть равной x координате биты. Хорошо. Давайте пропишем это кодом. До этого мы редактировали код только в объекте биты. Пришло время писать код для мяча.
Щелкаем дважды на объект мяча, создаем для него событие шага (Step) и в нем пропишем всего одну строчку:
x = Bat.x
Т.е. каждый шаг мы делаем координату x мяча равной координате x объекта биты (Bat).
Чтобы из одногообъекта получить доступ к переменным другого объекта, достаточно просто прописать имя объекта из которого мы хотим вытянуть какую-то переменную и через точку указать имя этой переменной.
Это очень распространенный прием и мы будем очень часто им пользоваться.
Запускаем игру.
Теперь все отлично! Бита двигается вместе с мячом.
Думаю для второго урока тоже достаточно.
Спасибо, что дочитали статью до конца! Ставьте лайки, подписывайтесь, активно делитесь данной статьей, оставляйте комментарии и задавайте вопросы, если что-то непонятно. В следующих уроках мы продолжим дорабатывать нашу игру и научимся запускать мяч, сделаем так, чтобы он отскакивал от стен и разбивал блоки.