Как лучше проверять изменение переменной?
| |
alexsilent | Дата: Понедельник, 14 Ноября 2022, 23:50 | Сообщение # 1 |
почти ветеран
Сейчас нет на сайте
| Мне нужно очень часто проверять изменение разных переменных: Например изменение Health, чтобы текстом или баром поменять сколько теперь здоровья. Или например количество золота.
Обычно я делаю проверкой с дополнительной переменной:
Код if (oldHealth != Health) { // чтобы лишний раз не обновляться для оптимизации oldHealth = Health; // дополнительная переменная сохраняющая прошлое здоровье UpdateHealthBar(); // а тут уже само обновление текста и бара здоровья }
Но мне тут сказали, что это не оптимально каждый кадр проверять переменную. А какой вариант лучше? Кто как делает проверки изменения переменных?
Сообщение отредактировал alexsilent - Вторник, 15 Ноября 2022, 00:06 |
|
| |
TLT | Дата: Вторник, 15 Ноября 2022, 00:18 | Сообщение # 2 |
Сейчас на сайте
| Зависит от жанра и типа игры. При коллизии обычно обновляется. Не пойму зачем вообще здоровье периодично обновлять, если обновление можно производить исключительно при изменении параметра. Если здоровье изменилось, то передано обновление на индикатор/бар.
Как у тебя в коде обычно проверяют "отжатость" кнопки, например, в тех движках, в которых не прописано это в API. Впрочем, для современных мощностей это не критично. А вот если бы делал для ретро-систем, то замена одного равенства ли сравнения равенства могла бы дать мелкий прирост.
Например, в столкновении пули прописать код --здоровье и саб на обновление полоски здоровья HUD. В столкновении с аптечкой прописать код ++здоровье и саб на обновление полоски здоровья HUD.
Дао, выраженное словами, не есть истинное Дао.
|
|
| |
alexsilent | Дата: Вторник, 15 Ноября 2022, 00:30 | Сообщение # 3 |
почти ветеран
Сейчас нет на сайте
| Цитата TLT ( ) то передано обновление на индикатор/бар.
Хорошо, допустим, там один объект и легко команду ему отправить. А что если у меня на уровне много объектов, которые меняются от погоды и времени суток. И чтобы следить за ними у каждого объекта стоит проверка типа:
Код if (oldDayTime != Global.DayTime) { oldDayTime = Global.DayTime; UpdateShowOrHide(); }
Как отправить им общую команду, то что время изменилось? Не через BroadcastMessage же на весь уровень отправлять сообщение?
Сообщение отредактировал alexsilent - Вторник, 15 Ноября 2022, 00:32 |
|
| |
TLT | Дата: Вторник, 15 Ноября 2022, 00:39 | Сообщение # 4 |
Сейчас на сайте
| alexsilent, гипотетически ты сейчас напридумываешь... Определись, речь про индикатор здоровья, количество золота или время? Я сказал, что переменная меняется 1 раз при её изменении. А ты говоришь о том, как от этого значения действовать другим объектам? Прозванивать периодично или когда к ним обращаешься - зависит от интерактивности и функциональности объекта. Если они автономны и должны действовать в реальном времени, то обращаться периодично, либо сообщать им индивидуально каждому, а как ещё...
Дао, выраженное словами, не есть истинное Дао.
|
|
| |
alexsilent | Дата: Вторник, 15 Ноября 2022, 00:48 | Сообщение # 5 |
почти ветеран
Сейчас нет на сайте
| TLT, Я просто все так проверки делаю. Делаю их автономными, ибо иногда не знаю кто или что изменит эту переменную. И непонятно как отследить...
Если бы только в юнити была бы такая системная функция у скриптов:
Код void OnUpdateVariable(MyVariable) { // лол
}
Добавлено (15 Ноября 2022, 01:00) --------------------------------------------- Нашёл я тут один вариант, вообще норм вот так делать для переменных? get/set?
https://www.youtube.com/watch?v=V3fXY-clRjg&ab_channel=RAZDOLBAYS
Сообщение отредактировал alexsilent - Вторник, 15 Ноября 2022, 01:01 |
|
| |
martuk | Дата: Вторник, 15 Ноября 2022, 10:56 | Сообщение # 6 |
заслуженный участник
Сейчас нет на сайте
| Одно из решений использовать систему управления состоянием. Нужно не проверять каждую переменную вручную а создать хранилище, которое хранит текущее состояние, а это будет, к примеру, мана, хп, патроны и все в таком духе. Затем, когда требуется изменить переменную, мы не обращаемся к ней на прямую а вызываем специальный метод у хранилища, который обновляет состояние, вызывет нужные коллбеки и отправляет сигнал подписчикам на этот стор. Далее просто подписываемся на хранилище в том месте, где нам требуется знать актуальные данные.Добавлено (15 Ноября 2022, 11:05) --------------------------------------------- Уже есть готовые решения, можно загуглить так: managing application state, state pattern, главное не путать со state machine
Сообщение отредактировал martuk - Вторник, 15 Ноября 2022, 10:57 |
|
| |
MagicHero | Дата: Вторник, 15 Ноября 2022, 11:48 | Сообщение # 7 |
участник
Сейчас нет на сайте
| alexsilent, Насчет шкалы здоровья то ты же ее рисуешь и так каждый кадр. И там явно должно быть указано ее размер, который зависит от переменной и которая в этом коде есть. Изменилась переменная, изменилась шкала здоровья. И разницы с тем что она не менялась или поменялась нет вообще.
Но если у тебя там как то по заумному идет, например в моей игре я использую для количества денег картинки цифр и чтобы каждый кадр не разбивать скажем число 1234567890 на отдельные символы я сделал скрипт который активируется в момент получения или трат денег. Т.е. деньги истратили, активировался скрипт по распределению картинок и дальше каждый кадр они уже рисуются. Тебе также надо сделать, отняли или прибавили здоровье, активировался скрипт для перерисовки шкалы здоровья, какого либо текста или состояния (заболел, травма, при смерти и т.д.)
|
|
| |
TLT | Дата: Вторник, 15 Ноября 2022, 17:11 | Сообщение # 8 |
Сейчас на сайте
| Цитата MagicHero ( ) Насчет шкалы здоровья то ты же ее рисуешь и так каждый кадр.
Отображение элемента (спрайта) на экране не значит, что он рисуется каждый кадр. Если у тебя рисуется он каждый кадр, то это не оптимизированное решение.
Дао, выраженное словами, не есть истинное Дао.
|
|
| |
alexsilent | Дата: Вторник, 15 Ноября 2022, 17:23 | Сообщение # 9 |
почти ветеран
Сейчас нет на сайте
| Цитата TLT ( ) Если у тебя рисуется он каждый кадр, то это не оптимизированное решение. В Tic-80 и Pico-8 так. И я также делаю в GMS. В юнити же это конечно реально будет плохо, ибо юнити не рисует напрямую в графику, а вначале создаётся объект.
Сообщение отредактировал alexsilent - Вторник, 15 Ноября 2022, 17:28 |
|
| |
martuk | Дата: Вторник, 15 Ноября 2022, 20:31 | Сообщение # 10 |
заслуженный участник
Сейчас нет на сайте
| Цитата alexsilent ( ) И я также делаю в GMS А вот и плохо!) По-хорошему интерфейсы нужно отрисовывать по факту изменения в конечном итоге всего на один сюрфейс в качестве таргета и уже его отрисовывать каждый кадр. Всякие функции draw_* не такие быстрые как кажется и их использование лучше минимизировать
|
|
| |
drcrack | Дата: Вторник, 15 Ноября 2022, 21:13 | Сообщение # 11 |
старожил
Сейчас нет на сайте
| Посмотри например https://docs.unity3d.com/560/Documentation/Manual/UnityEvents.html Их можно вытащить в инспектор и настроить обработчики типо как на кнопках
Цитата Отображение элемента (спрайта) на экране не значит, что он рисуется каждый кадр. Если у тебя рисуется он каждый кадр, то это не оптимизированное решение. Как и в любом современном движке, в Unity каждый кадр экран очищается и рисуется заново
Цитата Мне иногда жать, что в юнити нет способа рисовать сразу напрямую в графику, вместо создания объекта спрайта. Способы есть, причем разные, но в 95% случаев все же проще создать "объект со своими скриптами и скриптом спрайта"
|
|
| |
HaGe | Дата: Понедельник, 21 Ноября 2022, 12:56 | Сообщение # 12 |
постоянный участник
Сейчас нет на сайте
| Цитата alexsilent ( ) Но мне тут сказали, что это не оптимально каждый кадр проверять переменную. больше слушай экспертов )
можешь быть уверен, что чистый c# будет достаточно быстро выполнен
о производительности, качестве кода и смысле жизни стоит задумываться, если у тебя слишком много if'ов идут подряд. скорее всего ты что-то делаешь не так в таком случае
+ стоит реально переживать за производительность в моментах получения доступа к компонентам юньки
Цитата alexsilent ( ) Нашёл я тут один вариант, вообще норм вот так делать для переменных? get/set?
https://www.youtube.com/watch?v=V3fXY-clRjg&ab_channel=RAZDOLBAYS да.
Цитата TLT ( ) Зависит от жанра и типа игры. При коллизии обычно обновляется. Не пойму зачем вообще здоровье периодично обновлять, если обновление можно производить исключительно при изменении параметра. Если здоровье изменилось, то передано обновление на индикатор/бар. Цитата alexsilent ( ) TLT, Я просто все так проверки делаю. Делаю их автономными, ибо иногда не знаю кто или что изменит эту переменную. И непонятно как отследить... очень хороший совет
я бы сделал так:
Код // подписываемся на изменение хелсбара, чтобы вызывать его только тогда, когда хп меняется Healthbar.OnChange += UpdateHealthBar;
// ...
// где-то в другом месте можем поменять хелсбар и наш метод вызовется Healthbar.Amount = 22;
// а это класс, в котором хранится хп. юзаем паттерн наблюдатель по сути public static class Healthbar { public static event Action OnChange;
private static int _amount = 100;
public static int Amount { get => _amount; set { _amount = value; OnChange.Invoke(); } } }
Сообщение отредактировал HaGe - Понедельник, 21 Ноября 2022, 14:08 |
|
| |
drcrack | Дата: Понедельник, 21 Ноября 2022, 17:49 | Сообщение # 13 |
старожил
Сейчас нет на сайте
| направление верное, но есть несколько нерешенных проблем из-за которых реальный код будет в 5 раз больше: 1) OnChange вызывается даже если новое значение равно старому 2) OnChange вызывается при каждом изменении, хоть 1000 изменений за кадр, хотя интерфейс достаточно обновлять 1 раз 3) Что если в игре больше чем 1 хп бар?
PS Бонусный пункт: Согласно стандартам нейминга в C# это событие должно называться не OnChange а AmountChanged (или HealthChanged или HealthAmountChanged) https://learn.microsoft.com/en-us....-events
Сообщение отредактировал drcrack - Понедельник, 21 Ноября 2022, 17:55 |
|
| |
HaGe | Дата: Понедельник, 21 Ноября 2022, 21:52 | Сообщение # 14 |
постоянный участник
Сейчас нет на сайте
| Цитата drcrack ( ) направление верное, но есть несколько нерешенных проблем из-за которых реальный код будет в 5 раз больше: 1) OnChange вызывается даже если новое значение равно старому 2) OnChange вызывается при каждом изменении, хоть 1000 изменений за кадр, хотя интерфейс достаточно обновлять 1 раз 3) Что если в игре больше чем 1 хп бар? 1 и 3 - нужен контекст.
2 - справедливо. для UI лучше инвокать ивент в апдейте, как это делает ТС
upd. касательно 1. вообще я хотел изначально написать метод Change (int value) и оставить это на совесть клиента, т.к. лишний if не хочется пихать. но свойство мне показалось более наглядным для примера
Сообщение отредактировал HaGe - Понедельник, 21 Ноября 2022, 22:08 |
|
| |
|