大家在玩《魂鬥羅》的時候一定知道遊戲中有一種追蹤彈吧,這種炮彈會隨着玩家位置的改變而改變,就像我們在某些軍事題材的電影中經常看到的鏡頭一樣,我方戰鬥機將敵機目標鎖定後發射炮彈,炮彈就會對敵機緊追不捨並最最終摧毀敵機。可是不管影視作品特效如何炫酷奪目,最終留給我們的就是華麗的特效背後蘊藏的原理。在遊戲開發領域,這種技術稱爲追蹤算法,它是屬於AI的一個範疇。常見的追中算法主要有三種,即座標追蹤、視線追蹤、攔截追蹤。下面呢,我們來分別講解這三種不同的追蹤算法:
一、座標追蹤
座標追蹤是最簡單、最基本的一種追蹤算法,如圖,
其基本思路是根據追蹤目標的座標來改變追蹤物體的座標,使兩者間距離縮短。舉一個簡單地例子,假設我們使用二維座標mPosition來表示追蹤物體的座標,使用mTargetPos來表示追蹤目標的座標,則座標追蹤的算法可以簡單表示成下面的代碼:
[csharp] view plaincopyprint?
if(mPosition.x<mTargetPos.x) mPosition.x+=Speed*Time.deltaTime;
if(mPosition.x>mTargetPos.x) mPosition.x-=Speed*Time.deltaTime;
if(mPosition.y<mTargetPos.y) mPosition.y+=Speed*Time.deltaTime;
if(mPosition.y>mTargetPos.y) mPosition.y-=Speed*Time.deltaTime;
二、視線追蹤,主要是指每一時刻都追蹤者會沿着被追逐者之間的直線方向運動。如圖所示:
由圖易知,該算法的關鍵是求解兩個位置間的連線。由向量的知識我們知道這條直線可以通過向量可以通過向量a-向量b得到。此時追蹤者的速度應該滿足約束條件:
水平分速度Vx/垂直分速度Vy=c向量的水平分量/c向量的垂直向量。
三、攔截追蹤,攔截追蹤是在前兩種方法的基礎上發展而來的一種方法,如果考慮的是追蹤目標太遠,如果兩者者速度一樣,或者相差不大,有可能很難追上。如圖
此時,對於追蹤物體而言,它只需要知道追蹤目標的位置、方向與速度,就會計算一個最佳的攔截位置,且所需要的時間最短。我們假設最佳攔截點是S2,由速度與位移的關係很容易知道 S2=Sp+t*V。其中t是追蹤者追上獵物的時間。接下來問題變爲一個簡單的追擊問題,求追擊時間t。
首先我們建立追蹤者與獵物的速度向量Va與Vp,及位置向量Sa與Sp。 設速度差向量 Vd =Vp-Va 。稱爲靠攏速度。 設距離差向量 Sd =Sp-Sa 。稱爲靠攏距離。 於是,靠攏時間 t=|Sd|/|Vd| 。即路程除以速度等於時間。 套用公式S2=Sp+t*V 就得到了攔截點S2,剩下的過程就與視線追蹤一樣。
好了,在理解了追蹤算法的基本原理以後,下面我們以一個最簡單的例子來演示今天的內容。首先我們在Unity3D中建立一個簡單地場景,如圖所示:
我們採取正交投影的方式來實現一個2D場景,場景中紅色的方塊爲目標物體,綠色的方塊爲追蹤物體。我們這裏採取的是視線追蹤的方法。我們首先來爲追蹤物體創建腳本Follow.cs。腳本定義如下:
[csharp] view plaincopyprint?
using UnityEngine;
using System.Collections;
public class Follow : MonoBehaviour {
//追蹤的目標物體
public Transform Target;
//兩個物體間的最小距離
public float MinDistance=1F;
//兩個物體間的最大距離
public float MaxDistance=5F;
//定義追蹤的速度
public float Speed=0.25F;
//定義追蹤物體的座標
private Vector2 mPosition;
//定義目標物體的座標
private Vector2 mTargetPos;
//是否在追蹤
private bool isFollow=false;
void Start ()
{
mPosition=new Vector2(transform.position.x,transform.position.y);
mTargetPos=new Vector2(Target.transform.position.x,Target.position.y);
}
void Update ()
{
//獲取目標物體的位置
mTargetPos=new Vector2(Target.transform.position.x,Target.position.y);
//如果追蹤物體與目標物體之間距離大於等於最大距離,則開始追蹤
if(Vector2.Distance(mPosition,mTargetPos)>=MaxDistance)
{
isFollow=true;
}
//如果追蹤物體與目標物體之間距離小於等於最小距離,則停止追蹤
if(Vector2.Distance(mPosition,mTargetPos)<=MinDistance)
{
isFollow=false;
}
//如果開始追蹤,則執行下面的代碼
if(isFollow)
{
//計算座標值
if(mPosition.x<mTargetPos.x) mPosition.x+=Speed*Time.deltaTime*Mathf.Abs(Mathf.Cos(getAngle()));
if(mPosition.x>mTargetPos.x) mPosition.x-=Speed*Time.deltaTime*Mathf.Abs(Mathf.Cos(getAngle()));
if(mPosition.y<mTargetPos.y) mPosition.y+=Speed*Time.deltaTime*Mathf.Abs(Mathf.Sin(getAngle()));
if(mPosition.y>mTargetPos.y) mPosition.y-=Speed*Time.deltaTime*Mathf.Abs(Mathf.Sin(getAngle()));
//改變追蹤物體的座標
transform.position=new Vector3(mPosition.x,mPosition.y,0);
}
}
private float getAngle()
{
float angle=0;
//獲取水平方向與豎直方向的變化量
float deltaX=mTargetPos.x-mPosition.x;
float deltaY=mTargetPos.y-mPosition.y;
//計算角度
if(deltaX>0 && deltaY>0)
angle= Mathf.Atan(deltaY/deltaX);
if(deltaX<0 && deltaY>0)
angle= Mathf.PI-Mathf.Atan(deltaY/deltaX);
if(deltaX<0 && deltaY<0)
angle= Mathf.PI+Mathf.Atan(deltaY/deltaX);
if(deltaX>0 && deltaY<0)
angle= 2*Mathf.PI-Mathf.Atan(deltaY/deltaX);
if(deltaX==0)
{
angle=Mathf.PI/2;
}
if(deltaY==0)
{
angle=0;
}
return angle;
}
}
在這段腳本中,我們定義了一個getAngle()方法,該方法用於獲取追蹤物體與目標物體連線與X軸正方向所成的夾角。這裏主要用到三角函數知識,大家可以再溫習下以前學過的知識,無論是程序設計還是遊戲開發,數學都應該是我們最應該掌握的東西。好了,通過角度計算,我們可以將速度分解到水平和垂直兩個方向,從而保證視線追蹤中的約束條件成立。如果我們將getAngle()方法從腳本中去除,則這就是最簡單的座標追蹤,希望大家自己去探討和研究啊,如果有時間的話,會將三種算法的代碼都展示出來的,希望大家繼續關注我的博客啊。呵呵。好了,接下來,我們來爲追蹤目標創建一個腳本,以便玩家可以控制追蹤目標躲避追蹤。腳本定義如下:
[csharp] view plaincopyprint?
using UnityEngine;
using System.Collections;
public class Control : MonoBehaviour {
//定義移動的速度
public float Speed=0.25F;
//定義當前位置
private float mX,mY;
void Start ()
{
mX=transform.position.x;
mY=transform.position.y;
}
void Update ()
{
if(Input.GetKey(KeyCode.A))
{
mX-=Speed*Time.deltaTime;
}
if(Input.GetKey(KeyCode.D))
{
mX+=Speed*Time.deltaTime;
}
if(Input.GetKey(KeyCode.W))
{
mY+=Speed*Time.deltaTime;
}
if(Input.GetKey(KeyCode.S))
{
mY-=Speed*Time.deltaTime;
}
transform.position=new Vector3(mX,mY,0);
}
}
好了,下面我們來測試一下程序運行的效果:
不知道爲什麼錄製的GIF動畫看不到追蹤物體,囧啊,不過可以負責任地對大家說,程序沒什麼問題,哈哈。
更多精彩請到http://www.gopedu.com/
好了,今天的內容就是這樣了,希望大家喜歡,如果大家希望繼續在《魂鬥羅》遊戲中尋找有趣的設計。