Найти тему

Уроки по Game Maker Studio 2 для начинающих (Часть 5)

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

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

Для этого достаточно нам добавить всего одно действие. А именно, назначить стену родителем для данного блока. Как это сделать и для чего?

Заходим в объект блока. Нажимаем на кнопку "Parent" (что переводится как "родитель").

Первый шаг
Первый шаг

Далее, в открывшемся окне жмем на три точки.

Второй шаг
Второй шаг

А там уже выбираем объект стены (Wall).

Третий шаг
Третий шаг

Щелкаем на него и все. Теперь для блока родителем назначен блок стены.

Что это значит? Вообще это достаточно обширная тема для изучения. Но для нас это значит, что мячу теперь не принципиально сталкивается ли он с объектом стены или с объектом блока, он все равно будет отскакивать. Так как для нашего мяча блок - это теперь тоже самое что и стена. Если в коде мяч каким-то образом взаимодействует со стеной, то и с блоком код повторится. Это конечно все очень утрировано. Но запустите игру на данном этапе и потестируйте.

Мяч теперь отскакивает как от стен, так и от блоков.

Есть конечно там один баг, который вы встретите, но надеюсь вы сами в силах его поправить. Ладно, чуть подскажу. Если мяч загнать между блоками, то прилетев на блок сверху, мяч просто залипнет. Он не отскочит. Все потому, что мы код столкновения со стеной для данного случая не прописывали. Ведь изначально мы не предполагали, что мяч может прилететь сверху на стену. У нас же нет под битой стены.

Наш первый баг залипания мяча на блоке
Наш первый баг залипания мяча на блоке

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

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

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

//Поле влево вверх
if dir=0 && place_meeting(x,y-spd,Wall) {dir=2}
if dir=0 && place_meeting(x-spd,y,Wall) {dir=1}
if dir=0 && place_meeting(x,y-spd,Wall) && place_meeting(x-spd,y,Wall) {dir=3}

Вот самый первый наш случай. Когда мяч летит влево и вверх. Тут есть три варианта: когда мяч сталкивается со стеной (а теперь и с блоком) сверху, слева и одновременно сверху и слева.

Давайте, выделим один из данных случаев, а именно столкновение со стеной сверху, т.е. первая строчка данного кода:

if dir=0 && place_meeting(x,y-spd,Wall) {dir=2}

Здесь мы проверяем, если мяч летит влево вверх И над ним на spd пикселей выше есть объект стены, то мяч меняет направление на влево вниз (dir=2). Т.е. логично, что сюда нужно вклинить кусок кода, где блок бы уничтожался.

Давайте эту первую строчку немного доработаем:

if dir=0 && place_meeting(x,y-spd,Wall) {
dir=2
if place_meeting(x,y-spd,Block) {
b=instance_place(x,y-spd,Block)
with(b) {instance_destroy()}
}
}

Так что же тут у нас. Т.е. условие не изменилось Все так же проверяем что направление у мяча dir=0 и есть объект стены выше, и если да, то так же меняем направление на dir=2.

Тут без изменений. А вот ниже добавлены еще три строчки.

Тут мы проверяем есть ли блок выше мяча в момент столкновения со стеной. Может быть немного сложно понять. Но блок у нас - это и блок и стена одновременно для мяча (так как блок - это теперь родитель стены). Для смены направления мяча мы используем проверку столкновения именно со стеной. А вот для разрушения нужно проверить, что стена - это на самом деле блок. Если сложно понять, то задавайте вопрос в комментариях, постараюсь объяснить проще.

Так вот, смотрим, в том же месте, где стоит стена(сверху) есть ли объект блока? Если да, то мы переменной b присваиваем id этого блока. А далее с объектом b производим уничтожение с помощью функции with.

И вот тут у нас появилось очень много нового. Для начала, давайте постараемся понять, что такое id объекта. Дело в том, что каждый объект, который мы ставим в уровень в редакторе комнат или создаем кодом, имеет свой уникальный номер. Через этот номер можно обратиться именно к этому образцу объекта.

Помните, мы обращались из объекта Биты к объекту мяча, когда нажимали клавишу пробел с помощью точки:

if keyboard_check(vk_space) {
Ball.fixed=false
}

Т.е. в объекте Ball переменная fixed должна была смениться на false. В нашем случае все работает отлично, так как объект Ball один на уровне. А если бы у нас было несколько мячей? Данный код бы сменил переменную fixed у каждого мяча на false. Но что если бы мы захотели поменять данную переменную только у одного конкретного мяча на уровне? Т.е. у одного образца объекта. Вот тут как раз необходимо было бы обратиться по уникальному номеру - этому самому id.

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

id образца объекта
id образца объекта

Но ведь нам нужно узнать, id именно того блока, с которым столкнулся мяч. Вот тут и пригодится функция instance_place, которая возвращает id объекта, находящегося в тех координатах, которые мы указываем. И id этого образца объекта мы тут же присваиваем переменной b (можно выбрать любое название).

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

b.fixed=false

И т.д.

Ну в данном случае b - это у нас id объекта блока и переменной fixed у него конечно же нет.

Теперь давайте перейдем к функции with.

Она переводится как С и имеет конструкцию:

with (объект с которым мы хотим что-то сделать) {код}

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

with(b) {instance_destroy()}

Если внимательно слушали, то вы можете спросить, а почему в данном случае не обратиться через точку. Т.е. что-то типа того:

b.instance_destroy()

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

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

Демонстрация разрушения блока и бага "залипания" мяча
Демонстрация разрушения блока и бага "залипания" мяча

Теперь осталось добавить по аналогии для каждого случая полета мяча. Расписывать уже не буду. Надеюсь вы уже сами сможете доработать код для каждого случая.

Тут возможен еще один баг. Пока о нем говорить не буду. При продолжительном тестировании вы должны будете на него нарваться. Тем интереснее будет для вас.

Всем спасибо за то, что дочитали статью до конца! Делитесь статьей, задавайте вопросы и т.д.

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

До новых встреч! Думаю вопросов будет теперь еще больше.