Как в Game Maker Studio 1.4.9 делать преднастройки переменных объекта?
Мне нужно сделать разные меню с одним скриптом.
Но как сделать так, чтобы содержание меню менялось?
В GMS если делать разные объекты под каждое меню отдельно, то код меню на каждом объекте будет уникален, а мне нужен один код на все меню?!
UPD: Сделал первый пример, Спасибо всем! :3
- 19 мая 2020, 07:03
- 00
Допустим я хочу сделать два меню.
С такими преднастройками, где menu - это текст, а action это вызываемая функция из Scripts:
menu[0]="Yes"; action[0]=YesAction();
menu[1]="No"; action[1]=CloseMenu();
и второе
menu[0]="Start"; action[0]=StartGame();
menu[1]="Continue"; action[1]=ContinueGame();
menu[2]="Exit"; action[2]=EndGame();
Получается я должен это пихать в два разных объекта?
Или же есть возможность каких-то более удобных преднастроек объекта?
Чтобы один объект мог работать в совершенно разных состояниях.
Смотрел вот это видео, но тут очень топорно, если на каждое отдельное меню надо делать отдельный объект с уникальным скриптом на каждый объект. Да и ещё сложно с его идеей switch менять расположение кнопок местами. Это совершенно не гибко.
Можно конечно сделать так, что ты добавишь переменную какое сейчас используется меню. А само создание\заполнение меню сделать в событии user_event(0) например. В нём, в зависимости от переменной менюшки, ты заполняешь свои menu и action.
Но мне структурно больше нравится вариант от Herzenrg c ds_map и ds_list.
И да, вот это "action[0]=StartGame();", если ты хотел использовать затем script_execute, то не нужно писать "()" в конце имени скрипта, а то это вызов этого скрипта, а не получение его id.
Спасибо загуглю про user_event. :)
И ещё вопрос:
Как много объектов можно создавать в ресурсах, будет ли лагать если их будет свыше 1000?
Я имею ввиду те, что находятся не на уровне, а в ресурсах.
Не занимайся предварительной оптимизацией, худшее из зол.
Это не оптимизация, а бенчмарк для определения пригодности движка :)
Что же такое ты там делаешь...
Пока только учусь, но заранее хочется знать подводные камни)
Просто если придётся при любых изменениях переменных дублировать объект, чтобы просто переменные сделать другие, то таких объектов может много накопиться. Либо я пока не правильно понимаю концепцию.
Не будет. У нас в проекте 500 объектов, ничего не происходит экстраординарного. Подгрузка проекта дольше. Работа в IDE не меняется от этого, а игра и подавно.
Это хорошо!
У меня как-то под 1К объектов было (привет Zzzz и Behind Mirror). В GMS1 были тормоза с сохранением проекта(минуты 3 на сохранение), начиная с версии 1.4.7 вроде. Ёё-шники говорили что это типа только у меня. Хотя я пробовал на разных компьютерах. В GMS2 такой проблемы нету.
жесть D:
Есть ещё вариант: использовать Room как префабы (по типу Годот или Юнити)
то есть использовать Room как отдельное меню, но я пока не понял, можно ли создать комнату в комнате,
и потом безболезненно удалить её.
Посмотрел команду "room_add", но похоже это что-то другое.
Ты можешь двумерный массив использовать
Там даже функция для получения длины массива есть так что это не проблема.
Можно через дата-структуры пойти, но в GMS с ними работать запутанно. Когда 2.3 выйдет - там вообще пиздато станет - как с двумерными массивами можно будет работать.
Спасибо! Я хотел второе измерение использовать для двумерного меню,
как например инвентарь как в Зельде, где предметы расположены 2-мерным списком.
А одномерный список для простых меню.
Но жаль, что всё равно придётся предустановку переменных делать только кодом
для меня это шок после использования Юнити.
Если ты про функционал выноса в панель компонента переменных с возможностью овверайда этих переменных у прафабов то такое есть во второй студии. Я про это писал ещё. Что есть прям variables которые ты опередляешь с дефолтными значениями у объекта, у чайлда и инстанса можешь эти значения переопределить.
А чем плохо делать инвентарь двумерным массивом и меню двумерным. Это же вроде не взаимоисключащие вещи, да и сущности разные. Для инвентаря лучше ds_map и ds_grid использовать. Хотя бы потому что ты при сохранении вызываешь у них функцию _write и получаешь строку, на загрузке читаешь эту строку функцией _read и получаешь снова структуру.
Вообще рекомендую сохраняемые глобалы хранить в ds_map. Потом проще будет сохранения делать.
Мне структура ds_map нравится, похоже на словарь из других языков (dictionary) типа JS и C#.
ну ещё можешь ds_list использовать вместо массива и ds_map для навигации между менюшками
И там дальше создаёшь всякие current_menu и current_select чтобы сделать менеджмент и отрисовку. Надеюсь, сам сможешь =)
Это кстати не факт. Если использовать ds_map_add_list, то ненужно, да. Но вот если использовать ds_map_add (что равно доступу через "[? ]"), то ГМС будет думать, что добавили просто число.
Пару раз я наткнулся на это и оно отучило меня писать через простой аксессор для ds_map\ds_list
Это да. Я к тому что я не делаю сразу ds_list_destroy(temp_list), хотя по правилам программиста если выделил память - будь добр её освободить. Если создавать список временно то это нужно делать обязательно.
Про ds_map_add_list не знал, давно не заглядывал в этот раздел хелпа =)
Я вчера придумал другой способ:
У нас есть объекты разные меню. При создании объекта - инициируется одно меню.
И объект заносится в список menus[] = self.
То меню, которое самое верхнее (последнее созданное) и будет активным.
При закрытии меню, объект удаляется, и тот объект-меню, который был предпоследний теперь активный.
Внутри объекта каждый кадр мы обращаемся к скрипту WorkMenu(self) ; и отправляем скрипту "себя",
а в self тут как раз все переменные, вся инфа о меню, чтобы скрипт WorkMenu мог работать с этим.
Надеюсь сработает, а то пока только в уме продумал.
Надеюсь списки у каждого объекта свои личные. Чтобы у каждого объекта был разный набор кнопок.
Ещё надо погуглить как делать публичную переменную (public), а то пока не понял.
В гамаке нет разделения на публичные и приватные.
Все локальные переменные объекта публичные. Это те которые ты объявил через присвоение.
Всё что объявлено через var - локальные для блока кода. Причём в конструкции with на них нужно просто ссылаться без указания other. С other просто ничего не получится
Через globalvar можно объявлять глобальные переменные
А можно через объект global, например global.myvar = 5, на этом настаивают разработчики, но тогда ты везде должен будешь юзать приставку global. Лично мне неудобно так что я через globalvar всегда делаю.
Списки (они же массивы) - локальные переменные и для каждого свои. А вот всякие айдишники которые возвращают ds_list_create, sirface_create, instance_create и т.д. - они глобальные.
жаль ds_list_create у каждого объекта не свой, а то можно было бы прикольные вещи творить
Можно и свой сделать. Это же просто число. Храни его в переменной объекта и всё.
Странная система на самом деле. WorkMenu(self) не будет работать. Лучше так что ли:
with menus[array_length_1d(menus)-1] WorkMenu()
Но тебе придётся как -то дописывать айдишники чётко в конец массива. Лучше какие-нибудь ds_list что ли.
Ну может и правда переборщил. Просто хотел, чтобы один объект отвечал за всё меню.
А другой за другое меню, если оно выше находится.
С другой стороны второе меню будет только с проверкой Yes/No, а в остальных случаях меню будет всегда одно на текущий момент.
"WorkMenu(self) не будет работать."
Cейчас попробовал Self передать в скрипт из объекта и вроде работает идеально, в объекте есть переменная rnd, но может тут другие проблемы есть:
Ты имеешь в виду что хочешь один раз написать логику "можно листать вниз, можно листать вверх, можно активировать", но чтоб в разных меню были разные действия? Для этого традиционно используют наследование. Делается один объект-родитель всех меню (его в игре не будет), а все конкретные меню игры его логику наследуют. И если ты решишь поменять что-то в самом принципе переключения меню, или в его отрисовке, то тебе достаточно будет поменять это только в объекте-родителе. Но ты можешь оверрайдить и переключение, и отрисовку, и оба из них, в конкретных меню, в объектах-наследниках.
Спасибо, Ксит! А я всё думал зачем тут родители и чайлды, думал неудобно будет тут структуру сделать как в юнити, там на уровне есть один родитель и куча чайлдов, а оказывается тут не для уровня, а для программирования. Пошёл гуглить про наследование.
Не найдёшь ничего. Щас в айти нужных программистов некому учить, а про геймдев вообще шаром покати.
Вот держи, с нуля исходник сделал, конкретно иллюстрирующий как это делается:
https://www.dropbox.com/s/8d77fjft6laxo9g/ParentMenus.gmz?dl=0
Конечно могут понабежать Хейзеры и сказать что нафиг свитч-кейзы, но тогда придётся каждый раз из объекта меню переключаться на скрипты задаваемые пунктам. Или распихивать их по юзер-ивентам как ДД. Сути наследования основного функционала меню это не меняет.
event_inherited() выполняет код родителя из такого же ивента. Если в объекте-потомке нет ивента который есть в объекте-родителе, то код из объекта-родителя выполняется автоматически (в моём исходнике это происходит с Draw конкретно).
О, спасибо! Почему-то в документации не нашёл примеры кода про паренты.
Хотя в сети нашёл, вроде начал понимать как это устроено.
https://developer.amazon.com/blogs/appstore/post/e355260d-ffed-4807-8f62-25dd0c8164f4/gamemaker-basics-parenting-and-inheritance
Так можно сделать группу врагов, группу друзей, группу опасности, группу меню, если правильно понял.
Да, для этого и нужно в большинстве случаев. Очень полезная штука. В GMS2 вообще круто это реализовано. Там в чайлдах видны события парента. Чего нет в GMS 1.4. Рекомендую всё же перейти на GMS2. Там довольно многое сделано по-другому и сделано лучше.
Спасибо ещё раз, очень помог пример! :3
Хотя я немного прокачал меню, совместил свитч и отдельный скрипт.
Просто не люблю когда свитч от цифр зависит, лучше от текста, чтоб можно было менять кнопки местами как хочешь или делать инвентарь в будущем.
Вдобавок можно функции меню вызывать не из меню вообще, например чтобы открыть меню:
menus("open",menuTest);
А ещё всё управление меню вынес в родителя. Но начальные настройки стали чуть сложнее, потом придётся ещё для картинки/иконки добавлять один массив.
Круто развил. Это дело.
Ты только не забудь что локаль потом может понадобиться приспособить не английскую. И понадобится разделять внутренние команды в свитчах и текст который на самом деле рисуется на кнопке.
Там кстати не от текста зависит, а от идентификатора кнопки (отдельный массив), но также у меня пока нет идей, как сам текст делать сразу для перевода. Какой самый простой способ сделать текст так, чтобы его легко было переводить на GMS?
Самый простой? Я бы сказал что писать везде только locale[N], где N это индекс строки в глобальном массиве locale, который читается из внешнего INI-файла со всё тем же CSV внутри на каждый язык. То есть содержимое файла:
Russian="Старт";"Загрузить";"Выход"
English="Start";"Load";"Exit"
В коде пишешь locale[0] там где Старт, 1 там где Загрузить, 2 там где Выход.
У нас в Замке Невозврата так доходит до locale[250] где-то, и 30 языков в игре - всё работает.
Инициализация:
Скрипт explode_string_list:
Начало файла Locale.ini для примера формата:
Символ ^ я выбрал в качестве разделителя потому что в текстах мне понадобилась точка с запятой. Так что по факту это не CSV (Comma-Separated Values), а... Caret-Separated Values, тоже CSV. :yak:
Как ты понял, это та причина почему скрипт explode_string_list вызывается с параметром "^".
P. S. И да, это простой способ. Если ты хочешь сложный, то в коде придётся писать каждый раз не locale[число], а идентификатор по типу locale[? "title_menu_start_button_text"] и в файл локали придётся добавлять каждый идентификатор тоже. То есть будет:
[English]
title_menu_start_button_text="Start"
...
[Russian]
title_menu_start_button_text="Старт"
И так все тексты. Раздувает файл локали и обращение к локализованным строкам в коде сразу в 2+ раза.
Спасибо) как раз с этим сейчас мучаюсь.
Правда не понял зачем working_directory, это вроде локальная папка виндовса для сейвов:
1) но тогда как туда запихать файл с переводом, перед тем как игра запуститься?
2) и как с файлом перевода работать в режиме разработчика, то есть напрямую из GMS?
плюс
3) ещё пытаюсь найти где тут операция Split, как в JavaScript и C#, кажется будто нету,
чтобы автоматически string текст разделить на массив, а по идее должна быть...
полез гуглить)
4) ещё также мне интересно можно ли хранить текстовые файлы внутри ресурсов, ещё и уметь их читать,
например чтобы базы данных быстро составлять, вместо того чтобы объекты делать с таким странным кодом инициализации, я бы мог бы сделать небольшой текстовый файл со всеми данными для кнопок
3) https://www.gmlscripts.com/script/explode
4) Собственно, эта же ссылка. Пример оттуда процитирую:
Это отличается от варианта с Included files тем, что конечный пользователь (геймер) поменять твои настройки кнопок не сможет, ну и ведь это системное меню. Но ты можешь сделать и так и так.
Спасибо, то что надо :)
Тебе нужно поместить этот файл в категорию ресурсов Included files (слева там где в ГМС1 объекты, спрайты и прочее, почти в конце внизу), и тогда он будет автоматически дописываться к дистрибутиву игры.
Такой возможности не предусмотрено, но из геймдев-IDE я вообще не помню чтоб что-то позволяло редактировать локали прям параллельно с разработкой игры. Все 30 локалей Замка Невозврата 2 сделаны в Блокноте, и только из-за того что добровольцы все поголовно хотели Эксель, мне приходилось запаковывать их в две колонки - английский и требуемый язык, то есть оригинальный текст транспонировать (переводить строку в колонку), а потом при получении готового перевода транспонировать обратно. Но тебе для твоих целей Блокнота с головой, по-моему.
И да, в ГМС2 можно редактировать внешние текстовые файлы прямо в IDE.
Наверное я плохо объяснил, хотел спросить как работать в режиме GMS с файлом (не редактировать, а чтоб все текста работали), но вроде бы первый ответ это ответ и на второй вопрос, сейчас потестирую)
Так то я могу с CSV и в Open Office работать (аналог Excel), чтоб не запутаться в знаках препинания.
Да, это и есть ответ.
получается в Included files вообще можно левые txt файлы держать, чтобы их читать для каких-то своих данных, например для информации кнопок меню или покупки в разных магазинах/вещи в сундуках, надо потестить
ещё бы понять как много файлов можно держать в Included files
В Замке Невозврата 2 их как минимум 100, стопудово тебе хватит.
Получается то что в Included files потом при запуске игры на другом компе эти все 100 файлов перенесутся в working_direction (то есть локальную папку винды)? И игрок их сможет редактировать, если найдёт? Или я не так понял?!
working_directory, не working_direction.
Да, так и будет. Вообще, возможность моддить игру это скорее приятно для игрока, чем нет, согласись. Если ты не делаешь мультиплеерную игру где нужно бороться с читерами, это ничего не портит. Да и много ли сейчас людей лазит по системным файлам игры. Мне кажется, современное поколение на смартфоны-планшеты всё подсело и еле помнит что такое ПК кроме как для просто_играния или работы.
Да в принципе не проблема)
Ещё странности со шрифтами в Low Res игре:
Неприглядный вид. Вроде всё что можно сделал в настройках:
Ещё одна вещь со шрифтом - русские буквы больше, чем английские, но наверное потому-что шрифт кириллицу не понимает, надо потом выбрать другой шрифт и потестить.
Скорее всего, проблема в том, что рисуешь через Draw, а не Draw GUI.
Спасибо! Попробую через Draw GUI, главное чтобы не оказалось, что в GUI альтернативное разрешение экрана,
мне кажется я уже встречал инфу, либо я просто неправильно перевёл или неправильно понял. Мне просто нужно чтобы во всех Draw функциях было одно и тоже разрешение: 384 x 216, а не чтобы GUI подстраивалось под любое разрешение экрана, как сейчас любят делать, что мне совсем не нужно.
Разрешение Draw GUI тоже можно менять. Но насколько я помню оно влияет на само разрешение Draw. То есть, если разрешение GUI меньше, чем для Draw, то тогда будет пиксилизация. Но это не точно.
Ты о чём?
О том, что можно менять размер GUI рендера
Так вроде размер GUI рендера равен размеру окна/дисплея. Разве нет?
Я так понял он про http://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/cameras%20and%20display/display/display_set_gui_size.html
Да, я про это изменение
Потестил Draw GUI и либо я неправильно делаю, либо это не для меня. :(
Позиция текста зависит от того насколько я экран разворачивал, а это мне не надо.
Ведь у меня экран, отрисовывается через
draw_surface(application_surface, surfX, surfY);
Видимо придётся текст делать через обычные спрайты и писать код чтоб эти спрайты рисовать.
Вообще-то более вероятно то что ты сам сказал раньше:
А всё разобрался. Вначале сделал скрипт коррекции размера GUI, а потом и вовсе отказался от GUI Draw,
оказывается текст без сглаживания можно рисовать через Draw, я просто в первом примере забыл поменять шрифт и рисовался дефолтный шрифт вначале:
А какой размер у левого и правого окна? В правом изменил gui размер через disply_set_gui_size ?
Да, вот эта функция помогла :3
display_set_gui_maximise(_multi, _multi, surfX, surfY);
где _multy - множитель размера, а surfXY - это смещение сурфейса
хотя потом оказалось, что несглаженный шрифт можно нормально рисовать и через обычный Draw,
я просто шрифт через код не поменял, думал по умолчанию поставиться, если он всего один в ресурсах
Да.
Ну ладно. Наверное нужно просто сделать самому шрифт, надо вспомнить где были сайты для создания пиксель шрифтов. А то потом ещё думать, есть ли лицензия у этого шрифта или нету.
Алекс, какие лицензии? Сделай игру, я тебе эти лицензии выкуплю вместе с Гамаком. Не думай всю эту ерунду.
Пиксель-шрифты лучше самому мутить. Все что я скачивал довольно херово работают. А если тебе понадобится локализация на португальский или китайский, то где потом глифы брать?
https://github.com/adobe-fonts/source-han-sans/tree/release
Вот эти хороши для восточных иероглифов, и покупать их не нужно.
https://github.com/adobe-fonts/source-han-sans/blob/release/LICENSE.txt
Спасибо! А кириллица там есть?
Блин я забыл что надо ещё и на азиатские языки когда то переводить, лучше сделать игру с минимум текста.
Не люблю переводить игру. Как в Машинариум вообще идеально, где из текста только название игры.
Есть.
забыл самое важное спросить, пойдёт ли это для пиксельных игр,
и не совсем понятно какой из этих файлов качать, но попробую разобраться
Ну для нашей же пошло. Но тебе иероглифы-то зачем? Делай на латинице сначала.
ну пока я не понял какой из этих файлов выбрать, или они все из ttc подходят,
но что-то больно много весят, аж 18 мб, для шрифта просто жесть) но может это не то,
или это так и должно быть, я пока для теста юзаю первый шрифт, потом вставлю навороченный,
главное чтобы он в 9-11 пикселей размер помещался)
Ну там иероглифов много, потому и много весит. Там не только два вида китайского (традиционный и упрощённый", но и японский, корейский, и отдельно тайваньский от гонгконгского.
Лучше пока с первым шрифтом продолжай, это на будущее.
Спасибо большое всем за подсказки! :3
Сделал первое меню. Заранее продумал, чтобы можно было делать 2-х мерное, если понадобиться, и чтобы можно было некоторые кнопки пропускать, если так был задуман интерфейс, плюс описание и проверку на Yes/No, например для выхода из игры.
Ещё думаю как сделать инвентарь, сделаю простой как в Guardian Legends, а не как в каких-нибудь играх, где можно выбрасывать вещи или перекладывать, это вообще жесть, я такое не вывезу на GMS.
А вот так примерно код инициализации меню выглядит, немного перестарался с количеством массивов, ведь нужно было продумать разные варианты кнопок и их свойств,
Ведь в GMS 1.4 нету класса, в котором можно было сделать все настройки в одном массиве, например:
button[xx,yy] = {text="Start",act="close",mode="",ask=1,icon=sprButton,text2=""};
Ты можешь сделать удобную инициализацию с помощью двухмерного массива, каждый элемент которого - ds_map.
Create:
Draw:
Если сильно хотеть, можно вообще вынести чтение всех меню из внешнего CSV-файла (считай, таблица как в Microsoft Excel - он кстати CSV поддерживает). Но это плохо тем что Эксель тебе не подскажет какие sprButton у тебя есть или нет в ресурсах.
Спасибо за лайфхак, а то я не понимал как с этим работать)
Хотя всё ещё не совсем понимаю, но кое-что проясняется из примера.
Надо загуглить как это удалять и прочие радости.
Я обновил исходник по той же самой ссылке, уже с новым примером:
https://www.dropbox.com/s/8d77fjft6laxo9g/ParentMenus.gmz?dl=0
Что удалять, структуры данных? В событие Destroy ставишь, в случае кода как выше, такое:
А массив menu_grid и удалять не надо, он сам сборщиком мусора очистится.
По правде говоря, это совершенно прямое использование структур данных, и ещё не лайфхак само по себе.
Тем временем в GameMaker 2.3 завезли такое:
https://www.yoyogames.com/blog/549/gamemaker-studio-2-3-new-gml-features
У меня такой версии в ближайшее время вряд ли появится, но выглядит структура прикольно.
Спасибо за ссылку) затестю
хотя всё ещё это не то
лучше бы
text: "Hello World!"
Естественно имеется в виду что можно писать туда какие угодно название : "текст".
Если вдруг кому-то захочется посмотреть исходники на GMS1/2:
https://drive.google.com/open?id=1f8jz0zJtE7x4YIEzXcplE3P8G8Ay2y1i