|
1. WayPoint尋路
下圖是一個典型的路點尋路
另一種方法是使用多邊形來記錄路徑信息,它可以提供更多的信息給ai角色使用。下圖就是一個navigation mesh。
以下列出幾個WayPoint的不足之處:
- 一些複雜的遊戲地圖需要的WayPoint數量過於龐大
- 有時會使角色走"Z"型路徑
如下圖A點和B點之間的路徑
NAV尋路如下圖
下圖是路點尋路,如黃線,會產生"Z"字形
下圖爲文章開始時展示的地圖的比較,紅線是wayPoint尋路,藍線是nav。
3. 不能進行動態修正,如果地圖中有動態障礙,處理起來會很困難
如要實現即時戰略遊戲中,一輛在路上行走的坦克會擋住你軍隊的去路,這個移動的坦克就是一個動態障礙。
4. 不能根據角色的特性(不同寬度、高度等)改變路徑
如一個狹窄的通道,普通的人能夠通過,而一輛馬車的寬度超過通道寬度,應該不能通過。
5. 不能保存地形的附加信息,如地表高度、地面特徵(水面、沙地等)
比如一個遊戲中的角色在走到沙地上時會降低移動速度,或走在一個斜坡上時人物會發生傾斜等。
2. NavMesh尋路:
nav尋路一般包含兩部分,首先是使用工具根據地圖信息生成尋路用的nav mesh,接下來就是在遊戲中根據生成的nav mesh來自動尋路。
一般人首先關心的就是尋路方法,所以這裏把順序顛倒下,先說尋路。
一. 使用A*尋找所經過網格路徑
下圖爲一個已經生成nav網格的地圖,深紅色區域爲不可行走區域,淺紅色區域爲可以行走的區域。
如下圖,現在如果要尋找從A點到B點的路徑,首先要從所有可行走的網格中找到一條最優的網格路徑(圖中紫色的網格),然後再根據這些網格生成所需要的路徑點。
計算最優網格路徑的方法可以使用流行的A*,也可以使用其它方法。A*算法網上很多就不說了,至於三角網格的A*實現因爲涉及網格的數據結構會在系列的最後給出。
二. 生成路徑點
nav尋路最常用的就是光照射線法 了,這個在neoragex2002的blog上有講,這裏就不說了
http://www.cnblogs.com/neoragex2002/archive/2007/09/09/887556.html
另一種方法就是拐角點法 ,如下圖
下圖的5個凸多邊形是已經生成的導航網格,多邊形外部的區域爲不可行走區域,current爲起點,goal爲終點,從圖中就可以看出最短路徑爲圖中紅線,藍色圈出的點爲我們需要找出的點。所有多邊形頂點均按逆時針方向存儲(這些均在生成導航網格時處理,以後會講到)。
(1)下圖顯示出各區域之間的入口,即多邊形的臨邊。由圖中可以看出每個臨邊均爲起點穿出該多邊形區域的邊,故以下稱該邊爲穿出邊。
(2)首先找到起始點所在的多邊形和穿出邊的兩個端點,由起點連接兩個端點,形成兩個線段lineLeft 和lineRight。如下圖。綠色圈表示左點,紅色表示右點(左點、右點是根據多邊形頂點保存順序而來)。
(3)繼續找到下一個穿出邊的兩個端點,判斷新的左點是否在lineLeft 和lineRigh之間,如果在,則更新lineLeft爲起點到新左點的線段。
同樣處理新穿出邊的右點,如下圖
該步最後得到兩個新的線段,如下圖。
(4) 繼續判斷下一個穿出邊的兩個端點,如下圖,新的左點在lineLeft和lineRight的外面,則不更新線段。
下圖說明新的右點在兩條直線之間,更新lineRight。
該步最後得到兩個新的線段,如下圖。
(5) 繼續循環判斷下一個穿出邊的兩個端點,該穿出邊的兩個端點都 在lineRight的右側,表示lineRight的終點 即爲路徑的一個拐角點 。
(6) 循環以上步驟都可以找到從起點到終點的一條完整路徑。
在繼續下面的nav網格生成算法之前,先介紹一下涉及到的計算幾何知識。這裏只羅列出結論,要詳細瞭解參考相關書籍。
- 矢量加減法:
設二維矢量P = ( x1, y1 ),Q = ( x2 , y2 ),則矢量加法定義爲: P + Q = ( x1 + x2 , y1 + y2 ),同樣的,矢量減法定義爲: P - Q = ( x1 - x2 , y1 - y2 )。顯然有性質 P + Q = Q + P,P - Q = - ( Q - P )。 - 矢量叉積
設矢量P = ( x1, y1 ),Q = ( x2, y2 ),則矢量叉積定義爲由(0,0)、p1、p2所組成的平行四邊形的帶符號的面積,即:P × Q 的標量大小 = x1*y2 - x2*y1,其結果是一個矢量。 - 折線段的拐向判斷:
折線段的拐向判斷方法可以直接由矢量叉積的性質推出。對於有公共端點的線段p0p1和p1p2,通過計算(p2 - p0) × (p1 - p0)的符號便可以確定折線段的拐向:
若(p2 - p0) × (p1 - p0) > 0,則p0p1在p1點拐向右側後得到p1p2。
若(p2 - p0) × (p1 - p0) < 0,則p0p1在p1點拐向左側後得到p1p2。
若(p2 - p0) × (p1 - p0) = 0,則p0、p1、p2三點共線。 - 判斷兩線段是否相交:
我們分兩步確定兩條線段是否相交:
(1)快速排斥試驗
設以線段 P1P2 爲對角線的矩形爲R, 設以線段 Q1Q2 爲對角線的矩形爲T,如果R和T不相交,顯然兩線段不會相交。
(2)跨立試驗
如果兩線段相交,則兩線段必然相互跨立對方。若P1P2跨立Q1Q2 ,則矢量 ( P1 - Q1 ) 和( P2 - Q1 )位於矢量( Q2 - Q1 ) 的兩側,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改寫成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。當 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 時,說明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共線,但是因爲已經通過快速排斥試驗,所以 P1 一定在線段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 說明 P2 一定在線段 Q1Q2上。所以判斷P1P2跨立Q1Q2的依據是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。同理判斷Q1Q2跨立P1P2的依據是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。
- 凸多邊形
假設我們在一個多邊形上(包括多邊形的邊界及邊界圍封的範圍)任意取兩點並以一條線段連結該兩點,如果線段上的每一點均在該多邊形上,那麼我們便說這個多邊形是凸的。 - 點在凸多邊形中的判斷
假設多邊形是凸的,而且頂點p0,p1,...,pn按順時針方向排列,則點在多邊形任意一邊 pi-1, pi 的右面。 - Delaunay三角剖分(Voronoi對偶圖)
在實際中運用的最多的三角剖分是Delaunay三角剖分,它是一種特殊的三角剖分。先從Delaunay邊說起:
【定義】Delaunay邊:假設E中的一條邊e(兩個端點爲a,b),e若滿足下列條件,則稱之爲Delaunay邊:存在一個圓經過a,b兩點,圓內(注意是圓內,圓上最多三點共圓)不含點集V中任何其他的點,這一特性又稱空圓特性。
【定義】Delaunay三角剖分:如果點集V的一個三角剖分T只包含Delaunay邊,那麼該三角剖分稱爲Delaunay三角剖分。
以下是Delaunay剖分所具備的優異特性:
1.最接近:以最近臨的三點形成三角形,且各線段(三角形的邊)皆不相交。
2.唯一性:不論從區域何處開始構建,最終都將得到一致的結果。
3.最優性:任意兩個相鄰三角形形成的凸四邊形的對角線如果可以互換的話,那麼兩個三角形六個內角中最小的角度不會變大。
4.最規則:如果將三角網中的每個三角形的最小角進行升序排列,則Delaunay三角網的排列得到的數值最大。
5.區域性:新增、刪除、移動某一個頂點時只會影響臨近的三角形。
6.具有凸多邊形的外殼:三角網最外層的邊界形成一個凸多邊形的外殼。
–主多邊形:被裁剪多邊形,記爲A
–裁剪多邊形:裁剪窗口,記爲B
多邊形頂點的排列順序(使多邊形區域位於有向邊的左側 )外環:逆時針 ;內環:順時針
主多邊形和裁剪多邊形把二維平面分成兩部分。
內裁剪:A∩B
外裁剪:A-B
裁剪結果區域的邊界由A的部分邊界和B的部分邊界兩部分構成,並且在交點處邊界發生交替,即由A的邊界轉至B的邊界,或由B的邊界轉至A的邊界。
如果主多邊形與裁剪多邊形有交點,則交點成對出現,它們被分爲如下兩類:
進點 :主多邊形邊界由此進入裁剪多邊形內 如,I1,I3, I5, I7, I9, I11
出點 :主多邊形邊界由此離開裁剪多邊形區域. 如, I0,I2, I4, I6, I8, I10
算法步驟
(1)建立空的裁剪結果多邊形的頂點表.
(2)選取任一沒有被跟蹤過的交點爲始點,將其輸出到結果多邊形頂點表中.
(3)如果該交點爲進點,跟蹤主多邊形邊邊界;否則跟蹤裁剪多邊形邊界.
(4) 跟蹤多邊形邊界,每遇到多邊形頂點,將其輸出到結果多邊形頂點表中,直至遇到新的交點.
(5)將該交點輸出到結果多邊形頂點表中,並通過連接該交點的雙向指針改變跟蹤方向(如果上一步跟蹤的是主多邊形邊界,現在改爲跟蹤裁剪多邊形邊界;如果上一步跟蹤裁剪多邊形邊界,現在改爲跟蹤主多邊形邊界).
(6)重複(4)、(5)直至回到起點