Menu
CoddyTech

基础敌人脚本

本课属于 Coddy Unity 学习旅程的“Unity 游戏架构”单元。第 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";
    }
}

Ghost 的 Describe() 会返回 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 的 Start 是一个 private void Start(),而 Ghost 声明了自己的 Start,Unity 就只会调用 Ghost 的方法:Enemy 的方法不会运行,hp 会保持为 0,而且不会报错。将基类的这些消息声明为 protected virtual,就能使用普通的 C# 机制:子类写上 override,而 base.Start() 会在你调用它的位置运行基类中的部分代码。如果省略这个调用,基类中的部分就会被跳过。这样,子类就能替换某个步骤,而不是在原有步骤上添加内容。

challenge icon

挑战

简单

让 Golem 和 Wasp 先运行 Enemy 中的部分,再运行各自的部分。

  1. 在 Enemy 中,在 void Start() 和 void Update() 前面写上 protected virtual。
  2. 在 Golem 中,将其改为 protected override void Start(),并将 base.Start(); 作为第一行。
  3. 在 Wasp 中,将其改为 protected override void Update(),并将 base.Update(); 作为第一行。

按下 Play:石像怪会以满血状态行进,黄蜂会一边行进一边 zigzag。然后点击 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 游戏架构中的所有课

自己练习: Unity 在线编辑器