| 
				
				Как лучше проверять изменение переменной?
				 |   |  
| 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  |  
| 
 | 
 |    |     
		
		 
 |