Как сделать инвентарь в game maker

Добавил пользователь Alex
Обновлено: 04.10.2024

Я пытаюсь создать систему щелчка и перетаскивания в GameMaker 2, например, в одежде или, может быть, в головоломке. Как я могу заставить объекты щелкнуть и перетащить?

Я пытаюсь получить его, чтобы я мог нажать и перетащить предмет одежды, например, и перетащить его на персонажа, а затем перетащить еще одну одежду.

Если все ваши объекты перемещаются в позиции мыши одновременно, возможно, их событие Step выглядит следующим образом:

Или, по крайней мере, это эквивалент GML того, что происходит.

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

Шаг 1: отдельный флаг экземпляра

Мы даем каждому экземпляру переменную со стартовым значением false :

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

И Глобальное левое выпущено событие:

Наконец, наше событие Step будет проходить следующим образом:

Теперь объекты перетаскиваются, только если щелчок мыши произошел внутри маски столкновения.

Шаг 2: флаг глобального экземпляра

Эта переменная будет содержать id экземпляра, который должен перемещаться. Итак, вместо подхода true / false у нас есть переменная noone / id , которая указывает, какой конкретный экземпляр перемещается. Так:

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


(он находится тут: sprites->buttons->button_play). Назовите этот спрайт s_play и нажмите на кнопку "По центру". Нажмите ок. Первый спрайт готов. Мы его видим в меню слева.

Теперь нажмите на этот спрайт правой кнопкой мыши. Появится окошко с функциями. Кликните по функции "дублировать". Появится точно такой же спрайт. Только называться он будет по другому - sprite1. Итак, нажмите "редактировать". Затем нажмите на карандашик в правом верхнем углу. Теперь можем спокойно редактировать спрайт. Наша задача, залить белые участки красным цветом. Главное случайно не закрасить буквы. Иначе вы сами знаете, что выйдет.

Залили все белые участки красным цветом? Хорошо! Теперь сохраняем спрайт, нажав на зелёную галочку. Далее ещё раз на галочку. Выдадим спрайту имя - s_play2. Спросите зачем заливать красным?Читаем дальше.


Он похож на первый спрайт, правда? Но всё же текст там другой. Ладно, продолжим. Назовите этот спрайт - s_quit. Теперь делаем точно такую же операцию, что и со спрайтом s_play. То-есть дублируем его и заливаем красным цветом. Получившийся спрайт называем s_quit2.

Отлично! Мы сделали два спрайта кнопок для меню - играть и выход. Какую кнопку нужно добавить ещё? Конечно информацию об игре(помощь по игре).


Даём ему имя s_info. Затем жмём ок. И опять же дублируем его и заливаем новый спрайт красным цветом. Короче, проводим такую-же операцию, как и со спрайтами s_play и s_quit. Ах да, его имя будет s_info2. Можете радоваться! Вы только что сделали набор нужных спрайтов для меню.

Итак, начинается самое сложное - объекты. Я надеюсь, вы не подумали что мы всё закончили и что осталось разместить объекты на уровне и всё, можно играть? Я надесь, что нет. Хорошо, хватит болтать, приступим к делу.

Создаём объект(если вы не умеете это делать,пишите в комментариях, отвечу). Присваиваем объекту спрайт s_play. Далее создаём событие кликнув по кнопке "добавить событие". Откроется окошко. Кликаем на кнопку "мышь"-->"наведение курсором мыши". Теперь посмотрите на колонку кнопок справа. Нашли?Там такие надписи: move, main1, main2, control и т.д. Нажмите на main1. Вы увидите что картинки изменились. В этих "картинках" найдите рисунок красного пакмэна(Change Sprite). Нажмите на него правой кнопкой мыши. Должно появиться окошко.Нажимаем туда, где стоит курсор на картинке.


Появится список наших спрайтов над которыми мы недавно работали. Выберите в этом списке красную картинку с именем s_play2. Теперь нажмите ок.

Дальше кликаем на "добавить событие". Выбираем - "мышь"-->"покидание курсором мыши". Опять жмём правой кнопкой на пакмэна. В появившемся окне открываем список спрайтов. Выбираем белый спрайт с надписью s_play. Нажмём ок. Снова жмём ок. И очередной раз создаём событие - "мышь"-->"левая нажата".


Нажимаем правой кнопкой мыши на Next Room . Жмем ок. Ура! Мы создали кнопку "играть", которая при нажатии перенесет вас в следующую комнату. Давайте дадим объекту имя o_play.

