События управляют интерфейсом
Часть раздела Архитектура игр в 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.
Задание
ЛегкоТир. Клавиша 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;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Архитектура игр в Unity
1Компоненты, а не иерархии
Небольшие компонентыБазовый скрипт врагаАбстрактные компонентыСовместная работа компонентовПовторение: модульная турель4Сериализованные данные
Сериализуемые классыСписки в InspectorПеречисления в InspectorПовторение: таблица лута2Интерфейсы в Unity
IDamageableИнтерфейсы и TryGetComponentGetComponentsПовторение: клавиша взаимодействия5ScriptableObjects
Ресурсы данныхХарактеристики оружияОбщие настройкиВолны как данныеПовторение: база предметов3События
События C# в UnityПодписка в OnEnableПоля UnityEventСобытия управляют интерфейсомПовторение: всплывающее окно достижения6Сохранение с помощью JSON
JsonUtilityСохранение игрыЗагрузка и значения по умолчаниюПовторение: слоты сохранения