Unity 使用物理射線(Physics.Raycast),實現扇形(Fan-Shaped)區域碰撞檢測。
參考以前的製做簡單AI: Unity 有限狀態機(Finite State Machine)的理解 與 實現簡單的可插拔(Pluggable)AI腳本對象。
源碼:GentleTank/PluggableAI/Scripts/Decision/LookDecision.cside
方法一:性能
很簡單,就是射多幾條角度平均的射線。能夠設置角度,精度(射線數量),來調節扇形區域的檢測。每條射線夾角是總夾角處於2,再除於精度。
spa
//
// LookDecision
//debug
//放射線檢測
private bool Look(StateController controller)
{
var defaultStats = controller.defaultStats;3d
//一條向前的射線
if (LookAround(controller, Quaternion.identity, Color.green))
return true;orm
//多一個精確度就多兩條對稱的射線,每條射線夾角是總角度除與精度
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;
}blog
//射出射線檢測是否有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);ip
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;
}內存
基本像個扇形了,並且性能沒有太大變化。
方法2:
相對方法一,能夠說又省代碼,又省內存。缺點就是檢測扇形區域每一幀只有一個方向。
原理:只用一條射線,每次調用的時候旋轉必定角度。若是一秒走30幀,那就是一秒能夠變化30次角度。通常來講也夠了。實現起來就至關簡單了。使用Mathf.Repeat來獲取角度就行了。
//
// 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;
}
說明:藍色坦克:攻擊了紅坦克。紅坦克就同時放出紅色坦克:巡邏時不知道被誰打了,同時放出四條黃色射線旋轉檢測,每條射線只要旋轉90°就能夠檢測完周圍360°。綠色坦克:發現了敵人,每次先直接射出一條正前方的紅線(由於攻擊時常常只須要這一條第一幀就抓到敵人),另一條就是旋轉的檢測射線。黃色坦克:正在巡邏。三條綠色同時旋轉,檢測角度爲90°,因此每條射線只要旋轉30°。