Unity 使用物理射線(Physics.Raycast),實現扇形區域碰撞檢測三種方法(借鑑大神,僅做爲筆記用)

Unity 使用物理射線(Physics.Raycast),實現扇形(Fan-Shaped)區域碰撞檢測。
參考以前的製做簡單AI: Unity 有限狀態機(Finite State Machine)的理解 與 實現簡單的可插拔(Pluggable)AI腳本對象。
源碼:GentleTank/PluggableAI/Scripts/Decision/LookDecision.cside

方法一:性能

實現原理:(lookAngle / 2) / lookAccurte

  很簡單,就是射多幾條角度平均的射線。能夠設置角度,精度(射線數量),來調節扇形區域的檢測。每條射線夾角是總夾角處於2,再除於精度。
  spa

1. 默認是射出一條向前的射線,精度爲0。

 

 

2. 設置角度爲90,精度爲1,就會多出兩條相對正前方45度的射線。

 

 

3.設置精度爲2。

 

 

實現代碼

//
// 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;
}內存

最終效果

查找角度:90、精度:6,追殺角度1五、精度2。

 

 

  • 紅坦克是查找時敵人發出的綠色射線;
  • 綠坦克是追殺時發出紅色射線;
  • 藍坦克在第一條默認射線就檢測到敵人,因此就不須要在添加額外角度射線。

     

     

    查找精度:50、追殺精度:10。

  •  

     基本像個扇形了,並且性能沒有太大變化。

  • 方法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;
    }

  •  

     上圖中射線實際上是一直在擺動的。

  • 方法3:

      就是結合方法1和方法2了,多條線同時旋轉檢測,算是結合前二者的優勢了。

      原理就是在方法2基礎上,多加一層循環,即同一幀有多條線檢測,以下修改代碼。

  • [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°。

相關文章
相關標籤/搜索