Menu
CoddyTech

Базовый скрипт врага

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

В C# один класс может наследоваться от другого: class Ghost : Enemy получает все поля и методы Enemy и добавляет собственные. Метод, помеченный базовым классом как virtual, можно заменить в подклассе с помощью override, а base.Describe() запускает версию базового класса изнутри новой. Обычный код на C#:

class Enemy
{
    protected int hp = 3;

    public virtual string Describe()
    {
        return "Enemy with " + hp + " hp";
    }
}

class Ghost : Enemy
{
    public override string Describe()
    {
        return base.Describe() + ", see-through";
    }
}

Вызов Describe() у Ghost возвращает Enemy with 3 hp, see-through. protected означает, что Enemy и его подклассы могут использовать hp, а другие классы — нет.

В Unity у врагов большая часть кода общая: очки здоровья, скорость, способ передвижения. Этот код находится в базовом классе, который наследуется от MonoBehaviour, а каждый вид врагов наследуется от него. Этот Enemy задаёт очки здоровья в Start и движется в направлении, куда он обращён, в Update, а Ghost изменяет начало, чтобы двигаться в два раза быстрее:

public class Enemy : MonoBehaviour
{
    public int maxHp = 3;
    public float speed = 2f;
    protected int hp;

    protected virtual void Start()
    {
        hp = maxHp;
    }

    protected virtual void Update()
    {
        transform.Translate(Vector3.forward * speed * Time.deltaTime);
    }
}
public class Ghost : Enemy
{
    protected override void Start()
    {
        base.Start();
        speed *= 2f;
    }
}

Ghost наследует поля, поэтому в Inspector у Ghost отображаются maxHp и speed. Он также наследует Update, поэтому движется без собственного Update. hp имеет уровень доступа protected: Enemy и его подклассы могут использовать его, а другие скрипты — нет.

Unity находит Start и Update по имени независимо от уровня доступа и вызывает метод в наиболее производном классе. Если бы у Enemy был закрытый void Start(), а Ghost объявил свой, Unity вызвала бы только метод Ghost: метод Enemy никогда бы не выполнялся, а hp оставался бы равным 0 без ошибки. Объявление сообщений базового класса как protected virtual делает это обычным C#: подкласс пишет override, а base.Start() выполняет часть базового класса в месте вызова. Не укажешь этот вызов — часть базового класса будет пропущена. Так подкласс заменяет шаг, а не дополняет его.

challenge icon

Задание

Легко

Сделай так, чтобы Golem и Wasp выполняли часть Enemy перед своей собственной.

  1. В Enemy добавь protected virtual перед void Start() и void Update().
  2. В Golem замени объявление на protected override void Start(), а первой строкой добавь base.Start();.
  3. В Wasp замени объявление на protected override void Update(), а первой строкой добавь base.Update();.

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

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

using UnityEngine;

// Что общего у всех монстров.
public class Enemy : MonoBehaviour
{
    public int maxHp = 4;
    public float speed = 1.5f;

    protected int hp;
    protected Vector3 spawnPoint;

    void Start()
    {
        hp = maxHp;
        spawnPoint = transform.position;
    }

    void Update()
    {
        // двигаться к замку вдоль оси z в отрицательном направлении
        transform.position += Vector3.back * speed * Time.deltaTime;
    }
}

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

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