IDamageable
本课属于 Coddy Unity 学习旅程的“Unity 游戏架构”单元。第 7 课,共 64 课。
接口是一个方法列表,类承诺会实现这些方法,但接口中没有方法代码。彼此毫无其他共同点的类也可以作出相同的承诺。用简单的 C# 表示:
interface IGreeter
{
string Greet();
}
class Robot : IGreeter
{
public string Greet() { return "Beep"; }
}
class Cat : IGreeter
{
public string Greet() { return "Meow"; }
}IGreeter 类型的变量可以保存 Robot 或 Cat,调用 greeter.Greet() 时,会运行它当前保存的对象对应的方法。声明实现 IGreeter,却没有公共 Greet() 方法的类无法通过编译。
在游戏中,许多东西都可能受到伤害,但它们几乎没有其他共同点:玩家有生命值,箱子则会在受到第一次攻击时损坏。共用一个基类会迫使它们归入同一个类别。接口只定义它们共有的特征,每个脚本都可以用自己的方式实现它:
public interface IDamageable
{
void TakeDamage(int amount);
}public class PlayerHealth : MonoBehaviour, IDamageable
{
public int hp = 10;
public void TakeDamage(int amount)
{
hp -= amount;
Debug.Log("Ouch! hp: " + hp);
}
}public class Crate : MonoBehaviour, IDamageable
{
public void TakeDamage(int amount)
{
Destroy(gameObject);
}
}脚本仍然只有一个基类 MonoBehaviour,接口则列在基类后面。接口要放在单独的文件 IDamageable.cs 中,而且不继承自 MonoBehaviour:它不是组件,也不会单独添加到对象上。声明实现该接口的类必须有公共的 TakeDamage(int) 方法,否则无法通过编译。
造成伤害的对象要获取接口,而不是某个类:
// Fireball.cs
void OnCollisionEnter(Collision collision)
{
IDamageable target = collision.gameObject.GetComponent<IDamageable>();
if (target != null)
{
target.TakeDamage(3);
}
Destroy(gameObject);
}火球用同一段代码伤害玩家、摧毁箱子,以后添加其他类型的目标也不需要修改这里。Unity 不会在 Inspector 中显示接口类型的字段,因此脚本会保存 GameObject 或组件,再从中获取接口,就像火球脚本所做的那样。
挑战
简单让雪人、铃铛和稻草人实现 IDamageable,这样锤子就能击中它们。
Snowman:每次调用TakeDamage,都让它在每个轴上缩小0.25f * amount;缩小到 0.5 或更小时,就销毁它。Bell:每点伤害记录一次Dong,并将amount加到rings上。Scarecrow:只有第一次被击中时,才运行transform.Rotate(0f, 0f, 90f);。- 在
Slam中,如果每个碰撞体上存在IDamageable,就对它调用TakeDamage(power)。
按“开始”,然后挥锤击打每个目标。接着点击“检查”。
亲手试试
using UnityEngine;
public class Snowman : MonoBehaviour
{
}
Unity 游戏架构中的所有课
自己练习: Unity 在线编辑器