Понедельник, 11 Ноября 2024, 02:19

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Как лучше проверять изменение переменной?
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
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг