Как сделать hp в game maker

Обновлено: 06.07.2024

Это небольшая статья об конструкции with и способах её применения. Предполагается, что вы уже знаете о gml и его синтаксисе, понимаете разницу между объектом и его образцами (образцы объекта), а также знаете о специальных объектах other, all, noone, self.

Примечание: Поскольку в txt2 нет разметки gml-кода, я взял на себя труд выделить ключевые слова, так, как они выглядят по-умолчанию в самом gml, чтобы код выглядел более-менее читабельным.

Конструкция with имеет несколько применений. Первоначальное применение - конструкция предназначена для выполнения одинаковых действий над всеми образцами объекта, имя которого указано в <имя объекта>. То есть, по сути, это особая форма цикла.

Как видно из примера, конструкция в цикле переберёт все образцы объекта obj_ball которые есть в комнате и передвинет их по оси х на 5 единиц вправо.
Кроме того, все действия и переменные, которые выполняются в конструкции with становятся локальными для образца в цикле, а образец, который вызвал with - внешним, и внутри самой конструкции к нему уже нужно обращаться как специальному объекту other .

Конструкция имеет другое важное применение. Она может служить для идентификации конкретного образца, и выполнению над ним действий из другого объекта. Как известно, в gml есть функции, которые работают только для конкретного образца объекта - для того, из которого его вызвали. Примером может служить функция instance_destroy() которая не имеет параметров, и уничтожает тот образец, из которого его вызвали (кстати, единственная функция, которая удаляет объекты).

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

Пример 1

Например, при взрыве (событие destroy) объекта "ракета" (obj_rocket), нужно нанести урон ракеты (damage) всем юнитам (obj_unit) в радиусе 150, и у тех, у кого здоровья (current_hp) меньше нуля - уничтожить.

obj_rocket destroy event (событие уничтожения образца объекта obj_rocket):

with ( obj_unit ) //Начало цикла
if( distance_to_object (other. id )<=150) //как видно, функция distance_to_object() возвращает расстояние от юнита до ракеты, а не наоборот, так как внутри конструкции они меняются местами, и теперь obj_rocket=other.id
current_hp-=other.damage //По сути, это сам юнит наносит сам себе урон, а урон мы берём из объекта ракеты.
if(current_hp<=0)
instance_destroy () //Вот тут юнит уничтожит сам себя, если его здоровье ниже нуля.
>
>
>

id - это встроенная переменная в любом образце, которая содержит уникальный численный идентификатор образца.

Пример 2

Сделаем все видимые объекты мячей в комнате невидимыми, а невидимые - наоборот.

Пример 3

С помощью объекта obj_player создадим объект obj_missle, и зададим ему начальную скорость и случайное направление движения. Событие не важно, предположительно, это нажатие на кнопку.

with ( instance_create (15,20, obj_missle ). id )
speed =10
direction = random (361)
>

--> Если вы только-только начали изучать игрострой и еще даже не успели скачать сам Game Maker, предлагаем вам на выбор следующие версии программы:

Если вы не согласны с какой-либо оценкой, примите участие и поставьте свой балл игре. Ваша оценка очень важна для нас ;) -->

Создание RPG, урок №2

И-так, начнём. Для начала добавим нужные нам спрайты. Сегодня их нам понадобиться всего лишь 2 штуки - спрайт врага и игрока. Дорабатываем переменные
Для начала нужно сделать регенерацию здоровья игрока. Как это сделать? Сначала добавим новую переменную, назовите её hp_max, значение на 100. Что переменная ограничивалась этим значением, нужно прописать следующий код в Степе игрока:
hp>hp_max

То есть, если здоровье больше максимального, то оно будет уравниваться к максимальному значению. С этим поняли. Теперь установим регенерацию.
В Креате игрока создайте будильник с паузой 50. Затем создаем событие этого будильника.Там запишем такой код:
hp+=1 и добавьте там опять таки этот же будильник. Теперь приблизительно раз в 2 секунды здоровье игрока будет пополняться на 1 еденицу.
Теперь нужно осуществить переход на следующий уровень. Для этого создаём ещё ону переменную, назовём её xp_max и установите её значение на 100. Затем прописываем в Степе такой код:
if global.xp=global.xp_max

<
global.lvl+=1
global.xp=0
global.xp_max = global.xp_max*2
global.hp_max+=5
>

