Menu
CoddyTech

Награды

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

Каждый враг, которого башня уничтожает, приносит ей reward. Enemy сообщает об убийстве так же, как сообщает о достижении базы: с помощью статического события Killed, а GameManager слушает его и добавляет деньги.

За убийство нужно платить один раз. Destroy не удаляет объект сразу: это происходит в конце кадра, и до тех пор он всё ещё находится в игре. Два выстрела могут попасть в цель в одном кадре, и второй обнаружит врага с 0 здоровья, который всё ещё на месте. Если TakeDamage сообщает об убийстве каждый раз, когда здоровье равно 0 или ниже, второй выстрел снова принесёт награду. В игре с воздушными шариками и дротиками возникает та же проблема, и её решает bool:

public void Pop()
{
    if (popped)
    {
        return;
    }

    popped = true;
    Popped?.Invoke(this);
    Destroy(gameObject);
}

Врагу не нужен дополнительный bool, поскольку его здоровье уже показывает, мёртв ли он: если TakeDamage обнаруживает, что здоровье равно 0 или ниже, ему больше нечего делать.

challenge icon

Задание

Средне
  1. В Enemy объяви публичное статическое событие Killed (Action<Enemy>). Вызови его, передав врага, когда TakeDamage уменьшает его здоровье до 0 или ниже, непосредственно перед его уничтожением.
  2. Убийство приносит награду только один раз: если вызвать TakeDamage для врага, чьё здоровье уже равно 0 или ниже, ничего не происходит.
  3. В GameManager добавь public void Earn(int amount), который прибавляет деньги и отображает их. Подпишись на Enemy.Killed рядом с ReachedBase и начисляй reward убитого врага.

Нажми Play и наблюдай, как растёт сумма денег, пока работают башни, затем нажми Check.

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

using System;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour, IDamageable
{
    public static readonly List<Enemy> All = new List<Enemy>();
    public static event Action<Enemy> ReachedBase;

    public EnemyData data;
    public Transform[] waypoints;

    private int next = 1;
    private int health;

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

    void OnEnable()
    {
        All.Add(this);
    }

    void OnDisable()
    {
        All.Remove(this);
    }

    void Update()
    {
        Vector3 target = waypoints[next].position;
        transform.position = Vector3.MoveTowards(transform.position, target, data.speed * Time.deltaTime);
        if (transform.position == target)
        {
            next++;
            if (next == waypoints.Length)
            {
                ReachedBase?.Invoke(this);
                Destroy(gameObject);
            }
        }
    }

    public void TakeDamage(int amount)
    {
        health -= amount;
        if (health <= 0)
        {
            Destroy(gameObject);
        }
    }
}
quiz iconПроверьте себя

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

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