抽象组件
本课属于 Coddy Unity 学习旅程的“Unity 游戏架构”单元。第 3 课,共 64 课。
有些基类描述的是一种不会单独存在的事物。每种武器都会开火,但既不是手枪也不是霰弹枪的武器无法开火。将这类标记为 abstract,并将子类必须编写的每个步骤声明为抽象方法,不包含方法体:
public abstract class Weapon : MonoBehaviour
{
public int shots;
public void Pull()
{
shots++;
Fire();
}
protected abstract void Fire();
}public class Shotgun : Weapon
{
public GameObject pelletPrefab;
protected override void Fire()
{
for (int i = -1; i <= 1; i++)
{
Instantiate(pelletPrefab, transform.position + transform.right * i * 0.3f, transform.rotation);
}
}
}如果子类没有编写 Fire,就无法编译:CS0534,'Pistol' does not implement inherited abstract member 'Weapon.Fire()'。Unity 也不允许将抽象脚本添加到对象上。把 Weapon 拖到对象上时,它会显示 Can't add script behaviour 'Weapon'. The script class can't be abstract!,因为 Unity 无法创建一个没有 Fire 的 Weapon。
其他脚本仍然可以使用基类类型。GetComponent<Weapon>() 会返回对象上实际存在的子类,而 Pull() 会运行该子类的 Fire:
// Player.cs
private Weapon weapon;
void Start()
{
weapon = GetComponent<Weapon>();
}
void Update()
{
if (Mouse.current.leftButton.wasPressedThisFrame)
{
weapon.Pull();
}
}将 Shotgun 组件换成 Pistol,Player 脚本仍然保持不变。
挑战
简单将 Monster 设为抽象类,让塔攻击每一种怪物。
- 在
Monster中,写出public abstract class Monster和protected abstract void React();,不要添加方法体。 - 现在编译器会指出
Imp有问题:添加protected override void React(),让它把Vector3.forward * 2f加到自身的位置上。 - 在
Tower中的循环里,对target.GetComponent<Monster>()调用Zap()。
按“开始”,再按 Space:史莱姆会缩小,小恶魔会向后跳。然后点击“检查”。
亲手试试
using UnityEngine;
// 所有怪物共有的内容。
public class Monster : MonoBehaviour
{
public int hp = 3;
public void Zap()
{
hp--;
if (hp <= 0)
{
Destroy(gameObject);
}
else
{
React();
}
}
// 这种怪物被电击后如果存活,会如何反应。
protected virtual void React()
{
}
}
Unity 游戏架构中的所有课
自己练习: Unity 在线编辑器