Это значит следующее: Если опыт будет равняться максимальному, то уровень вырастет на еденицу, опыт обнулиться, для перехода на следующий уровень потребуется в два раза больше опыта, максимальное здоровье вырастет на 5 пунктов. Дальше можете написать на сколько вырастут основные характеристики. Переменные мы доделали. Перейдём к созданию ПНЦ.

Создаём объект, назовите его NPC, присвойте соответствующий спрайт.

Теперь запишем такой код в его Степе:

if point_distance(x, y, Player.x, Player.y) < 96

<
instance_change(NPC_1_1,NPC_1)
switch show_message_ext("Сюда пишите что говорит НПС", 'Сюда ответ игрока')

case 1: show_message('Сюда текст, который появиться при нажатии кнопки 1'); break;

Что это всё значит? Если игрок существует, и расстояние от него к игроку 96 пикселей, то появляется диалог с выбором ответа. Да, и ещё, чтобы не был вечный цикл. Для этого создайте аналогичный объект без кода, пустой, и что бы цикл не начался добавьте строчку кода рядом с начаолм диалога на смену объекта.Переходим к врагам.

Ваш первый враг в игре

Создаём объект врага, присваиваем соответсвующий спрайт. В Степе пишем:

if point_distance(x, y, Player.x, Player.y) < 100

Теперь если игрок существует, и его расстояние от игрока равно 100 пикселям равно 100, он начнёт двигаться к игроку со скоростью 4. Чуть не забыл, в создании мобы запишем:

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

if distance_to_object(Player) < 5

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

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

Урок окончен. Всем спасибо. В следующем уроке я научу Вас делать инвентарь.

Рекомендации, которые покажут, как надо или не надо делать.

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

Иногда, чтобы просто заставить что-то работать, вы копируете код и какого-то руководства, даже не понимая, что он делает. Кажется что всё в порядке, но на самом деле это только усугубляет проблему. Вы не сможете полностью контролировать свой проект, если вы не понимаете, как в нём работает какая-либо часть кода.

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

Предположим, вам нужно сделать пару врагов: первый с 4 HP и второй с 10 HP. Как новичок, вы подумаете, что нужно создать ещё один объект и изменять HP внутри него. Но этот вопрос можно решить проще.

Когда вы размещаете экземпляр внутри комнаты через редактор комнат, вы можете открыть окно «Код создания» (в GMS2 нужно кликнуть дважды) и писать код в нём. Таким образом вы можете задавать HP экземпляров внутри их кода создания.

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

Функция place_meeting() может использоваться для проверки столкновений между объектами. Лучше использовать эту функцию в условии, чем использовать событие столкновения, так как вы сможете больше контролировать работу столкновений.

Первый и второй аргументы — это X и Y координаты, в которых будет проверятся столкновение. Третий аргумент — это объект, с которым будет проверятся столкновение.

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

Многие новички используют условия для установки переменных ввода. Например

Но есть более простой способ. Вот этот.

Вы знаете что keyboard_check() возвращает true если нажата определённая клавиша, или возвращает false если она не нажата. Но в GameMaker'е true становится — 1, а false — 0, это просто числа. Поэтому их можно использовать в таком уравнении.

Если нажата правая клавиша, то hsp будет равен 1.

Если нажата левая клавиша, то hsp будет равен -1.

И если ни одна клавиша не нажата, то hsp будет равен 0.

Тоже самое можно применить к вертикальному положению.

Для отрисовки HUD некоторые люди используют объекты или отрисовывают их через событие Draw — добавляют их относительные позиции в координаты камеры/вьюпорта.

Внутри события Draw GUI вам не требуется добавлять позиции камеры для того, чтобы HUD следовал за ней. Это событие использует координаты окна игры, вместо координат комнаты. Поэтому, если вы рисуете что-то в (0, 0), то это будет рисоваться в верхнем левом углу игрового окна, а не комнаты. Так что, всё что вы рисуете там, остаётся там: на его позицию не влияет камера в игре. Это как ещё один слой над вашей игрой.

В этом совете я обращусь к тому, что создает путаницу среди начинающих разработчиков.

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

Давайте возьмём список структуры данных, как пример. Эта функция создаёт список и хранит его в переменной, верно?

Если я создам список в локальной переменной, он исчезнет в конце события, потому что переменная является локальной. Ведь так?

На самом деле, это работает не так. Всякий раз, когда вы создаёте список, он создаёт его внутри памяти. Именно там он и существует. Функция просто возвращает указатель, на список внутри памяти. Таким образом, переменная, которую вы используете как «список», представляет собой просто указатель, который позволяет вам получить доступ к фактическому списку в памяти.