Теперь надо сделать кнопку "выход".Создаём объект, и сразу, что бы не забыть даём ему имя - o_quit. И сразу понятно что надо присвоить ему спрайт s_quit. Итак, нам надо сделать операции аналогичные тем, что мы проводили с объектом o_play.

Сразу создайте столбец таких же событий что и с предедущим объектом - o_play. Но только в событии левая нажата добавляем немного другое действие - Game End(найти его можно во вкладке Control). Это действие будет выключать игру при нажатии на кнопку. Переходим к "наведение курсором мыши". Добавляем действие с красным пакмэном. Как и в o_play. Ой! Я забыл рассказать что оно делает. Оно изменяет спрайт. То есть при наведении курсором мыши спрайт белой кнопки превращается в спрайт красной кнопки, как во многих играх.

Ладно. Добавляем действие с красным пакмэном. Открываем столбец с перечисленными спрайтами в появившемся окне и в этом столбце нажимаем на спрайт с названием s_quit2. Жмем ок. Давайте обрабатывать событие "покидание курсором мыши". Опять выбираем действие с красным пакмэном. (Ох, я устал от пакмэна уже. ) Появляется окно. В столбце выбираем спрайт с именем s_quit. Жмем ок. Еще раз ок.

Два объекта готовы. Наверное, вам не терпится посмотреть объекты в действии. Но нет игровой информации! Надо сделать.

Снова создаём объект, называем его o_info, присваеваем спрайт s_info и создаём столбец действий, как у объекта o_play и o_quit. В событии "наведение курсором мыши" очередной раз выбираем красного пакмэна, в появившемся окне открываем список спрайтов и выбираем спрайт s_info2. В "покидание курсором мыши" делаем то же самое только выбирайте не s_info2, а s_info. В событии "левая нажата" добавляем действие Show Info (вкладка main2). Теперь жмём ок.

Находим в левом тач-баре окна Game Maker пункт game information. Кликаем по нему дважды. И в окно, которое появилось на экране вписываем всю игровую информацию и помощь. После того как вы это написали, нажмите на галочку, чтобы сохранить текст. Создаём комнату(уровень) .И размещаем там наши объекты(кнопочки).


Это довольно старая статья, написанная еще в январе 2009 года на популярном американском блоге, посвященному Game Maker. Мы решили перевести ее и опубликовать, так как возможно, она будет полезна тем, кто еще не до конца осознал все преимущества программы Construct по сравнению с Game Maker.


Construct — бесплатный с открытым исходным кодом игровой конструктор с Drag-and-drop интерфейсом.

В минувшие выходные я говорил с Ashley Gullen, который спросил меня, почему, по моему мнению, Stencyl стал более известным, чем проект Construct, который продвинулся намного дальше в своем развитии. В отличие от Stencyl, который постоянно отказывается предоставить подробную информацию о своем релизе, Construct уже сейчас доступен для публичного скачивания.

Я решил не упускать возможность взглянуть на Construct, и мне понравилось то, что я увидел. Construct, который поддерживает встроенные сценарии Python, имеет стиль уровня похожий на PowerPoint и еще ряд преимуществ по сравнению с Game Maker.

1. Поведения


Часто используемые действия объектов заранее прописаны в Construct как поведения.

Хотите, чтобы ваш персонаж мог двигаться в 8 направлениях — просто выберите поведение 8 direction и задайте такие свойства как максимальная скорость, темп ускорения и замедления.

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

2. Layout Editor на уровень выше, чем редактор комнат у Game Maker


В то время как Game Maker’у требуются различные спрайты для каждого направления, куда смотрит объект, в Construct такой необходимости нет.

Все объекты можно поворачивать, как только вы добавили их на слой, и менять им угол, как вам угодно (слой в Construct аналогичен комнатам в Game Maker). Также вы легко можете менять объекту размер прямо на уровне, можете масштабировать слои — что не представляется возможным в Game Maker.

3. Встроенные типы объектов

Construct имеет встроенные объекты, которые позволяют легко добавлять различные элементы к вашим играм.


Хотите добавить текст на экран? Просто перетащите текстовый модуль, куда хотите, и поменяйте нужные вам свойства. Хотите использовать ввод с веб-камеры или выводить данные в гистограмме? — легко. На данный момент Construct имеет уже более 60 объектов, и любой желающий может написать плагин для добавления функциональности в программу.

4. Активная разработка

Construct активно развивается на основе предложений и идей своих пользователей.

5. 100% бесплатный и с открытым исходным кодом

Game Maker не имеет ни того, ни другого, а Stencyl объявил, что их проект больше не будет продвигаться как с открытым исходным кодом.

