一、实现玩家进入敌人可视范围的检测
要实现该功能,我们可使用以下方法(也可以通过Distance判断距离)
实现逻辑:设计一个方法,通过物理检测获取到球体范围内的碰撞体,如果其中有Tag为“Player"的物体,则返回true,并将当前状态设置为CHASE(追击)
先创建以下变量
private GameObject attackTarget; //获取攻击目标
public float sightRadius; //发现玩家可视距离
方法设计如下
/// <summary>
/// 发现玩家检测
/// </summary>
/// <returns></returns>
private bool FoundPlayer()
{
var CollidersInArea = Physics.OverlapSphere(transform.position,sightRadius);
foreach(var collider in CollidersInArea) //上面方法返回数组类型,所以使用foreach遍历
{
if(collider.CompareTag("Player"))
{
attackTarget = collider.gameObject;
return true;
}
}
//未检测到Player则返回false
attackTarget = null;
return false;
}
在状态切换的SwitchState()方法中调用该检测即可
if (FoundPlayer())
{
enemyState = EnemyState.CHASE;
}
注意:上述创建的sightRadius变量需要在Inspector窗口设置大小。记得要为Player添加Tag和collider,否则检测不了Tag
二、实现追击玩家与脱战的逻辑
首先,我们在Enemy的动画中添加一个攻击层(Attack Layer),将其权重设置为1(以便随时从其他状态层进入),并设置一个基本状态Basic State,当满足一定条件时将进入该动画层。然后在动画Transition中设置好转换条件即可
当FoundPlayer()方法检测到玩家后,Enemy会进入CHASE状态,此时将Enemy的destination设置为玩家的坐标即可;当FoundPlayer()方法找不到玩家时,Enemy脱战并返回原点
注:为了能使Enemy能回到原点,我们需要在程序开始时获得原来的坐标OriginalPosition
private void ChaseMethod()
{
isWalk = false;
isChase = true;
if(attackTarget != null) //防止空引用报错
{
isFollow = true;
agent.SetDestination(attackTarget.transform.position); //追击玩家
}
if (!FoundPlayer()) //找不到玩家,返回原点
{
isFollow = false;
agent.SetDestination(transform.position); //拉脱后立即停下
agent.SetDestination(OriginalPosition);
//TODO:返回原点后转回原方向
}
注:此处返回原点后,应该恢复原来的朝向,但目前没有想到解决方案,待日后解决
最后,在CHASE状态中调用该方法即可