Даже если переменная является локальной — список не существует. Помните, что переменная — это просто указатель. Чтобы уничтожить список, вам надо использовать.

Кроме того, когда вы делаете так.

Вы не создаете другой список, называемый «list_2», который совпадает с « list_1». Вы просто копируете значение указателя в эту переменную, поэтому обе переменные указывают на тот же список в памяти.

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

Когда вы создаете поверхность, она должна быть пустой, ведь так?

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

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

В раздел Gamedev попадают не только редакционные материалы, но и читательские тексты с пометкой «Блог». Вы можете нажать кнопку «Написать» и рассказать о своём опыте разработки. Подробнее о читательском контенте в разделе вы можете почитать тут.

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

Пробуем создать свой Арканоид

Я всегда всем советую начать изучение движка с создания простой игры. Да я и сам в свое время учился так. Создав 5-6 отличных друг от друга игр вы получите очень хорошую базу знаний по движку.

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

А теперь к делу.

Запускаем наш Game Maker Studio 2.

Для начало вам нужно будет зарегестрировать свой аккаунт на официальном сейте YoYoGames , чтобы войти в данный движок. Я об этом вроде говорил ранее.

Нажимаем "New" , что значит "Новый" , для создания нового проекта. У вас далее появится следующий выбор:

Тут следует немного остановиться подробнее. Движок GMS2 позволяет создавать игры на своем языке программирования GameMaker Language (GML) либо вообще без написания кода, то есть собирать игру как бы из логических блоков (Drag and Drop). Я бы рекомендовал учиться сразу писать код. Но вы можете конечно попробовать поиграть с блочной системой. Конкретно в этом уроке я буду объяснять работу именно проектов на основе кода, т.е. выбираем второй вариант. Ну а далее вы выбираете место, где будете сохранять своей проект и дадите ему имя.

Готовим ресурсы для игры

Сейчас нам необходимо будет подготовить ресурсы для игры. Как их создавать, я подробно описывал в предыдущих статьях и тут останавливаться на этом не буду.

Для игры нам будут нужны: бита, мяч, стены и блоки.

Создаем для начала спрайты для них. Я рисовал все сам прямо во встроенном графическом редакторе GMS2, по этому все очень схематично. Красным выделил на что стоит обратить внимание. В основном это размеры спрайта, его имя и где расположен его центр.

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

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

Назовите объекты так как я их назвал. Это пригодится далее в уроках. Итого у вас должно быть 4 спрайта и 4 объекта в дереве ресурсов.

Далее подготовим комнату и расставим все объекты в ней для первого уровня. Кроме мяча. Мяч мы будем создавать кодом.

Задайте ей размеры 960 пикселей в ширину и 540 пикселей в высоту. Создайте несколько слоев именно того типа, что я пометил стрелочкой (т.е. слои для объектов). Поменяйте им названия. Расположите их в том же порядке что у меня на скриншоте. И далее на каждый слой перетащите и расставьте соответствующие объекты, как они у меня расставлены в комнате. Т.е. на слой "Walls" , например, расставляем объекты "Wall" и т.д.

Так же можете поменять цвет фона. Для этого просто щелкаете на слой Background и чуть ниже выбираете нужный нам цвет. Но это не обязательно. Можно оставить и изначальный черный.

Обратите внимание, что мы создали еще и слой "Ball" , но на него ничего не ставим. Мы подготвили этот слой заранее, чтобы потом создать кодом на нем наш мяч (объект Ball).

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

Т.е. при запуске у вас откроется подобное окно:

Справились? Поехали дальше!

Начинаем писать логику для игры

Давайте начнем с биты, так как игрок будет управлять именно ей. Щелкнем на объект биты и создадим ей событие шага ( Step ), о котором я писал в прошлых статьях. Создаем именно событие Step , не Begin Step и не End Step . Для чего нужны они, объясню когда-нибудь в последующих статьях. Но запомните, в 95% вы будете использовать именно событие Step из этих трех возможных, так что пока не забивайте голову.

И вот наконец-то у нас открылось окно редактора кода. Как долго же мы шли к этому событию! Для начала, давайте сделаем так, чтобы бита двигалась вправо и влево по нажатию кнопок со стрелками вправо/влево на клавиатуре.

