Unity3D RPG Core | 23 扩展方法
这节我们实现敌人面向的攻击视角内,如果没有角色人物,则不对角色人物造成伤害。这也是符合现实逻辑的。
1. 使用扩展方法实现
我们新建一个 C# 脚本,命名为 ExtensionMethod。内容如代码清单 1 所示,扩展方法类需要是静态的。编写 IsFacingTarget() 函数实现对范围的判断。
IsFacingTarget() 函数的第一个参数就是需要扩展的类,使用 this 关键字申明。这边的 this 关键字就暗示了 this 指针的意思,加上语言支持反射,所以对实现的机制并不好奇。
- static public class ExtensionMethod
- {
- static float m_dotThreshold = 0.5f;
- static public bool IsFacingTarget(this Transform transform, Transform target)
- {
- Vector3 toTarget = target.position - transform.position;
- toTarget.Normalize();
- float dot = Vector3.Dot(transform.forward, toTarget);
- return dot >= m_dotThreshold;
- }
- }
IsFacingTarget() 的实现,主要是使用了 Vector3.Dot 判断敌人面向朝向与角色人物之间的角度。Vector3.Dot 就是点积的计算:
\(\vec{a}\cdot\vec{b}=\lvert\vec{a}\rvert\lvert\vec{b}\rvert cos\theta\)
当向量都是单位向量时,两个向量的点积返回的就是两个向量之间角度的 cos 值。各个角度的 cos 值如图 1 所示,小于 0 代表背向。这边指定 cos 值大于 0.5 为在视线范围内。大于 0.5 为左右 60 度这 120 度范围内。

2. 增加判断条件
敌人产生伤害是在之前定义的 Hit() 函数中实现的。如代码清单 2 所示,现在我们在上面增加判断条件,只有面向角色人物的时候才会产生伤害。
- public class EnemyController : MonoBehaviour, IEndGameObserver
- {
- // Animation Event
- void Hit()
- {
- if (transform.IsFacingTarget(m_playerObj.transform))
- {
- CharacterData playerCharacterData = m_playerObj.GetComponent<CharacterData>();
- m_attackData.TakeDamage(playerCharacterData);
- }
- }
- }
我们做如下测试:将角色人物的血量设置为 1,如图 2 所示,通过走位来躲避敌人的攻击。
