Базовый скрипт врага
Часть раздела Архитектура игр в 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() выполняет часть базового класса в том месте, где вы его вызываете. Не вызывайте его — и часть базового класса будет пропущена. Так подкласс заменяет шаг, а не добавляет к нему что-то.
Задание
ЛегкоМонстры наступают на замок. В 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;
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Архитектура игр в Unity
1Компоненты, а не иерархии
Небольшие компонентыБазовый скрипт врагаАбстрактные компонентыСовместная работа компонентовПовторение: модульная турель4Сериализованные данные
Сериализуемые классыСписки в InspectorПеречисления в InspectorПовторение: таблица лута2Интерфейсы в Unity
IDamageableИнтерфейсы и TryGetComponentGetComponentsПовторение: клавиша взаимодействия5ScriptableObjects
Ресурсы данныхХарактеристики оружияОбщие настройкиВолны как данныеПовторение: база предметов