Для этого нам в шаге нужно создать условие, которое бы проверяло, что нажата та или иная клавиша (вспоминаем прошлые статьи опять же). За событие нажатия клавишы в GMS2 отвечает функция keyboard_check_pressed () , где в скобках мы напишем необходимую нам клавишу. Чуть ниже мы к этому вернемся. Так вот, а что именно мы будем делать при нажатии этой клавиши? Просто будем менять X-координату самой биты, т.е. будем прибавлять или отнимать эту координату, тем самым перемещая биту вправо или влево. Итоговый код в событии шага биты у нас будет выглядеть так:

Т.е. если нажата клавиша "стрелка вправо" ( vk_right - это как раз обозначение этой самой клавиши), то x биты прибавит 10 пикселей, а так как ось X в GMS направлена слева-направо , то бита как раз сдвинется вправо. Вот этот код как раз отвечает за прибавление 10 к x: x+=10.

Аналогично для левой стороны. Итак, жмем клавишу для запуска игры, чтобы потестировать. Сделаю оговорку: мы очень часто будем запускать игру для проверки текущего кода, чтобы избежать ошибок на первых порах. Напишем небольшой кусочек, проверим, напишем еще - снова проверим и по такой схеме постоянно. Если возникнет какая-то ошибка, то нам проще будет найти тот участок кода, в котором мы ее допустили.

Протестировали? Хм. Код и правда УЖЕ работает не так, как нам хотелось бы, правда? Т.е. зажав стрелочку вправо, например, бита сдвинется чуть вправо и остановится, пока мы не отожмем клавишу и заново ее не нажмем. Т.е. чтобы нам двигать биту, нам нужно постоянно клацать на клавишу стрелки. Согласитесь, это не очень удобно. Что же мы сделали не так?

Все дело в том, что мы выбрали не совсем нужную нам функцию нажатия клавиши. Их существует три. Давайте подробнее на них остановимся.

  1. keyboard_check_pressed()
  2. keyboard_check_released()
  3. keyboard_check()

С первой фкункцией мы уже познакомились, она срабатывает ровно в тот момент, когда клавишу нажали, т.е. когда клавиша только опустилась. Событие при нажатии сработает соответственно только раз.

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

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

Меняем код и пробуем:

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

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

Теперь бита кажется более плавной. А давайте вообще заменим скорость переменной, чтобы можно было потом в самой игре менять скорость движения биты, например, когда подбираем какой-нибудь бонус. Согласны?

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

Создаем событие Create (так же как мы создавали Step ) и в нем напишем всего одну строчку кода:

А в самом событии шага (Step) чуть изменим код на такой:

Т.е. мы просто цифры заменили именем переменной, а так как она равна 5, то результат при запуске будет тот же. Но в дальнейшем нам это пригодится.

Не люблю повторяться, об этом я писал в прошлых статьях, но тут все таки сделаю исключение. Напомню, что событие Create выполняется лишь раз, в момент создания объекта. Т.е. весь код, что написан в событии Create выполнится лишь раз, в самом начале, в отличии от Step , где он выполняется циклически, т.е. неприрывно.

Делаем столкновения со стеной

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

Т.е. что нам нужно сделать? Алгоритм такой:

  1. Проверить нажата ли клавиша вправо
  2. Проверить находится ли бита все еще левее самой крайней стены
  3. Если да, то только в этом случае сдвигаем ее на 5 пикселей вправо

Тоже самое потом проделываем и для левой стороны. Чуть дорабатываем наш код:

Ну, давайте разбираться, что мы тут написали.

Сначала как и прежде первой строкой проверяем нажата ли клавиша "стрелка вправо". И если она нажата, то все, что идет далее между скобок <> будет выполняться, если нет, то код в них просто будет игнорироваться.

А в скобочках у нас еще одно условие (if). Им мы проверяем если x-координата биты меньше значения 891, то можем выпонить код следующий далее в скобках <>. А в нем у нас как раз прибавление координаты x на 5 пикселей, т.е. сдвиг вправо. Таким образом, если у нас x биты меньше 891, то она сдвинется вправо, а если больше или равно, то код в скобках не будет выпоняться, т.е. бита не сдвинется и будет стоять, т.е. как бы упрется в стену.

То же самое для левой стороны, только там условие чуть отличается. Если x больше 67, то бита сдвинется влево на 5 пикселей, если меньше или равно 67, то соответственно нет.

Где я взял эти значения: 67 и 891? Это просто координаты в комнате. Как уже сказал, ось X в GMS идет слева направо. Т.е. самая левая координата комнаты будет равна 0, а самая правая - значению ширины комнаты (которое мы задавали при создании комнаты, т.е. 960 пикселей в нашем случае).

Читайте также: