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
Хочу сделать сменяемый 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 ниже.