参考之前的制作简单AI: Unity 有限状态机(Finite State Machine)的理解 与 实现简单的可插拔(Pluggable)AI脚本对象。
源码:GentleTank/PluggableAI/Scripts/Decision/LookDecision.cs
网上已经很多实现扇形检测的方法。大部分都是用MeshCollider实现的。而据说MeshCollider这东西很耗性能(没有亲测),所以就用射线来实现。在之前看官方教程时,作者使用了Physics.SphereCast(射出类似圆柱体)来检测坦克前方是否有Player,但我自己在制作成扇形射线时,发现相比使用Physics.SphereCast,使用多条Physics.RayCast有更好的性能,而且更精确。及射线细而密。
很简单,就是射多几条角度平均的射线。可以设置角度,精度(射线数量),来调节扇形区域的检测。每条射线夹角是总夹角处于2,再除于精度。
//
// LookDecision
//
//放射线检测
private bool Look(StateController controller)
{
var defaultStats = controller.defaultStats;
//一条向前的射线
if (LookAround(controller, Quaternion.identity, Color.green))
return true;
//多一个精确度就多两条对称的射线,每条射线夹角是总角度除与精度
float subAngle = (defaultStats.lookAngle / 2) / defaultStats.lookAccurate;
for (int i = 0; i < defaultStats.lookAccurate; i++)
{
if (LookAround(controller, Quaternion.Euler(0, -1 * subAngle * (i + 1), 0), Color.green)
|| LookAround(controller, Quaternion.Euler(0, subAngle * (i + 1), 0), Color.green))
return true;
}
return false;
}
//射出射线检测是否有Player
static public bool LookAround(StateController controller, Quaternion eulerAnger,Color DebugColor)
{
Debug.DrawRay(controller.eyes.position, eulerAnger * controller.eyes.forward.normalized * controller.defaultStats.lookRange, DebugColor);
RaycastHit hit;
if (Physics.Raycast(controller.eyes.position, eulerAnger * controller.eyes.forward, out hit, controller.defaultStats.lookRange) && hit.collider.CompareTag("Player"))
{
controller.chaseTarget = hit.transform;
return true;
}
return false;
}
- 基本像个扇形了,而且性能没有太大变化。
//
// LookDecision
//
[Range(0, 360)]
public float angle = 90f; //检测前方角度范围
[Range(0, 100)]
public float distance = 25f; //检测距离
public float rotatePerSecond = 90f; //每秒旋转角度
//放射线检测
private bool Look(StateController controller)
{
if (LookAround(controller, Quaternion.Euler(0, -angle / 2 + Mathf.Repeat(rotatePerSecond * Time.time, angle), 0), distance, debugColor))
return true;
return false;
}
上图中射线其实是一直在摆动的。
[Range(1, 50)]
public float accuracy = 1f; //检测精度
private bool Look(StateController controller)
{
float subAngle = angle / accuracy; //每条射线需要检测的角度范围
for (int i = 0; i < accuracy; i++)
if (LookAround(controller, Quaternion.Euler(0, -angle / 2 + i * subAngle + Mathf.Repeat(rotatePerSecond * Time.time, subAngle), 0), distance, debugColor))
return true;
return false;
}