Menu
CoddyTech

Доберитесь до базы

Урок 3 из 18 курса Игра в Unity: защита башен на Coddy.

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

Статическое событие решает обе проблемы. Оно принадлежит классу Enemy, а не отдельному врагу, поэтому GameManager подписывается один раз и получает сообщения от каждого врага, в том числе от созданных позже. Каждый враг вызывает это событие, передавая себя в качестве аргумента, чтобы слушатель мог узнать, какой вид врага прорвался. Монета в платформере сообщает о себе таким же образом:

public class Coin : MonoBehaviour
{
    public static event Action<Coin> Collected;
    public int value = 1;

    void OnTriggerEnter(Collider other)
    {
        Collected?.Invoke(this);
        Destroy(gameObject);
    }
}
// ScoreBoard.cs
void OnEnable()
{
    Coin.Collected += AddCoin;
}

void OnDisable()
{
    Coin.Collected -= AddCoin;
}

void AddCoin(Coin coin)
{
    score += coin.value;
}

Статическое событие существует, пока работает игра, поэтому -= важен как никогда: на уничтоженный ScoreBoard, от которого так и не отписались, всё ещё будут вызываться методы, и его код завершится с ошибкой при обращении к уничтоженному текстовому объекту. OnEnable и OnDisable идут парами, поэтому каждому += соответствует свой -=.

challenge icon

Задание

Легко

На базе должны быть жизни, и враг, добравшийся до неё, должен их отнимать.

  1. В EnemyData добавь публичное целое число damage: столько жизней этот тип врагов отнимает у базы.
  2. В Enemy объяви публичное статическое событие ReachedBase, которое передаёт врага (Action<Enemy>). Когда враг достигает последней путевой точки, вызови это событие, передав в него самого врага, и уничтожь его, вместо того чтобы останавливаться там.
  3. В GameManager добавь сериализованное целое число startLives (20) и приватное целое число lives, начальное значение которого равно этому числу. Подпишись на Enemy.ReachedBase в OnEnable и отпишись в OnDisable. Каждый прошедший враг отнимает у базы значение damage своего ресурса.
  4. Отображай количество жизней в сериализованном TMP_Text livesText в виде Lives: 20 в начале и после каждого изменения.

На объекте Game есть компонент GameManager, в Inspector привязан LivesText, а каждый из двух ресурсов отнимает 1 жизнь. Нажми Play, дождись, пока оба врага доберутся до базы, затем нажми Check.

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

using UnityEngine;

public class Enemy : MonoBehaviour
{
    public EnemyData data;
    public Transform[] waypoints;

    private int next = 1;
    private int health;

    void Awake()
    {
        health = data.maxHealth;
    }

    void Update()
    {
        if (next >= waypoints.Length)
        {
            return;
        }

        Vector3 target = waypoints[next].position;
        transform.position = Vector3.MoveTowards(transform.position, target, data.speed * Time.deltaTime);
        if (transform.position == target)
        {
            next++;
        }
    }
}
quiz iconПроверьте себя

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

Все уроки раздела Игра в Unity: защита башен