Menu
CoddyTech

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

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

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

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

challenge icon

Задание

Легко

Монстры наступают на замок. В Enemy.cs находится то, что у них общего: Start устанавливает hp равным maxHp и запоминает spawnPoint, а Update перемещает монстра вдоль оси z в отрицательном направлении со скоростью speed. Grunt — обычный Enemy, и он работает как надо. Два других вида добавляют собственное действие, но при этом каждый теряет поведение Enemy:

  • Golem: его Start увеличивает голема в 1.5 раза и выводит в журнал The golem wakes up, но его hp остаётся равным 0, потому что Unity выполняет Start голема, но не Start класса Enemy.
  • Wasp: его Update отклоняет осу на 1 единицу в обе стороны от spawnPoint.x, но она движется зигзагом на месте, потому что Unity выполняет Update осы, но не Update класса Enemy.

Сделай Start и Update класса Enemy protected virtual и переопредели их в Golem и Wasp, чтобы каждый из них сначала выполнял часть Enemy, а затем свою. Нажми Play, затем Check.

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

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;
    }
}
quiz iconПроверьте себя

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

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