Menu
CoddyTech

События управляют UI

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

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

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; } позволяет интерфейсу читать здоровье, но не изменять его.

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

challenge icon

Задание

Легко

Пусть оружие сообщает об изменениях, а HUD их отслеживает.

  1. В Gun.cs добавь using System;, public event Action<int, int> OnAmmoChanged и public event Action<bool> OnReloading; вызывай их в местах, указанных в комментариях.
  2. В AmmoHud.cs подпишись в OnEnable и отпишись в OnDisable: ammoText показывает Ammo: 4/6, а reloadText отображается только во время перезарядки.
  3. В Start один раз отобрази gun.Ammo и gun.Reloading.

Нажми «Играть» и дважды разряди оружие. Затем нажми «Проверить».

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

using UnityEngine;
using TMPro;

public class AmmoHud : MonoBehaviour
{
    public Gun gun;
    public TMP_Text ammoText;
    public GameObject reloadText;
}

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

Потренируйтесь самостоятельно: Песочница Unity