GMS 2, как поменять разрешение для всех комнат?
Что-то я запутался переходя с GMS 1 на GMS 2, раньше я делал так на старте игры:
//Auto Resize Rooms View
for (var i=1; i<=room_last; i++) {
if (room_exists (i)) {
room_set_view (i,0,true,0,0,screenW,screenH,0,0,screenW,screenH,screenW*.45,screenH*.45,2,2,noone);
room_set_view_enabled (i,true);
}
}
- 11 января 2021, 15:54
- 00
Ещё пытался делать такой код вначале при загрузке новой комнаты,
но почему-то вьюпорт всегда был размером с комнату
Подсказал бы, но сам пока до конца не разобрался. По сути, настройки комнаты остались те же самые, но в коде слегка переименовали это дело. Раньше у нас было два понятия: сам вид и порт этого вида на экран. Теперь у нас есть: камера и порт этого вида на экран. Тут чисто ренейм произошел.
Если тебе инструкцию здесь не напишут, то лучше всего будет открыть свойства комнаты, и каждую настроечку, которая там есть повторить в коде. Тогда, думаю, ты со всем разберешься.
Спасибо! Да мне потом объяснили, как сделать. Это один раз при старте игры:
Оказывается там была ещё одна проблема, это камера её надо было к виду привязывать на старте комнаты,
и вроде теперь всё наладилось:
1) при создании главного не удаляемого объекта, где ядро игры (я назвал MAIN), или просто при старте игры:
2) при событии старта новой комнаты, (в тот же MAIN запихал):
(хотя может тут ещё есть подводные камни)
Наверное тему переименую в "Вопросы по GMS" 2 как-нибудь так, удалить её всё равно нельзя.
Оказывается там много изменений было, например оказывается что функция tile_layer_find кажется устарела,
иначе не понимаю почему у меня так сильно тормозит код превращения тайлов в массив, для быстрой коллизии,
и ещё для генерации событий.
Немного повозился с тайлами и почему-то этот код выдаёт ошибку "-1",
хотя слой я переименовал и он его нашёл, может дело в том что тайлы были перенесены с GMS 1?
Слой как будто бы и есть, но его как будто бы и нет?! Или просто слой не осознаётся как тайловый?
Всё понял. Сделал с нуля тайловый слой и всё заработало.
Оказывается чтобы правильно перенести с GMS 1 в GMS 2, тут было очень много лишнего кода и скриптов,
а также все слои для совместимости были попорчены. Короче, лучше начинать свой проект с нуля,
чем пытаться в этом продолжать копаться с GMS1 совместимой версии. Так и сделаю, буду постепенно переносить всю графику и искать замену старым функциям на GMS 2.
PS Хорошо что проект не долгострой и не оброс тоннами скриптов и контентом, а то я бы также офигел как это было с Unity, которая взяла и отменила Java Script,а у меня на JS был долгострой и 120-150 скриптов в том проекте на юнити.
При переносе тайтлов с GMS1 на GMS2, он создаёт слой ассетов, в которых размещает обрезанные спрайты тайлсета. Самое смешное что сам ты поместить на слой ассетов такие кадрированные спрайты не можешь.
Так что да, нужно создать именно тайлсет и тайловый слой и там разместить тайлы. Функции для работы с тайлами в GMS2 совершенно другие. Кодом управлять не очень удобно на деле.
Печально будет, если кто-то делал очень много уровней на GMS 1, а потом это всё придётся переводить в другой формат. Ну ладно, благо я только начал.
Но вообще тут много чего интересного в GMS 2, правда из-за этого код приходится переписывать,
думаю возможно переписать свой старый код GMS 1 для кнопок меню из такого формата:
То есть тупо, очень много массивов привязанных к одной кнопке.
Хочу заменить на struct , чтобы в одной яйчейке массива было всё сразу, все данные.
Только я пока не уверен как это написать, но примерно понял. Надеюсь можно struct привязывать к массиву,
по типу:
пока ещё не тестировал, надеюсь я не ошибся с кодом
Ну и где-то саму структуру кнопки сделать, только пока хз где, может прямо тут или в глобальном объекте:
PS или может есть ещё лучше вариант, и я просто не шарю?!
или может лучше такой вариант? только как потом удалять такую структуру?...
Ну главное чтобы этого было достаточно, чтобы не было утечек памяти!
Потестировал код, вроде работает.
А я тут застрял на новом пункте, как вызывать функции из объекта и где эти сами функции внутри объекта хранить.
Может я не правильное место выбрал для функций в объекте, хотя читал что вроде как можно теперь любые функции добавлять прямо в объект, попробую погуглить эту тему.
Что-то не гуглится тема про кастомные User функции внутри объекта, либо они не так называются, либо мне приснилось, что я где-то это читал... xD либо я просто видел это в годоте, а подумал про GMS)
PS Возможно придётся и дальше юзать внешние Scripts, надеюсь когда их накопится под 500-1000 штук из-за того что придётся много локального интерактива делать под каждый отдельный объект это не выльётся в проблему.
Кастомные User ивенты (не функции) вызываются только по номерам, если ты о них.
Жаль, а по номерам не интуитивно и не удобно(
Так это и не надо делать, ведь теперь, с ГМС2.3, есть именно функции.
Так убери
self.
просто?Всё равно не работает, и в дебагере показывается странно, как будто самого объекта нету.
А o_test выглядит так и он тоже есть на уровне, как и объект вызывающий функцию.
Проблема в том, что твой GAME идёт раньше, а ты в его событии Create делаешь with(o_test) UseIt(); а у самого o_test лишь в Step событии ты задаёшь функцию эту.
Но если появляется ошибка, значит в Game with(o_test) срабатывает, но причина всё равно в том, что определяешь ты уже после того, как вызываешь. Переставь определение функции в Create событие.
Спасибо! Теперь всё заработало! :3
Получается если я хочу вызвать из Step, то лучше функцию в Step у другого объекта держать?
PS а нет, лол, похоже всё равно лучше держать все функции в Create,
откуда бы вызов ни шёл. Спасибо ещё раз, теперь всё работает)
Теперь можно делать более крутые диалоги и больше интерактивности, давно хотел такие функции как: EatIt, UseIt, TalkIt, GrabIt и другой интересный функционал, без этих скучных и непонятных номерных эвентов как было в старых GMS .
PS Плюс ещё один нюанс - приоритет загрузки, если поменять местами эти 2 объекта, то опять будет ошибка.
Алекс, напомни, что именно ты тестируешь здесь? Для чего тебе тестировать то, чего тебе в игре не нужно? Это же комната инициализации, она служит только для того чтобы инициализироваться и никаких Use_It().
Да пока других скриптов нет, я просто тестировал, чтобы понять как архитектуру менять под новую версию GMS, какие есть возможности. Так что да, этого не будет в нормальной версии.
Есть разника как объявлять функции. Как я помню в справке было написано, что функции, которые объявлены через обычный function functionName() видны в этом блоке кода, за исключением случаев когда они объявлены в скриптах. А если функцию присваивать переменной через functionName= function() то она попадает в область видимости всего объекта и должна быть доступна через with.
Вот тут можно почитать: https://www.yoyogames.com/blog/549/gamemaker-studio-2-3-new-gml-features
Спасибо, надо проверить! А я думал эти способы ничем не отличаются, потому-что в примерах пишут "или так или так" без комментариев, чем способы функций отличаются, как будто это абсолютно одно и то же.
А из этого метода можно заранее проверить, есть ли в этом объекте например функция
Use_It = function() {...}
Я попробовал такой метод, но оно не работает:
Может есть альтернативная штука типа function_instance_exists, но в гугле не находится подобное?!
А жаль, очень полезная была бы штука, заранее проверять, можно ли объект использовать.
Проверил. Не заметил разницы, всё также очень важен порядок инициализации функций, а через with работает и первый вариант function Use_It() {...} если порядок объектов нормальный,
то есть Game позже инициируется, чем o_test.
Зато нашёл вот такую штуку, проверять есть ли функция у объекта,
надеюсь я не ошибся с концепцией, и метод и функция это же одно и то же???
Но пока-что этот код работает в моём примере.
Метод — это функция, привязанная к объекту (ну или структуре).
В
if (is_method(Use_It))
может случиться ошибка, еслиUse_It
не инициализирована, для надёжности можно ещё в одну проверкуif (variable_instance_exists(id, "Use_It"))
вложить. К сожалению, нельзя эти две проверки просто объединить через&&
, потому что в GM он не short circuit, насколько помню.Спасибо за информацию!
Сложная система, а чего-то попроще как в юнити нету?
Система SendMessage, то есть отправляем запрос на функцию, и если функция существует,
то будет запущена, а если нет, то игнорируем эту строку?
В GMS есть event_perform.
Сделай новый скрипт, назовём его допустим execute_if_exists(), внутри:
https://manual.yoyogames.com/GameMaker_Language/GML_Reference/Asset_Management/Scripts/script_exists.htm
И вызывай
execute_if_exists("Use_It", аргументы скрипта)
.Насчёт
is_method()
не знаю , вроде бы не все функции являются методами.Спасибо, Ксит!
Если требуется именно метод, наверное, можно так. Сделать скрипт
и вызывать его
SendMessage(target, "Use_It")
. Если нужно ещё аргументы пробрасывать, то вероятно сойдёт вот такая модификация:поскольку непереданные аргументы инициализируются в undefined, как в JavaScript.
Спасибо, выглядит интересно, надо записать и потестить!
В старых это обычно решалось макросом. Объявляем макрос TAKE_IT соответствующим 6, а потом вместо user_event(6) объекта пишем user_event(TAKE_IT). Хотя новые возможности гибче будут.
В новой версии макросы(константы) тоже есть. В таком случае действительно будет удобнее.
Но там минус в том, что есть ограничение на 15-16 констант всего. Хотя как вариант запуска тех функций, которых я не знаю, есть ли они в объекте.
Что за хрень, вроде говорили что теперь все скрипты наподобие
gml_pragma("global", ...)
срабатывают со своими декларациями до всей игры? Теперь что, можно не знать какие у объекта функции, пока не выполнится ивент где эти функции задаются? Для полноты вакханалии надо было добавитьobject_has_declared_function(...)
и проверять есть ли такая-то функция уже, или ещё нету. Фейспалм.Что странно, если убрать строку с функцией и заменить на что угодно другое, то внезапно всё норм,
видимо проблема в том что нельзя функцию так читать(?):
А что если
o_test.Use_It()
, только не в степе функцию эту объявляй?Так вначале и писал, но не понимал из-за чего была ошибка, потому потом добавил with, чтобы быть точно уверенным для тестирования.
Я при переносе проекта Zzzz с GMS1 на GMS2 переделал все 60 уровней игры. Заняло пару дней. А совсем недавно для Cold Silence все слои тайлов менял. Потратил часов 6-8 на это дело. В масштабах разработки игры - копейки. Основная сложность была - разобраться со слоями которых GMS2 нагенерил довольно много.
А можно ли как-то этот спрайт спрятать за другие спрайты?
На правую кнопку нет типичного меню, чтобы на задний план поставить этот объект не создавая нового слоя.
А меню помеченное голубым цветом не работает для графики, куда ни двигай, кажется ничего не меняется.
Для чего я тебе с нуля вручную написал этих твоих глубин, чтобы ты третий раз одно и то же спрашивал?
Ксит, ну я также писал, что там мало функционала. С тем редактором глубин нельзя никакие настройки объектов сделать, а настройки отдельных объектов это приоритет для дизайна уровней, например для выхода настроить в какой уровень попадать, а для монстра какого он уровня и какие уникальные вещи именно в этой локации у него есть или тот же сундук. Так что я подумал, может проще будет стандартным функционалом обойтись, и странно если этого тут не будет, потому-что ещё в первом Construct и Multimedia Fusion уже такое было в начале 2000-х, чтобы можно было переставлять местами объекты.
вот такая опция
А нет! Всё нашёл, тут оказывается ещё один есть такой список, один видимо для приоритета скриптов и порядка создания, а второй уже конкретно для графики, правда это всё на моём маленьком мониторе не помещается, ну да ладно и так сойдёт)
Тебе показалось, это не то что тебе нужно. Такой опции в ГМе нет, перестань выдумывать.
Ладно, шутка не прокатила.
лол) а я думал ты про автоматическую сортировку)
В целом, вот если бы вот в этом отмеченном окне была бы галочка Auto Y Sorting, то вообще был бы топ)
Запроси фичу у разработчиков.
Можно. Использовать ноду YSort. Ах, да, здесь нет такого... хи-хи-хи🤭
Доделал код, чтобы камера нормально работала, во всех уровнях было одинаковое разрешение и pixelperfect, хотя конечно этот код выглядит немного тупо. Слишком много раз приходится напоминать коду простые вещи, что разрешение мне нужно на все уровни одно единственное. Или может есть проще вариант, а я просто не в курсе?
Здесь чистый прототип, с pixelperfect на GMS 2 и оконный режим по умолчанию с вариативным размером, если вдруг кому-то будет интересно:
https://drive.google.com/file/d/1vplhxuq5iH0YM9nN2jrSPJmn_zx9Apsm/view?usp=sharing
Ещё бы сделать запрет перехват на нажатие кнопки крестик на окне и Ctrl+F4, чтобы не закрывалось автоматически, а вначале выпадало игровое окно. Собственно, пойду гуглить, легко ли в GMS 2 это делать.
Я обычно у камеры в step событии только для текущей комнаты проставляю разрешение с учётом игровых настроек.
Не вижу смысла делать это для всех комнат сразу.
Этот код просто задаёт настройки видов и камер для всей игры, чтобы их в IDE вручную не настраивать.
А почему у тебя степ, непонятно. Чем тебе Room Start не подошёл, например?
Тоже хотел спросить почему Step, а не Start, это ж каждый кадр надо обновлять?
Потому что игрок может отресайзить окно, например.
А точно, у меня тоже обновление экрана каждый кадр, только камера всего один раз вначале менялась,
но разрешение окна каждый кадр.
Я всё равно параметры камеры и вьюпорта рассчитываю исходя из настроек игры, которые могут меняться в любой момент (тот же ресайз окна). Так что один раз задать все параметры для всех комнат - такое себе. Room Start можно, если потом отлавливать все события которые аффектят разрешение и камеру. Ладно если это платформер, а если камеру зумить нужно?
народ с вашего позволения спрошу, можно ли как-то в гмс 1.4 у физических партиклов включить кинематику?
а то я что-то не нашёл...
"Физических партиклов" не бывает - есть партиклы, а есть физические fixtures. Если ты хочешь чтобы поверх fixture рисовался партикл, то просто создай партикл поверх него.
ксит... есть такая штука как софт боди...
рс11... кинематики там нет...
https://docs.yoyogames.com/source/dadiospice/002_reference/physics/soft%20body%20particles/index.html
Идея для патреона - сделай реалити-шоу, где ты пробуешь разные движки и мучаешься с ними по-разному :)
лол) да уж, это единственное что я умею, мучаться с разными движками, а мог бы игры делать xD
... мучаясь с разными движками
А можно как-то найти все строки с восклицательным знаком во всех скриптах проекта?
Это бы очень помогло найти например те же опечатки переменных.
Спасибо Ксит, оказывается тут всё просто)
Ух ты, чо там есть!
А я уж собирался писать ответ "вот видите, я же говорил говно этот ваш GM, там даже консоли для вывода ошибок нет!".
Хорошо что я решил подождать знающих людей.
Это не консоль для вывода ошибок (для них есть отдельно Compile Errors, а ошибки упаковки билдов выводятся в Output). В Syntax Errors, несмотря на слово "Errors", выводятся только предупреждения, помогающие сориентироваться где в проекте торчит что-то странное, то ли недописанное, то ли ненужное.
Не ну тут в GMS 2 намного стало удобнее, чем в GMS 1, кроме графического редактора.
В графическом редакторе в GMS 1 можно легко было через Ctrl+V вставить арт из другого редактора,
но теперь это получается очень криво, да и ещё зачем-то в Brush эта вставка добавляется.
Приходится каждый раз новый Brush удалять.
Часть картинки почему-то справа налево переносится, тут маленький кусок перенёсся, а бывает и намного больше кусок, крайне неприятный баг. А остальное в GMS 2 мне нравится.
Теперь то стоит от тебя ожидать законченных конкурсных игор?
В идеале, я бы хотел бросить конкурсы и начать уже делать что-то действительно важное в геймдеве.
Хочу сделать хоть раз нормальную игру, где не надо урезать и выпиливать всё что можно, только лишь бы успеть к сроку, и самое обидное что даже это часто не успеваешь.
Хотел бы совместить TES + Zelda + Maunt & Blade + Rune Factory, и сделать в 2D с элементами аркадности, аркадность и 2D немного упростят сложный жанр песочницы.
И вообще мне хотелось бы найти такую нишу, где людям не важен сюжет, я всегда мечтал делать миры больше чем линейные сюжеты, от игры часто требуют сюжеты и концовки, но мне куда интереснее создать мир в котором хочется находится, ну в целом в TES достаточно хорошо это реализовали, сделали простой сюжет и многогранный мир, а в Maunt & Blade совсем нет сюжета, но у игры много фанатов.
Ну вот ещё есть Animal Crossing, но я не уверен, понравится ли эта игра людям, если оттуда вырезать сетевую составляющую, в свою игру я сеть не добавлю никак, хотя бы потому-что это сложно и я совсем не разбираюсь и не хочу разбираться в сетевых технологиях.
Повторяю в третий раз - вставляй кадры не внутри кадров, не пиксели. А вставляй сразу целиком изображение в раскадровку, в ленту сверху.
Здесь? Ну тут Ctrl+V у меня почему-то не работает:
А если лента сверху эта, то тут при нажатии правой кнопки мыши на ленту и выбрать Paste,
всё равно вставится так же криво и через Brush
Призываю в тред Хейзера.
Нет возможности гибко вставлять арт в проект, это да. В целом copy/paste через кисти сделан неудобно но я уже подпривык. Но редактор сам удобнее, чем в GMS1 ИМХО. Особенно круто анимации делать за счёт онион-скининга.
Обычно всё прям в редакторе рисую (пиксельарт). Не пиксельарт в стороннем редакторе сразу нарезаю кадры на отдельные картинки и импортирую скопом. Отдельно кадры добавлять, увы нельзя почему-то. Ещё можно стрипы импортировать но я этим не пользуюсь очень давно ибо всю графику рисую с нуля обычно.
Спасибо хоть атласы GMS2 сам формирует.
Вообще можно делать feature request в саппорте. В целом там вроде прислушиваются к советам пользователей.
Спасибо за ответ!
Когда-нибудь я им точно напишу, уже и так накопилось много реквестов.
Правда я не уверен что меня кто-то там услышит, обычно все игнорируют, что по юнити, что по Tic-80.
Не очень понятно, зачем профессиональному художнику понадобилось пересесть с любимого редактора на какой-то внутридвижковый велосипед :)
Не ну я обычно всё и рисую в другом редакторе. Но чтобы потом перенести изображение как раз это и нужно,
а оно нормально не работает.
Ну или можно долгим способом сохранять:
1) Скопировать из работы выделенный спрайт, у меня оно обычно сразу большой группой:
2) Создать новую картинку и вставить туда это
3) Сохранить картинку на рабочий стол
4) Вытянуть в редакторе картинку с рабочего стола
Но мне кажется быстрее было бы, если б нормально работала вставка спрайта внутри самого редактора.
В идеале бы, если б можно было в GMS 2 загружать целые группы спрайтов, но которые были бы не одинаковым размером.
Понятно! В Krita есть Paste as new image (Ctrl+Shift+N). Постоянно пользуюсь, наверняка, и в твоём есть что-то такое. А сохранять в папку проекта, а не рабочий стол.
А то получается наподобие, что GMS 1 варил тебе чай помимо разработки игры, а другие так не могут, и всё, застрял на GMS 1. :)
Вообще Скорчед прав. Редактор ГМа и раньше был сомнительный, а в ГМС2 стал вообще дичь, работай в своём обычном редакторе и экспортируй в ГМС2 уже готовые раскадровки лентами. Или GIF даже попробуй, вроде его поддерживали до последнего времени.
Ты тоже прав про нормальную вставку, но - не завезли.
Запутался. Нужно отключить все инстансы, кроме тех у кого есть особый тэг.
Но я так и не понял, как проверить тэг у инстансов, ибо проверяется только у объектов.
Ещё была вторая идея, отключить все инстансы кроме Game и o_MenuCore.
Но o_MenuCore может быть больше одного, а with вроде как не работает с отключёнными инстансами.
Если так сделать, то потом хз как достать все o_MenuCore из отключённых объектов.
PS Но получается и не так и не так не могу подобраться)
Был ещё третий способ - заранее не отключать все инстансы у которых есть в родителях o_MenuCore,
но как это проверить я запутался.
То есть пройтись по списку вот так:
Разобрался с одним пунктом, но появилась другая проблема.
_menu.object_index - находит объект у инстанса,
но если взять потомка от этого объекта o_MenuCore , то тэг нельзя проверить,
видимо буду другую идею прорабатывать, либо придётся всё тэгами завешать, главное не забыть отметить тэги во всех меню вообще, иногда такая ошибка может всплыть намного позже из-за невнимательности
ВСЁ! Вопросы отпадают, жаль не удалить эти монологи xD
оператор object_is_ancestor идеально работает для того чтобы искать инфу о предках инстанса
значить можно сделать что-то типа такого:
Ровно такой же результат будет от следующего кода:
То есть все объекты с o_MenuCore восстановятся, а не только один из объектов!?
Ну вообще у меня кое-какие странности были из-за мгновенной переактивации объектов,
точно уже не вспомню, но приходилось там корректировать строки в GMS 1 версии,
так что я подумал было бы неплохо вообще не отключать важные скрипты,
даже если это сразу же снова включится.
Скрипты невозможно отключать, речь идёт о деактивации объектов.
Все объекты, наследующие o_MenuCore, будут активированы этим кодом. Также будет активирован объект Game, а всё остальное деактивировано. Странности - на совести твоей архитектуры, её тогда надо перепродумать.
Ну я перепродумал, чтобы исправить косяк, а теперь перепродумал ещё раз) уже чтобы совсем избавиться от лишнего включения-выключения заново.
В принципе, если скрипт запускать из объекта Game, то не будет переактивации
для главного ядра игры и возможно не будет того бага.
Так-то лучше! А то аж
object_is_ancestor()
, я вообще не был в курсе что такая функция есть! :yak::yak: xD
А я ей даже пару раз пользовался. Не помню при каких обстоятельствах правда.
Можно их:
А) Удалить и пересоздать при надобности;
Б) Спрятать, сместив их координаты за экран и отключить взаимодействие.
А можно как-нибудь перехватить закрытие игрового окна, чтобы при нажатии на крестик, открывалось меню закрытия приложения, а не сразу выходило из игры?
Сделать полноэкранный режим и в нём - фейковый крестик справа вверху.
Ну это такое) Обычно движки позволяют блокировать/перехватывать крестик, думаю и GMS2 может,
только как это правильно по английски сформулировать, чтобы загуглить, я не знаю.
Гуглим "GameMaker Studio 2 close window event".
Находим событие "Game end" в Other.
Спасибо! Нашёл кое-какие расширения!
Расширения тебе для этого не нужны. Это просто ивент в объекте.
Вроде нашёл только расширения. Окей, ещё гляну
Какие расширения? Событие Game End срабатывает при закрытии игры, всё ж просто.
Я имею ввиду наоборот блокировать автоматическое закрытие игры при нажатии крестика окна. А вначале предложить диалог выхода.
Зачем? Если я правильно понял твою целевую аудиторию - играющие на рабочем месте - то им как раз надо БЫСТРО закрывать окно с игрой, для чего они и играют в окне вообще, а не в фуллскрине. Ты уж определись, ты делаешь домашнюю игру (которую нет причин не разворачивать на полный экран, потому что ты в неё полностью погружаешься), в которой нормальные вопросы типа сохранить или отменить, и оконный режим тогда не нужен; или поиграл-выключил, в которой автосейв, чтоб если закрыл то тебя автоматически сохранит, главное чтоб начальник не увидел.
Ну в принципе ладно, не так критично, если посудить.
Наделал кучу неограниченных меню и неограниченных диалогов.
Нравится переделывать архитектуру так, чтобы костылей было всё меньше и меньше.
Если интересно могу скинуть этот код на GMS 2, где пока только готовы lдиалоговоые окна, меню и гибкое разрешение экрана с Pixel Perfect составляющей.
Не обращайте внимания на текст, лол это что-то типа "Loren ipsum..." xD
Хочу сделать сменяемый AI для объекта персонажа, например если мы можем играть за любого NPC в своей команде или если например можем вселяться в любое тело противника.
И вопрос, не будет ли утечек памяти, если я вот так код организую:
И вообще как проверять утечки в проекте?
Запускаешь по F6 и смотришь в дебаггер - растёт расход памяти или не растёт, пока ты создаёшь-удаляешь объекты.
А что здесь может утечь? Здесь нет структур данных (ни пользовательских, ни встроенных).
Ещё, зачем передавать id в вызовах MyAI() и MyDraw()? Просто впиши внутрь этих функций id вместо того аргумента, который ты туда передаёшь, будет работать так же само.
Да, наверное это лишнее, это просто по привычке, как в юнити.
Только в юнити кажется такой прикольной фишки нельзя сделать, как присвоение функции к переменной,
чтобы менять тот же AI, это очень крутая фишка.
Можно. Только для этого тебе потребуется пробросить доступ между классами, методами и ещё кто знает чем.
Юнити — это же C#, всё там можно.
var square = x => x * x;
Алекс имел в виду что-то вроде делегатов или как минимум именованные функции/методы, а не анонимные по месту использования. Для этого потребуется соблюдать уровни доступа и сигнатуры, чего в ГМе делать не придётся.
В C# есть делегаты. В Lua все функции - именованные и все по ссылке, делегаты тоже можно сделать.
В C#, помимо делегатов, есть Func<> — просто функция с некоторой сигнатурой, завёрнутая в переменную, аналог std::function из C++.
Мне C# не очень нравится. Для ООП он хорош, но в остальном видно что язык разрабатывался с прицелом на криворуких индусов чтобы они себе в ногу не выстрелили. Если классы не нужны - лучше взять хотя бы Си.
Убрали прямой доступ к данным - везде обертки. Указателей - нет, настоящих массивов нет - теперь это объект, контролирующий границы массива. Структур - нет, теперь это классы, которым без конструктора - никак. Объявить массив структур - гемморой.
short и int - только со знаком. Куча функций возвращают данные разных типов, из-за чего постояннный гемморой с их приведением. Побитовый сдвиг почему-то только int-типа. Зачем тогда использовать типы byte и short?
Вот и выходит что проще везде объявлять int вместо более экономных byte, short чем постоянно приводить типы. Какая уж тут оптимизация?
И работает, он медленно. В Visual C# любое изменение интерфейса работает намного медленнее, чем я предпологал. Дошло до того что в проге где в диалоговом окне очень много элементов после запуска пару мгновений видно как они создаются.
Для чего они тебе?
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct - как это нет?
Не из-за языка это тормозит, а из-за API/библиотеки прорисовки.
Для чего указатели на функцию/структуру? Ну, например, чтобы ускорить доступ к ее полям, а не перебирать все вложенные ссылки. Или напрямую работать с символами строки, а не через прослойку, выделяющую каждый раз новую память.
Структуры - это тот же класс в C#. Все из-за отсутствия прямого доступа к данным.
Ты не можешь написать так: abc = { 10, 0 }; придется abc = new abc(10, 0);.
Тут, возможно, ты прав.
А зачем его ускорять? Ты делаешь реалтаймовую симуляцию экономических процессов?
https://docs.microsoft.com/ru-ru/dotnet/standard/base-types/stringbuilder
В Си слишком много неуместного байтоложества, неопределённого поведения и стрельбы по ногам, чтобы в 21 веке его брать для чего-то помимо прошивок микроконтроллеров (да и там по возможности лучше предпочесть Rust).
Welcome to unsafe-код с сырыми указателями, если приспичило преждевременно пооптимизировать или подключить сишную библиотеку.
Структуры C#, в отличие от классов, являются value-типами, не боксятся и размещаются по возможности на стеке. Какой ещё более прямой доступ нужен — неясно.
Ты о чём? Какой такой перебор ссылок?
ushort, uint.
На 32/64-битных платформах byte и short не дают никакой экономии (кроме хранения большого их количества в буферах), а наоборот — значения меньше машинного слова всё равно нужно перепаковывать, особенно если они невыровнены.
Ну и как мне тогда объявить массив структур с инициализацией?
B a[] = { {1,2}, {3,4}, {5,6} }; не прокатывает.
Чтобы на Си вместо a.b.c.d.e = 1; писать E * e = &a.b.c.d; *e = 1; при том что это структура, а не класс.
Точно, забыл.
Ну через
new
, более громоздко, но суть-то та же.Так ведь доступ к полю сколь угодно вложенной структуры происходит за фиксированное время, потому что смещения всех полей известны при компиляции. Вот если требуется указатель на это поле передать куда-то наружу, чтобы потом менять, тут да, у C# проблемы; но вообще это нарушением инкапсуляции попахивает и наверняка должно решаться другими средствами.
А как HPC# (относительно новый язык для Юнити)? Лучше-хуже?
Ну а по конкретному моему примеру можно также на C# сделать в юнити?
А то как раз сейчас думаю можно ли плавающие функции сделать.
Чтобы в зависимости от переменной вызывалась другая функция (без switch или if костылей)
PS Мне просто нужно отдельному персонажу сделать разную систему поведения не прикрепляя новых
Behaviour к объекту. В идеале было бы круто, если бы работало так:
public MonoBehaviour MyAI = NPCAI;
MyAI();
но даже если это можно, то оно записывается как-то иначе на C#
Ну или придётся со switch костылём и простым string указателем на конкретный костыль вызова функции:
Ну или можно запихать в поведение MyAIs все функции,
чтобы не занимать на одну функцию весь MonoBehaviour, и опять же с костылём switch:
Объявляешь в классе персонажа виртуальную функцию для обновления ИИ.
В дочернем классе переобъявляешь тело этой функции. Для каждого противника делаешь свой класс, со своей функцией AIUpdate.
Делать виртуальной Awake, Start, Update, FixedUpdate и прочие функции, наследуемые от MonoBehaviour - не советую. Компилятор постоянно будет жаловаться что в "родительском классе такая функция уже есть".
Лучше объявляй свои функции, а их уже вызывай из вышеназванных функций.
Собно так Кситилон и советует сделать. С интерфейсами, областями видимости и всякими там имплимитациями я не дружу, этот ваш ООП и так слишком сложный чтобы в такие дебри залезать. Я предпочитаю использовать виртуальные функции.
Для всяких там выбираемых сущностей лучше использовать перечисление (enum).
Если хочешь чтобы enum был виден во всех скриптах, то пиши его ДО строчки public class ИМЯ_КЛАССА : MonoBehaviour {.
На самом деле перечисление - это int с отдельным названием для каждого значения.
И в public-переменных (которые видны в инспекторе) перечисления хранятся как int.
Поэтому если будешь потом менять цифры, (например MOUNT = 0 на MOUNT = 1), то у всех перечислений этого типа поменяется значение.
А для индексирования по строке надо использовать словари
мне enum вообще не нравится, хоть там легко выбирать слот, но мне проще юзать string,
так код меньше символов занимает и легко сохранять это в файл для Save Game например
хотя лучше так:
тогда проще константы юзать вместо строк
тоже вариант)
А потом где-нибудь опечатываешься в строчке и ловишь загадочные баги.
В C# тебе надо будет определить новый класс для взаимо-заменяемых функций, и все функции должны будут наследовать этот класс. Но так как функции должны принимать свой набор аргументов, то возможно тебе лучше будет определить интерфейс и его имплементировать в таких функциях. Более простого способа я не знаю. Пускай на эту тему лучше выскажутся Юнитибоги с 300наносекунд/рубль.
Ксит, лол, я таких слов даже не знаю xD, я программирую методом: "Эта штуковина туда, а эта сюда")
Ну да ладно, в целом, мне пока хватает практических знаний для написания простых игр, без сложной структуры, просто в теории я никакой)
Вот недавно с JS на C# перешёл на юнити, почти допилил новый движок. Словами не понимаю, но когда показывают пример кодом, сразу становится понятно, если только код не слишком замудрённый.
В музыке также, не понимаю как эта нота называется, но получается собирать любительские композиции xD
Это примерно то что ты сделал на GM, только в C# ты специально прописываешь Интерфейс - это класс-пустышка, в котором ты только выписываешь названия функций. А те классы, которые этот интерфейс унаследуют обязаны все эти методы иметь. И это только потому что язык сильно типизированный и чтобы у тебя были гарантии что у каждого класса который интерфейс наследовал были те самые методы. Т.е. чтобы вместо рантайм-ерроров ловить ошибки компиляции "А у вас метод из интерфейса не реализован".
В гамаке если ты у кого-то из потомков не напишешь функцию myAI или MyDraw то твой код посыпется. Так что лучше ещё пару чеков сделать - что эта переменная действительно есть и что в этой переменной находится функция. Но лично я обычно так не заморачиваюсь и предпочитаю пару раз словить рантайм-еррор и быстро это поправить.
Единственный минус GM и слаботипизированных языков - это то что ты перегрузку на функцию не сделаешь, чтобы у тебя могли быть разные наборы аргументов. И в сильно типизированных языках это реально полезная штука. А в динамических уже много лет назад придумали практику configureOptions. По сути ты формируешь одну переменную в JSON с любыми аргументами/значениями и скармливаешь в функцию, а уже сама функция(в каждом объекте своя) разбирается что там пришло и делает что нужно. Если поведение разных сущностей сильно отличается то лучше их вообще по разным объектам разнести без наследования функционала - больше времени потратишь на костыли для подгонки нестандартного поведения под универсальное, чесслово.
Вообще-то чтоб так не было, надо прописывать дефолтные пустышки вместо них. Не у всех из потомков есть все эти функции, а прописывать вручную их отсутствие - напрасный труд из-за собственной неоптимальной архитектуры, вместо решения задачи.
Ты о чём? Ещё в скриптах можно было проверять количество аргументов, и сейчас это тоже никуда не делось. Перегрузку по ТИПАМ не сделаешь, хочешь сказать? Тоже неверно - никто не мешает is_real(), is_string() и прочее прописать. Просто после опыта с JS это делать лень, но надо помнить ради чего вообще связываешься с ГМом - удобно создавать игры. Не надо делать из программирования самоцель.
Это верно. Но в гамаке есть потенциальная опция их не написать. А интерфейс в шарпе гарантирует что у тебя такой ситуации не будет. Это если рассматривать вопрос в контексте сравнения ГМ и шарпа. Если бы я делал это на ГМ то так бы сделал. Словил бы рантайм еррор и прописал бы пустышки у парента.
Типа того, да. Про количество аргументов - это как раз хвосты. Они вроде даже в шарпе есть, но это не точно. Это когда в последнюю переменную как в массив наваливаются все аргументы функции если их больше указано, чем заявлено, а в самой функции ты обращаешься к последнему элементу как к массиву.
Но вообще да, я имел в виду перегрузку по типам. В динамических языках начинается вот это вот is_real и is_string и функция по факту может начать состоять из нескольких функций, которые по "правилам хорошего кода" лучше всего прорефакторить в отдельные функции, а исходную оставить в качестве функции-маршрутизации. Ты получаешь те же яйца, только сам знаешь в каком ракурсе. Просто ты руками пишешь то, что в сильно типизированных языках делается на уровне компиляции самим компилятором без твоего участия. С другой стороны, и там много писанины получается, если функция делает одно и то же но отличается только форматом входных данных - например подсчёт расстояния для dist(int x, int y) и dist(vec2 xy). Очевидно, что реализация у функции одна и та же и в динамическом языке это будет одна функция, у которой локальные переменные по разному сформируются. А в сильно типизированных языках это будут две совершенно разные функции, хотя и можно сделать чтобы одна вызывала другую. С учётом того что В СНОВНОМ задачи как раз по части разного формата входных данных, перегрузка функций - так себе фича и удобнее пользоваться динамическими языками.
Да и вообще всё это сравнивать некорректно, ибо в целом подход по проектированию и написанию кода в том же C# довольно сильно может отличаться от подхода проектирования и написания кода на JS или GML. Со своими плюсами и минусами с обеих сторон, разумеется. Где-то выиграл, но где-то и потерял.
У меня там есть пару проверок, да.
Это пока весь код обновления NPC, тут и сразу проверка на AI, если скрипта AI нет, то просто NPC будет по типу камня без движений и активностей.
noone
это константа для инстансов, логичней там писатьundefined
.Вроде так просто сравнить не проканает. Есть функция is_undefined. По крайней мере до версии 2.3 так было. Может в 2.3 уже поменялось.
И как же потом обнулить этот параметр? Так?
или так?
MyAI = noone;
Вообще не нравится, что нельзя юзать null как в C#, ибо так меньше символов и вдобавок это работает для любых типов что объектов, что скриптов:
MyAI = null;
хотя кажется в C# нельзя присвоить функцию к переменной простым способом, но радует что тут null универсален.
PS Интересно почему в GML не использовали null, или эта опция использована под другое?
Вообще раньше в GMS всё было числами и тот же noone
Возможно и для undefined есть что-то такое. Можешь проверить вот так, например
show_debug_message(string(undefined))
Я думаю что там null не использовали чисто из-за взаимоствования из JS. Этот undefined, NaN пришли именно из JS в GMS вместе с JSON форматом и всем тем новым, что появилось в 2.3 версии по коду.
Видимо на юнити JS какой-то другой был, ибо я там всегда использовал null опцию.
NaN
в GML из чисел с плавающей точкой, а не JS. И да,null
в JS действительно есть, наряду сundefined
.Там обычный JS. В нём есть как null так и undefined, что немного разные вещи. За пределами JS, я в других языках никогда не замечал использование undefined, да и многие фишки 2.3 взяты именно из JS, так что я сделал вывод что GMS2.3 унаследовал это всё именно из JS, но не полностью, разумеется. ИМХО лучше из JS с undefined, чем из C# с null =)
Разницу не понял пока-что, но постоянно использовал в Unity JS null не зная о существовании undefined и проблем не встречал вроде) Но теперь в юне JS отменили, так что уже без разницы, пришлось C# изучать(
Стоп, то есть если я сделаю константу?
Если тут есть константы, было бы прикольно сделать константу например
Constant null = -4;
и потом использовать было бы вот так
MyAI = null;
Но видимо не всё так просто и придётся это как-то иначе выкручивать, что в конечном итоге проще будет использовать noone и даже длинное слово undefined, чем длинющее
MyAI = global.null;
Можно
#macro null noone
, но не очень понимаю смысл экономить одну буковку.null
в GML нет, потому что там нет ссылок. Дескрипторы ресурсов, экземпляров объектов, структур данных и прочих штук — просто числа.noone
— просто волшебная константа только для объектов, использовать её для других вещей (например, взаменundefined
) не получится.Спасибо!
Я просто люблю сокращения, чем короче слово, тем лучше для меня, особенно если это слово часто используешь, как тот же noone. Код то и так большой с огромным количеством строк всегда, а тут ещё и каждое слово/оператор/переменная длинные, от этого читабельность кода уменьшается для меня, нужно найти баланс между краткостью и пониманием. Когда совсем коротко и не понятно это одна крайность, а вторая это когда слишком длинные названия переменных или функций.
PS Больше всего претензий у меня к юнити, там вот эти вот ужасные
SendMessageOptions.DontRequireReceiver
иDontDestroyOnLoad
...Но и в GML мне тоже кое-что не нравится, чёрточки в функциях, вот например функция
draw_sprite_ext()
лучше бы называлась такDrawSpriteExt()
Ты можешь переименовать абсолютно все скрипты в другие. Но игру это за тебя не сделает. Если это ПОМОЖЕТ тебе её делать, то просто переименовывай! И пусть тебя ничто не останавливает.
Ещё лучше, если бы это был метод
draw
у классаSprite
. Эх, мечты-мечты...В чём разница-то? Автодополнение и так и так работать будет.
Чтобы вместо
draw_sprite(s_hpbar, <arguments>)
писатьs_hpbar.draw(<arguments>)
. Зачем лишний раз напоминать, что это спрайт?EDIT: хотя это по оопешной идеологии не очень верно, ведь
s_hpbar
— объект, а не субъект. Возможно, лучше простоdraw(something, <arguments>)
, и пусть он поsomething
диспатчится в отрисовку спрайта, строки, прямоугольника или чего угодно.Если бы
s_
, было бы совсем плохо, вдругhpbar
это звук? Но так вроде бы и ничего....Кроме того факта, что сейчас в отрисовке всё выглядит так:
draw_sprite(sprite_index,0,x,y)
draw_set_alpha(0.3)
draw_set_color(c_white)
draw_circle(x,y,energy_speed*5,1)
for (a=0 a<5 a+=1)
draw_circle(x,y,sin(global.l)*energy_speed*(a+random(1)),0)
draw_set_alpha(0.5)
draw_line(x-sin(global.l)*energy_speed*5,
y-cos(global.l)*energy_speed*5,
x+sin(global.l)*energy_speed*5,
y+cos(global.l)*energy_speed*5)
draw_line(x-sin(global.l+pi/2)*energy_speed*5,
y-cos(global.l+pi/2)*energy_speed*5,
x+sin(global.l+pi/2)*energy_speed*5,
y+cos(global.l+pi/2)*energy_speed*5)
for (a=0 a<480 a+=1+random(4))
{
draw_set_color(make_color_rgb(a,a,a))
draw_point(lives mod 480,view_yview[0]+a)
}
Сразу видно, что в коде относится к рисованию, а что нет.
А будет выглядеть так:
sprite_index.draw(0,x,y)
тут ХЗ что, какое-нибудь gpu_set_alpha(0.3)??? draw.alpha(0.3)?
draw.color(c_white)?
circle.draw(x,y,energy_speed*5,1)
for (a=0 a<5 a+=1)
circle.draw(x,y,sin(global.l)*energy_speed*(a+random(1)),0)
draw.alpha(0.3)?
line.draw(x-sin(global.l)*energy_speed*5,
y-cos(global.l)*energy_speed*5,
x+sin(global.l)*energy_speed*5,
y+cos(global.l)*energy_speed*5)
line.draw(x-sin(global.l+pi/2)*energy_speed*5,
y-cos(global.l+pi/2)*energy_speed*5,
x+sin(global.l+pi/2)*energy_speed*5,
y+cos(global.l+pi/2)*energy_speed*5)
for (a=0 a<480 a+=1+random(4))
{
draw.color(make_color_rgb(a,a,a))
point.draw(lives mod 480,view_yview[0]+a)
}
Или как бы это выглядело?
Кек, а я до звуков ещё не доходил в GMS, а реально как помечают звуки?
Если "s_" - к спрайтам относится, то для звуков придётся писать как-то иначе...
Может "a_" - Audio? :yak:
Я у себя в проектах разделяю на
"sfx_" - для одиночных звуков
"mfx_" - для музыки
Дело в том, что для музыки скорее всего нужны будут другие настройки связанны ес поточным воспроизведением. Возможно, даже в аудиогруппы придётся объединять чтобы разрывов при переключении не было.
mfx - это что, музыкальные ЭФФЕКТЫ? Что за ерунда? Звучит как те звуки, которые в старых квестах приходилось играть на MIDI-инструментах, чисто по технической причине - WAV весил слишком много для 5.25" дискет, на которых распространялись игры. Но и они не назывались MFX, просто это по смыслу на них похоже больше чем на музыку, играемую в лупе.
Это звуковое и музыкальное оформление.
И как по-твоему "оформление" по-английски? FормXление?
:yak: а я также в своих проектах оформляю папку с музыкальными треками в той же юнити и Blitz Max раньше) если честно не могу объяснить почему xD видимо где-то давно видел SFX - рядом со звуковыми эффектами и по аналогии назвал так и для музыки MFX. У меня до сих пор часто папки со звуком называются SFX, а для музыки либо MUSIC, либо MFX xD
В старое время я писал "s_" для спрайтов и "snd_" для звуков, но начиная с сегодняшнего дня буду использовать для звуков "a_", как мне подсказал некто Алекс Сайлент с сайта по инди-играм "Гамин" 20 марта 2021 года.
...Впрочем, всё равно приходится делить на звуки и музыку, или как минимум на однократные и повторяющиеся по кругу. Так что возможны вкрапления "bgm_".
Надо лишь делать
Draw_Sprite_Ext()
:yak::yak: xD
Можешь макросами себе null сделать если нужно.
#macro null undefined
А два значение на один макрос можно?
Было бы круто типа:
#macro null (undefined,-4);
Потому-что мне часто нужно проверять 2 вещи в одном:
1) Существует ли объект/структура, и не удалён ли этот объект/структура,
2) не равняется ли эта вещь noone;
хотелось бы что-то простое для проверки этих 2-х вещей.
Макрос — это простая текстовая замена левой части на правую. Если
null
будет заменяться на(undefined,-4)
, ничего хорошего не выйдет. Используй функцию.Я пока немного с GMS2.3 работал, но потребности проверять что-то такое у меня не возникало.
Тот же undefined тебе может вернуться только если не инициализирована переменная/метод. А noone используется только при проверке существования инстанса. Лично я и эту константу использую только для инициализации переменных, в которых у меня будет id объекта, по сути - отсутствие объекта в переменной. Во всех остальных случаях у меня там будет id инстанса (сдох он или нет - не важно) , причём эти id всегда уникальные и не перетираются. Всё это для того чтобы корректно отработала функция instance_exists(), которая вернёт false и в случае если ей подсунули noone и в случае, если инстанс был уничтожен. А насчёт undefined - это только проверять существование методов перед их использованием, другого применения я пока не вижу. В обоих случаях задачи настолько разные, что проверять их одновременно нет никакой необходимости.
Если тебе нужно что-то супер-универсальное - создай функцию isNull(value), в которой проверяй всё что хочется.
в ГМС2 есть null, но называется он pointer_null
(хотя был уверен, что он именуется nullptr, решил перепроверить и действительно писать больше символов. Ну можно макро сделать на NULL)
Так он же только для указателей, кои в GM встречаются очень и очень редко (кажется, видела только два сценария — что-то там с текстурами, и общение с нативным кодом в dll)
Ну вопрос был в том есть ли null в ГМС, ответ - он есть!
А сам я тоже использую noone как условный null. Редко пишу просто "-1". Надо делать проверку на отрицательное значение и тогда туда входит и -1 и -4\noone. Да и вроде функции нормально работают если такие значения подать (например, surface_exists)
-4
А вот это кстати интересно, если там без разницы какой минус, то вместо того чтобы вот так мучиться:
cancelButton = noone;
if (cancelButton != noone){...}
может тогда лучше сразу делать типа?
cancelButton = -4;
if (cancelButton > -1) {...}
Можешь делать так, но я бы советовал всё равно избавляться от магических чисел (-4, -1 и т.д.). Поэтому я собственно noone и использую - это ключевое слово хоть и относится исключительно к инстансам, но те же дс структуры могу им "обнулять" (0-ой индекс структуры кстати вполне может быть) или сёрфейсы там.
Жесть, только что натолкнулся на проблему:
И в логе получилось в конце вместо числа с минусом undefined, а само undefined можно превратить тоже в число?
Так сказали же, что
noone
— волшебное значение конкретно для идентификаторов экземпляров объектов, которые на самом деле просто числа. Структура — не экземпляр, а отдельный тип, да иundefined
вроде как тоже отдельный тип (кстати, не знала, чтоstring
его конвертировать умеет). И если ты работаешь со структурами, лучшеundefined
вместоnoone
и использовать, проверяяif !is_undefined(cancelButton) ...
Для clarity можно ещё
function is_defined(a) {return !is_undefined(a);}
завести %)Я хотел бы всё-таки универсальую проверку как для объектов, так и структур.
Видимо придётся делать функцию типа (надеюсь в GML функции работают достаточно быстро, хотя бы как в Lua, чтобы часто их спамить для проверки разных вещей) :
Это же просто
Точно, иногда забываю что так можно сократить. Большое Спасибо!
Сделал стресс тест с этой функцией, выглядит интересно, надеюсь функции в GML работают достаточно быстро, хотя бы как Lua в Tic-80, чтобы их постоянно спамить проверками разных вещей:
Правда первую строку пришлось закомментить, ибо она не переваривается:
И лог выглядит приятно:
Какие стресс-тесты тебе ещё нужны, неверующий ты наш?
https://archive.kolenka.net/posts/na-chto-sposoben-vash-dvizhok-gamak-derzhit-34000-obektov-na-59fps
Упрёшься в пределы - тогда и говори.
Тот тест проверяет исключительно скорость работы оптимизированных недр движка, а скорость выполнения скриптов — нет.
Обожаю когда приходят оправдывать бесполезные тесты. Может ещё давайте арифметику тестировать? Сколько чисел можно сложить? Игра ж сама сделается, как только это узнаем.
А тебе-то какая разница? Сделай так:
Поздравляем, теперь можно писать null!
Можешь даже сделать:
И инициализировать через
MyAI=n
. Зачем это надо, неясно, зато потом код не так-то просто будет понять!Так же как ты его и инициализировал. Ты ведь обнуление будешь проверять одинаково с не инициализированностью? Или тебе надо знать конкретно - ты в таком-то объекте такую-то переменную ещё не задавал, или уже задавал, а потом обнулил? Тогда можно двумя разными способами.
Конечно я очень не Юнитивод и совсем не Шарпомастер, но кажется я сталкивался с чем-то подобным в юнити недавно. Эх, а вот был бы Си\++ - можно было бы ссылку на функцию оставить и вызывать! Но в Шарпе есть делегаты и\или юнитиЭвенты. Там даже можно навешать несколько функций на один вызов так сказать. Плюс юнитиЭвенты ещё и в инспекторе отображаются - с их помощью ваще каеф делать какие-нибудь кнопки и реакцию на их нажатие (даже базовые включить\выключить свет)
Делегаты лучше для обработки событий или обратной связи испольщовать.
Эх, то что в Си/Си++ делается элементарно, в Си# придумали кучу прослоек и оболочек.
Лишь бы криворукие программисты себе в ногу не выстрелили.
Пока криворукие программисты пишут реальный софт, пряморукие программисты не могут игру доделать - стреляют в ногу и месяцами ищут утечки памяти по просранным указателям XD
Починил.
Это верно чуть ли не для любой наугад взятой пары языков.
Так делегат по сути и есть ссылка на функцию/метод. В чём тут преимущество у С++, в котором указатели на методы вообще малоюзабельны?
Увы, про специфику Unity (что такое эти ваши монобехи) ничего не знаю, но вообще должно быть возможно именно так, как ты хочешь — в зависимости от условия где-то сохранить в переменную нужную функцию и потом её вызывать. В махровом ООП, где нет first-class функций (но где их сейчас нет), такая штука делается паттерном Strategy (или Command, постоянно их путаю), где заводят абстрактный класс на абстрактное действие/поведение и разные их имплементации — примерно как предложил AndreyMust19 ниже.