На настоящий момент мы знаем, что такое переменные, умеем присваивать в них данные, умеем вызывать функции. После этого логично рассказать о языковых конструкциях, вроде if , while , with , for и switch - но мы споткнёмся об отсутствие данных, которые нам придётся обрабатывать.

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

Рекомендации к названиям

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

Отметьте также, что в названиях не встречаются цифры. Только рядом с ними. Позже узнаете, как так вышло. Сейчас же отмечу только то, чт любое название не должно начинаться с цифры, иначе всё сломается.

Подтипы

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

Это не свойство языка, это свойство сознания разработчика придавать числам иной смысл. Различные виды смысла я здесь буду называть подтипами. У них есть одна неприятная особенность - нет никакого способа однозначно определить, к какому подтипу относится число. Единственный способ знать это наверняка - заранее договориться с самим собой о хранении в отдельных переменных значений известного подтипа. Это не так сложно, как кажется. Ведь нет никакой проблемы хранить в одной корзине только красные яблоки, а в другой только зелёные? Нет. Ладно, сейчас посмотрим.

Логический подтип

Но из мира операций - сюда попадают все операции сравнения: == (равно), (меньше), > (больше), >= (больше или равно), (меньше или равно), != (не равно).

= тоже сработает в качестве оператора равенства. Но лучше не путаться, где вы его используете для сравнения, а где для присваивания. Используйте == . Если у вас это ну никак не укладывается в голове, можно поступить и наоборот - пользоваться присваиванием в стиле Pascal ( a := 2 ), и использовать = для сравнения. Поведение и правила никак от этого не изменяются.

Операторы == и != прекрасно работают и на логическом подтипе. Это всего лишь числа, в конце концов!

a b a && b a || b !a !b a == b a != b
0 0 0 0 1 1 1 0
0 1 0 1 1 0 0 1
1 0 0 1 0 1 0 1
1 1 1 1 0 0 1 0

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

Итого. У нас есть условия на score и time.

Теперь их надо склеить, чтобы любое из условий срабатывало. Оператор || ! Для полной уверенности, что вычисление будет в правильном порядке, обернём выражения в круглые скобки и для наглядности добавим if . if (score >= (10 * 50)) || (time >= (room_speed * 60)) Страшновато выглядит? Можно воспользоваться свободой GML в расстановке переводов строк и пробелов, и записать это дело так:

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

Индексный подтип

Почти все ресурсы игры представлены в GML при помощи индексов. Индекс - это некое целое неотрицательное число ( 0 , 1 , 2 …), по которому GM может найти ресурс.

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

Не без исключений, конечно. Вы можете делать с ним разные обратимые вычисления. Если прибавить к индексу 1, а потом вычесть 1 - индекс станет прежним, и по нему вновь можно будет найти указанный ресурс. Но нужно быть достаточно осторожным, чтобы не трогать изменённый индекс, поскольку вы рискуете попасть на совсем другой ресурс (это не так страшно) или вовсе несуществующий (это уже фатально).

Также очень плохая идея - пихать индекс одного ресурса в функцию для другого. Это может привести к очень необычным эффектам, поскольку индексы некоторых ресурсов разных видов вполне могут совпадать. К примеру, у sprite0 , object0 и room0 , которые создаются в пустом проекте, индексы наверняка будут одни и те же, но означать каждый из них будет что-то своё, и применять это значение нужно будет соответствующе. Здесь есть где ошибиться. Я даже приведу пример рассуждений, которые видел у кого-то.

Хочется повернуть спрайт у object1 , которому присвоен спрайт sprite0 , что ж, спрайт и повернём: sprite0.image_angle = 70; Ожидание: поворот sprite0 , присвоенный object1 . Реальность: поворачивается спрайт у object0 , который мы вообще не трогали. Как так вышло? Очень просто. image_angle - это переменная объекта, у спрайтов их просто нет. Операция . применима только к объектам. И этой строчкой был изменён image_angle объекта с индексом 0 (равному индексу sprite0 ). Оказалось, что это object0 , никак, казалось бы, к sprite0 не относящийся. Будьте осторожны с такими моментами.

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

Значения переменных индексных подтипов не берутся из ниоткуда. Они есть всего двух видов: в константах и в переменных. Скорее всего, констант у вас в любом проекте тонна, потому что каждое название спрайта, объекта, комнаты, фона, звука и всего остального - это константа, содержащая соответствующий индекс. Выражение, если угодно. К примеру, у sprite0 (если вы его не переименовывали) значение 0 .

