Menu
CoddyTech

События управляют интерфейсом

Часть раздела Архитектура игр в Unity путешествия по Unity на Coddy. Урок 13 из 50.

При использовании событий HUD следует за игрой, а игра ничего не знает о HUD. Компонент Health владеет очками здоровья и сообщает о двух вещах: здоровье изменилось и достигло 0. В нём нет поля для полосы, текста или экрана окончания игры, поэтому один и тот же компонент работает на игроке, на враге без HUD и в тестовой сцене:

public class Health : MonoBehaviour
{
    public int maxHp = 100;
    public event Action<int, int> OnChanged;
    public event Action OnDied;
    public int Hp { get; private set; }

    void Awake()
    {
        Hp = maxHp;
    }

    public void TakeDamage(int amount)
    {
        if (Hp == 0) return;
        Hp = Mathf.Max(Hp - amount, 0);
        OnChanged?.Invoke(Hp, maxHp);
        if (Hp == 0) OnDied?.Invoke();
    }
}
// HealthBar.cs, на HUD
public Health health;
public Image bar;

void OnEnable() { health.OnChanged += Show; }
void OnDisable() { health.OnChanged -= Show; }

void Start()
{
    Show(health.Hp, health.maxHp);
}

void Show(int hp, int max)
{
    bar.fillAmount = (float)hp / max;
}

Полоса слушает события, только пока она активна, благодаря паре OnEnable и OnDisable. Событие передаёт оба числа, поэтому Show больше ничего не нужно от компонента Health. GameOverScreen подписывается на OnDied, чтобы показать свою панель, а звук получения урона подписывается на OnChanged — каждый в своём скрипте; компонент Health при этом не меняется. Hp { get; private set; } позволяет HUD считывать здоровье, но не изменять его.

Событие сообщает об изменениях, поэтому до первого попадания полоса ничего не услышала. Она один раз отображает текущее здоровье в Start. Не в OnEnable: Unity вызывает Awake, а затем OnEnable для каждого объекта по отдельности, без гарантированного порядка, поэтому OnEnable полосы может выполниться раньше, чем Awake компонента Health установит Hp, и полоса покажет 0. К моменту выполнения любого Start уже выполнились все Awake.

challenge icon

Задание

Легко

Тир. Клавиша Space стреляет из оружия (Gun.cs), в котором есть maxAmmo (6) выстрелов. После последнего выстрела начинается перезарядка длительностью reloadTime (1.5) секунды, после которой боезапас восполняется. Пока что HUD ничего из этого не отображает. Сделай так, чтобы оружие сообщало об изменениях, а HUD слушал эти сообщения; у оружия не должно быть поля для HUD.

  • В Gun.cs добавь два публичных события: OnAmmoChanged, которое передаёт количество патронов и maxAmmo (два значения типа int), и OnReloading, которое передаёт bool: true, когда перезарядка начинается, и false, когда заканчивается. Вызывай их в местах, указанных в комментариях.
  • В AmmoHud.cs (на HUD) добавь прослушивание обоих событий, пока HUD активен. ammoText показывает количество патронов в формате Ammo: 4/6, а reloadText (объект с текстом Reloading...) отображается только во время перезарядки.
  • HUD должен правильно отображаться сразу, ещё до первого выстрела: Ammo: 6/6, без текста о перезарядке. Свойства оружия Ammo и Reloading содержат текущие значения.
  • Если HUD уничтожить, оружие продолжает стрелять без ошибок.

Нажми Play, разряди оружие дважды, затем нажми Check.

Попробуйте сами

using UnityEngine;
using TMPro;

public class AmmoHud : MonoBehaviour
{
    public Gun gun;
    public TMP_Text ammoText;
    public GameObject reloadText;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Архитектура игр в Unity