База знаний ЯЮниор
  • C#
    • 🗃️Ссылочные и значимые типы в C# Ключевые слова ref, out, in Что нужно знать новичку
    • 📋Использование констант
    • 🔖Snippet или фрагмент кода
    • 📝Пустые строки
    • 🛡️Инкапсуляция
  • Unity
    • 🚶‍♂️Управление Параметрами Аниматора
    • ⚙️Динамическое изменение объектов
      • 🛠️Создание объектов
      • 🪛Изменение объектов
      • 🪚Добавление и изменение компонентов
      • 🔥Удаление объектов и компонентов
    • 🔊События
      • 🧬Параметризация
      • 🔗Совмещение событий
      • 📡Action и UnityAction
      • 🕹️UnityEvent
    • 🔌Подключение среды разработки к Unity
    • ⌚Корутины
      • 🪄Управление корутинами
      • ⏰Yield Instruction
      • 🕵️‍♂️Как устроены корутины?
  • Git и GitHub
    • 🗃️Git
    • 🗄️GitHub
    • 🖥️GitHub Desktop
Powered by GitBook
On this page
  • Пример проблемы
  • Суть проблемы
  • И какое отношение к этому имеют события?
  • Что с этим делать дальше?

Was this helpful?

  1. Unity

События

Автор: Дмитрий Прокопьев

У вас когда-нибудь случалось такое, что один компонент влез в зону ответственности другого? Ситуация, когда на такой компонент сваливалась вся работа и из за этого он становился перегруженным? С этим рано или поздно сталкиваются все, но не все знают, как решить эту проблему.

Пример проблемы

Представим, что мы работаем над игрой, в которой персонаж может зарабатывать игровую валюту и тратить ее в магазине. Для этого мы сделали ему простой кошелек:

public class Wallet : MonoBehaviour
{
    public int Money { get; private set; }
    
    public void AddMoney(int amount)
    {
        if (amount <= 0)
            return;
        
        Money += amount;
    }
    
    public bool TrySpendMoney(int amount)
    {
        if (amount <= 0)
            return;
        
        bool isEnough = Money >= amount;
        
        if (isEnough)
            Money -= amount;
        
        return isEnough;
    }
}

У этого кошелька одна простая ответственность: проводить транзакции и обеспечивать их корректность. Но теперь нам прислали новую задачу: отображать количество средств на экране. Не проблема, мы уже реализовали класс WalletView, который умеет отображать количество средств. Осталось лишь вызвать у него метод:

[SerializeField] private WalletView _walletView;
//...
_walletView.Display(Money);

Нам опять пришла новая задача! Теперь каждый раз, когда происходит транзакция, нужно сделать сохранение в файл, чтобы запомнить сколько денег теперь есть у игрока. Не проблема, мы уже реализовали класс FileSaver, который умеет сохранять количество денег. Нужно лишь вызвать у него метод:

[SerializeField] private FileSaver _fileSaver;
//...
_fileSaver.SaveMoney(Money);

Удивительно, опять новая задача! Теперь магазин должен предлагать игроку новые товары, когда тот произвел транзакцию. Не проблема, обратимся к классу Shop:

[SerializeField] private Shop _shop;
//...
_shop.OfferItems(Money);

Видите, куда это идет? Вот так теперь выглядит метод AddMoney у кошелька:

public void AddMoney(int amount)
{
    if (amount <= 0)
        return;
        
    Money += amount;
    
    _walletView.Display(Money);
    _fileSaver.SaveMoney(Money);
    _shop.OfferItems(Money);
}

Бред, так ведь? Теперь кошелек делает совершенно не свою работу. Как нам в будущем догадаться, что именно кошелек делает все это? Как понять, почему магазин внезапно перестал работать, когда мы всего лишь убрали кошелек у игрока? Как понять, почему кошелек отказывается работать, когда мы всего лишь выключили интерфейс? Много вопросов - мало ответов.

Суть проблемы

Где в этой ситуации корень зла? Когда мы допустили роковую ошибку? Мы сделали это тогда, когда повесили на кошелек задачи других компонентов. Но как этого избежать, если только кошелек знает, что происходит с деньгами?

Например, кошелек может уведомить всех, что происходит, но не указывать компонентам, что именно делать. Тогда ответственность за реакцию компонентов переляжет с кошелька на них самих. Мысленно представим такой диалог:

- Wallet (кричит через громкоговоритель): Количество денег изменилось! Теперь у нас 50 монет. Сами решайте что делать с этим, на этом мои полномочия все.

- WalletView: Мне это важно. Выведу на экран число 50

- FileSaver: Мне это важно. Запишу в файл число 50

- PlayerMover: Меня это не беспокоит, направление движения игрока не зависит от финансового положения. Я ничего не слышал

- Shop: Мне это важно. Обновлю ассортимент товаров: добавлю те, которые можно купить за 50 монет

- Coin: Меня не интересует, сколько денег у игрока. Я ничего не слышал

Заметьте, как кошелек больше не отвечает за остальных! Он сообщил информацию и на этом успокоился. Так мы и можем решить эту проблему.

И какое отношение к этому имеют события?

Событие (англ. Event) - это механизм, позволяющий организовать общение между компонентами описанным выше образом. Название "Событие" появилось, потому что сообщение, которое передает компонент, говорит, что "что-то случилось" или "произошло какое-то событие". То есть событием называется само "сообщение".

Тот компонент, который сообщает информацию через событие, называется владельцем события. Помните, как некоторые компоненты услышали сообщение, а некоторые нет? Одни называются "слушателями" (англ. Listeners) или "подписчиками" события, потому что они получают из него информацию. А другие никак не называются, не хотят - не слушают.

Чтобы стать слушателем события, нужно на него подписаться (англ. Subscribe), а чтобы перестать быть слушателем нужно отписаться (англ. Unsubscribe).

Что с этим делать дальше?

PreviousУдаление объектов и компонентовNextПараметризация

Last updated 1 year ago

Was this helpful?

Теперь нам известно, зачем нужны события, и мы знаем основные термины. Осталось только почитать про типы событий и их синтаксис: и

🔊
UnityAction
UnityEvent