Для примера разберём такую строчку: draw_sprite(sprite0, -1, x, y); . Согласно справке, этой функции требуются, по очереди: индекс спрайта, индекс кадра в спрайте (или -1, чтобы использовать обычную анимацию) и две координаты положения спрайта в комнате. sprite0 - константа, содержащая индекс спрайта (число индексного подтипа). Это не текст "sprite0" , и попытка подставить именно в таком виде приведёт к проблемам: система не поймёт, какой спрайт ей использовать. А остальные аргументы - самые обычные числа, обозначающие количества или величины. С ними вы уже должны быть в состоянии разобраться сами.

В переменных такие числа могут оказаться двумя способами. Либо вы переписали их из констант, либо создали новые ресурсы при помощи функций - а возвращают такие функции индекс созданного ресурса. К примеру, sprite_add , если вы хотите загрузить спрайт извне. Конструкция получится вроде: ваша_переменная = sprite_add(. ) .

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

Но немножко особняком среди них стоят объекты. Потому что к индексам объектов применима особая операция: . . Она позволяет обращаться из кода одного объекта к данным другого. Есть ещё одна особенность: на один и тот же объект ссылается несколько индексов сразу. Каждый объект отзывается на свой id (о них далее), на индекс своего объекта ( object_index ), индексы объектов своих родителей (об этом позже) и ключевое слово all (на которое отзываются вообще все). Как отзываются — расскажу в уроке по языковым конструкциям.

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

Есть и другие способы достать индексы отдельных экземпляров. Можно это делать функциями instance_nearest и instance_furthest - которые особенно полезны для выбора цели обстрела. Как можно предположить из названия, эти функции просматривают все указанные им объекты, и возвращают тот, который ближе всего (или дальше, если furthest) к исполняющему скрипт.

Символьный подтип

Об этом много не расскажешь, всё его использование крутится вокруг функций chr и ord . Делают они взаимно обратные вещи: ord делает из символа его код, а chr обратно — выдаёт код символа.

Зачем это нужно практически - вопрос неоднозначный. Как правило, код символа удобно применять с различными свойствами кодировки. К примеру, цифры обычно перечисляются подряд: 0123456789 . Вот это выражение всегда истинно: ord("7") == (ord("0") + 7) . А латиница организована в два больших блока - 26 подряд идущих строчных букв, и 26 подряд идущих заглавных. И не только она - все национальные алфавиты стараются организовывать так же. Русский - не исключение (единственное, что там проблемы с буквой Ё).

В GML пользы от подобных приёмов мало, поскольку под самые частые задачи, где они нужны, в GML уже есть функции. К примеру, этот приём позволяет достаточно быстро собирать из известного числа строчку (что в GML делает функция string ).

Можно выделить и больше подтипов, но ничего принципиально нового вырвать из них не удастся.

Массивы

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

Можно подумать, что массивы - это просто группа переменных. Так и есть. В этом случае вы должны придумать название только группы, а каждый элемент группы можно достать по названию и номеру (которых в массивах называют индексом): my_array[2] - третий элемент массива my_array (здесь нет опечатки, он правда третий: после 0 и 1 ). У номера есть ограничения: он должен быть числом, целым и неотрицательным. Говоря проще: любым из 0 , 1 , 2 и так далее.

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

Массивы делают код удобнее. Мы можем взять и нарисовать спрайт предмета, просто зная его номер. Скажем, если это 3, выйдет что-то такое: draw_sprite(inventory[3], -1, mouse_x, mouse_y); . Но вместо 3 может быть и переменная: draw_sprite(inventory[selected_slot], -1, mouse_x, mouse_y); , и переменную можно изменять. Уже сейчас вы можете сделать переключатель слотов инвентаря. А после урока с языковыми конструкциями сможете его ещё быстро и целиком рисовать.

Эксперимент III

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

Сделайте кружок ( draw_circle ), который обводит одну из планет, и клавишу, с помощью которой можно переключать обведённую планету на ту, что дальше (а если самая дальняя - то снова на самую близкую). Здесь воспользуйтесь приёмом: изменяйте индекс выбранной планеты вот так: sel_planet = (sel_planet + 1) mod 3; . Этот хитрый кусочек кода никогда не даст sel_planet уйти из множества значений 0, 1 и 2. mod - это взятие остатка от деления.

К примеру, 49/5 - это, строго говоря, 9.8 , а вот 49 div 5 - это 9 , 5*9 = 49 - 4, и значит, остаток от деления 49 на 5 - это 4. В коде - 49 mod 5 == 4 .

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

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

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

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