Menu
CoddyTech

IDamageable

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

Интерфейс — это список методов, которые класс обещает иметь, но без кода внутри них. Классы, у которых больше нет ничего общего, могут давать одно и то же обещание. На простом C#:

interface IGreeter
{
    string Greet();
}

class Robot : IGreeter
{
    public string Greet() { return "Beep"; }
}

class Cat : IGreeter
{
    public string Greet() { return "Meow"; }
}

Переменная типа IGreeter может содержать Robot или Cat, а вызов greeter.Greet() запускает метод того объекта, который она содержит. Класс, в котором указан IGreeter, но нет публичного метода Greet(), не скомпилируется.

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

public interface IDamageable
{
    void TakeDamage(int amount);
}
public class PlayerHealth : MonoBehaviour, IDamageable
{
    public int hp = 10;

    public void TakeDamage(int amount)
    {
        hp -= amount;
        Debug.Log("Ouch! hp: " + hp);
    }
}
public class Crate : MonoBehaviour, IDamageable
{
    public void TakeDamage(int amount)
    {
        Destroy(gameObject);
    }
}

У скрипта по-прежнему один базовый класс — MonoBehaviour, а интерфейсы перечисляются после него. Интерфейс размещается в отдельном файле IDamageable.cs и не наследуется от MonoBehaviour: это не компонент, и сам по себе он никогда не добавляется к объекту. В классе, где он указан, должен быть публичный метод TakeDamage(int), иначе класс не скомпилируется.

Объект, наносящий урон, запрашивает интерфейс, а не класс:

// Fireball.cs
void OnCollisionEnter(Collision collision)
{
    IDamageable target = collision.gameObject.GetComponent<IDamageable>();
    if (target != null)
    {
        target.TakeDamage(3);
    }
    Destroy(gameObject);
}

Огненный шар наносит урон игроку и разбивает ящики с помощью одних и тех же строк кода, а если позже добавится новый тип цели, здесь ничего менять не потребуется. Unity не отображает в Inspector поле типа интерфейса, поэтому скрипты хранят GameObject или компонент и запрашивают у него интерфейс, как это делает огненный шар.

challenge icon

Задание

Легко

Сделай так, чтобы снеговик, колокол и пугало реализовывали IDamageable, чтобы молот попадал по ним.

  1. Snowman: TakeDamage уменьшает его размер на 0.25f * amount по каждой оси; если размер становится равным 0.5 или меньше, уничтожь его.
  2. Bell: выводи в журнал Dong за каждую единицу и добавляй amount к rings.
  3. Scarecrow: только при первом ударе вызывается transform.Rotate(0f, 0f, 90f);.
  4. В Slam вызывай TakeDamage(power) для IDamageable каждого коллайдера, если он есть.

Нажми «Играть» и ударь по каждому объекту. Затем нажми «Проверить».

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

using UnityEngine;

public class Snowman : MonoBehaviour
{
}

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

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