作者:Dave C. Pottinger
移動(Movement): 尋道(Pathfinding): 中繼點(Waypoint): 個體(Unit):
在進一步深入到我們的移動系統中之前,我將先簡介一下人們在解決移動問題上遇到的一些問題,這些問題是消耗最少的CPU時間的同時達到最佳的智能效果和最高的移動精度的關鍵。
不要忘記處理個體移動中的碰撞問題。一旦你的遊戲中的士兵們碰撞到了一起,你要怎樣將他們分開呢?一種方法是是個體之間根本不發生碰撞,但在實際的應用中這是不可能做到的。不僅僅是實現這要求的程序代碼非常難寫,而且無論你寫再多的代碼也是無用的,這些個體總是會找到一些途徑來使彼此重疊在一起,而在更多的情況中,這些個體的重合是必須的。一些使用近距離兵器進行戰鬥的遊戲,例如《帝國時代》,就是一個要求個體重合的實例。另外,如果你要限制你遊戲中的個體不能碰撞在一起,那麼他們很可能爲了避開彼此而離開預設的移動路線,暴露在其它對手的攻擊之下,受到意外的傷害,這會使玩家對你的遊戲極端不滿。因此你必須決定好你的那些個體相互靠的有多近,重合多少是可以容忍的,還要設法處理由這些決定所帶來的問題。
讓我們從一個簡單的對個體狀態進行處理的移動算法的僞碼(僞碼如下)開始,這個算法所作的只是簡單的使用一條給定路線前進,當遇到碰撞和衝突時重新尋道,因此它能在2D和3D遊戲中都表現得很出色。使用該算法,我們將從一個給定的狀態開始,持續循環直到找到一個可行的位置作爲中繼點作爲個體移動的目標去接近之後才跳出循環。移動狀態將會在整個UL中保存下來,這將使我們能夠正確的設置未來的狀態,例如"自動"添加中繼點。這種保存機制可以保證減少一個個體在下一次UL中作出與當前UL移動相反的判斷的可能性。
所有碰撞檢測系統的基本目標都是判斷兩個個體是否發生了碰撞。這次我們所介紹的碰撞檢測都是假設兩個物體的碰撞,將來我們會專門介紹大量物體互相碰撞的檢測問題。但無論是兩個物體還是多個物體發生碰撞有一點是共同的:每個物體都要收到碰撞信息以便作出適當的響應(分開彼此)。
對於一羣個體的簡單集合來說,可以接受的碰撞檢測下限是對整個組中的每個個體進行檢測。這種方法將允許那些不屬於你所選定的組的個體輕鬆的混入你的組隊中。相對來說,對編隊所要進行的碰撞檢測就要更加複雜一些了。我們還應該認識到這種簡單的組羣還有一種特殊的性質決定了我們應該儘可能的簡化對它所採用的碰撞檢測方法--這種組羣應該能夠隨時隨地的將排列方式變換成任何可能的適應當地空間大小的陣形。
大多數移動算法從根本上都是"離散"的,不同於數學上的離散定義,這裏所說的"離散"指移動算法在按照給定路徑從A點移動到B點的過程中從不考慮中間路徑上可能出現什麼東西,相反,在"連續"的算法中就會考慮這些情況。這樣做的一個問題就是當我們進行一個Internet遊戲時(衆所周知,由於網絡速度的限制,這類遊戲的UL時間一般較長)那些速度較高的個體很可能在一次UL時間中移動相當大的一段距離(由於UL時間變長),而當這樣增長的UL連續出現時很可能出現個體躍過了其它本應發生碰撞的個體。如果這樣的情況出現在一個工人的身上那並不會有人在意,但顯然任何玩家也不會希望敵人能夠從辛苦建設的城牆中穿越而過進而攻擊玩家的基地(某些早期及時戰略遊戲中出現的"穿牆"的BUG就是有這種問題造成的)。大部分的移動系統現在採用限制個體移動距離的方法來對付這一問題,該方法可以有效的簡化所需的處理。在離散型的移動算法中解決這類問題的方法如下圖所示:
一種有效地解決方法是將一次移動拆分成多次移動的集合。這種拆分需要滿足一定的移動距離上的要求,這要求就是要保證每次移動的距離剛好短於任何個體的長度,這就可以保證不可能有任何個體移動到當前個體的路徑上來,從而避免了從其它個體之上跨越過去的情況。當每次這種拆分後的移動結束時我們就要使用碰撞檢測系統對個體的當前位置進行碰撞檢測。你可能會想到如此頻繁的計算大量點的碰撞信息將會極大的增大系統消耗,沒關係,在後面的章節中我們將會介紹一種方法來降低這種計算對系統的消耗。
經過上週的工作,我們已經有了一個簡單的移動算法和一個管理個體碰撞的列表,還有什麼工作是強化個體之間協作所必需的呢?位置預測(Position prediction)。
顯然,最方便的優化方法是避免在每一幀中重複計算每一個已經預測過的個體位置。一個簡單的移動列表可以實現這樣的目的並且能夠工作得很好:你可以在每一幀中從表內刪除當前的位置,並向表內添加新的預測位置以維持列表長度固定(見圖5)。雖然這一方法並不會減少個體開始移動時創建整個列表的計算量,但可以保證在剩餘的移動過程中維持固定數量的計算。
下一種優化方法是設計一種能夠處理點和線的位置預測系統,由於我們的碰撞系統支持處理點和線,因次添加這一功能將是很容易的事。如果一個個體按照一條直線進行移動,那麼我們可以利用當前個體位置、預測位置和個體運動半徑來指定一段移動的軌跡及範圍。然而如果個體正在進行一次圓運動那麼整個處理就會略微複雜一些。當然你可以將這種運動過程作爲一個函數保存起來,但這顯然會加大系統的負擔。作爲替代可以嘗試通過對圓上的點進行取樣來作出正確的位置判斷(見圖6)。最後,再次建議一定要使用能夠實現對點和線的無縫交替處理的預測系統,以便在任何可能的情況下通過使用直線來減少對CPU的耗用。
最後所要介紹的一種優化方法非常重要,但同時也可能有一些不夠直觀,不能簡單的看出其優化作用。如果我們要使用這樣的預測系統,爲了儘可能少的消耗資源,顯然不應該在計算了一次預測未知之後再進行一次計算來移動個體。因此解決的方法是精確地進行位置預測,並最終使用該位置移動個體。這樣我們就能對每個個體的移動只計算一次並且除了前述的開始移動時的計算之外沒有其他多餘的計算開銷。
我們已經建立了一個複雜的系統來確定個體未來的可能位置,它支持3D移動,同時對計算量的提升也並不比一個簡單的方法多多少,重要的是該方法提供給我們一個記錄了一個個體在未來一小段時間內移動所需的一切信息的列表,這正是我們所需要的。現在我們可以進入較爲有趣的部分了。 CASE 1:if 個體已經全部停止移動: CASE 2:if 個體沒有移動,是另一個個體將要移動,什麼也不做 CASE 3:if 當前個體正要移動,其它個體已經停止
2.Else,if 可以避開另一個個體,避開他以解決碰撞 3.Else,if 是高優先級個體並且能夠沿移動路線推動低優先級個體,推動它,改變狀態爲正在處理的碰撞 4.Else,if 停下,重新尋道 CASE 4:if 當前個體正在移動,另一個個體也在移動: 2.if 碰撞不可避免,並且當前個體是高優先級,通知另一個體停止移動,轉狀態爲CASE 3.1 3.Else,if 當前個體是高優先級的,計算出下步移動位置,通知另一個體減速到足以避免碰撞。 正在處理的碰撞: 1.if 是一個移動的個體要處理CASE 1的碰撞,並已經移動到了目的地,碰撞解決 2.if 是CASE 3.1中低優先級個體,並且高優先級個體已經抵達預定位置,開始返回原位置,碰撞解決 3.if 是CASE 3.1中高優先級個體,等待(減速或停止)直到低優先級個體從通路上離開,之後繼續移動 4.if 是CASE 3.3中高優先級個體並且現在低優先級個體已可以從通路中離開,轉狀態爲CASE 3.1 5.if 是CASE 4.3中低優先級個體並且高優先級個體已經抵達預計地點,恢復移動速度,碰撞解決
計劃編制是個體協作的關鍵,雖然我們儘可能地提升預測和計算的精確性,但是顯然事情總是會出錯的。例如我們在《帝國時代》中所犯的一個錯誤是我們總是在一幀的時間內使個體作出移動的決定,雖然這樣的決定多數是正確的,但我們並沒有在以後的UL中參考它。這樣就造成了一個問題:個體對移動路線作出了決定,實行時發現出現問題必須重新決斷,結果是使個體再次返回它的出發點。計劃編制可以有效地避免這類問題。我們保存一定數量的個體以前移動中所遇到的障礙和碰撞的解決步驟(由其它的遊戲細節定義),這就爲我們未來遇到困境時提供了參考。舉例來說,當我們要避免一次碰撞時我們將存儲哪一個個體是我們所要閃避的。由於我們要設定一個可行的計劃,沒有任何理由對碰撞中的另一個體進行碰撞檢測,除非其中的某一個個體得到了新的命令或發生其它類似的變化。一旦我們完成了閃避,就可以爲其它的個體恢復正常的碰撞檢測了。在下面的擴展中,你將看到我們將反覆利用這一思想來達到我們的目的。
遊戲編程的樂趣之一就是要不停地創新來開發新技術以使設計人員能作出更優秀的遊戲。在即時戰略遊戲中,越來越多的開發人員希望能夠在他們下一批作品中加入對編隊的處理能力。在這裏我不會介紹現在那些低技術含量的移動方法,我所要討論的是如何協調編隊的移動,使每一個個體都能在智能的維持編隊隊形的同時在地圖上隨意的移動。 組隊(Group)移動 首先要弄清楚何謂組隊(Group):由用戶(玩家)爲方便操作而選取的簡單的個體集合(一般會對其成員發佈相同的命令),除了在移動時要保持成員一同移動之外組隊並沒有其他對移動系統的限制。組隊的使用使我們必須記錄許多信息,例如組隊成員的列表以及當整個組隊還在一起時所能移動的最大速度。也許我們還應該保存整個組隊的中心,以作爲一個可以很容易得到的操作參考點。同時還應該選定一個組隊的指揮者,大多數遊戲中怎樣選出這個個體並不重要,重要的是一定要有一個這樣的個體。 在我們開始工作之前有一個問題需要回答:當組隊在地圖上移動時我們有必要保持所有個體在一起嗎?如果不,組隊將只是爲使用戶方便操作而存在的,每一個個體都會獨自尋道和移動就如同用戶對每個個體分別下達指示一樣。當我們關注如何加強組隊的管理時,我們可以發現組隊的凝聚力可以分爲多個等級。 組隊中的個體都以相同的速度移動。一般地這將使用組隊中速度最低的個體的最大速度,不過有時讓那些速度較慢的個體在組對中移動的稍快一些會更好(見圖8)。然而一般遊戲的設計人員給一類個體較低的速度總是有原因的,例如如果允許強力的個體能夠非常高速的在地圖上移動將會極大的破壞遊戲的平衡性。
組隊中的個體都以相同的速度移動並使用同一條路徑。這種方法可以有效的避免當組隊中一半的個體從森林一側前往目的地時另一半卻從另一側移動(見圖9),稍後你將看到實現這一方法的一條簡單途徑。
組隊中的個體以相同的速度移動,使用同一條路徑並同時抵達。這是最複雜的組隊組織方式,它不但要求達到上述兩點,並且還要求位於前面的個體能夠等待落在後面的個體追上來,有時還要給後面的慢速個體短時間加速以使其能夠追上前面的個體。 怎樣才能實現最後的要求?這要使用一種分級的移動系統,這樣我們就能在處理每個個體的移動時兼顧那些同屬於某個組隊的個體了。如果我們對組隊的個體創建一個組隊對象,我們就能夠記錄所有必需的數據,爲整個組隊計算最大速度,以及判斷何時需要前面的個體等待後面的個體。下面就是一個組隊類的簡單定義:
BGroup類在其內部管理整個組隊中個體之間的交互操作。在任何時間點,它都應該有一個時間表以來處理組隊內的個體之間的碰撞,它也應該有能力通過參數和優先級管理來控制或修正個體移動。如果你的遊戲只支持一種移動優先級,那麼你就應該爲你在組隊中的個體們添加第二種優先級。雖然一個組隊對外的表現似乎只有一種優先級,但在其內部還是應該分爲不同的移動優先級。基本上來說,BGroup類是另一個完善的封閉的移動系統。 組隊的指揮者將負責整個組隊的尋道工作,它將決定整個組隊的移動路線,在簡單的組隊移動系統中所需的工作只是由這個個體本身來尋道即可。然而在下面的部分中我們將看到指揮者所能夠作的其它事情。 編隊控制基礎 首先應該給出編隊的定義:編隊(Fomation)是一種更復雜的組隊,編隊有自己的方向(前方、後方、左翼和右翼)。編隊中的每一個個體都試圖保持自己在編隊中的位置,而這個位置是唯一固定的也是相互關聯的。更加複雜的模型使得編隊中各個個體的朝向需要單獨處理,而同時也要求在移動中提供整體旋轉的方法。 編隊是建立在組隊系統之上的,它是一種限制更加嚴格的組隊,因爲我們必須非常詳盡的規定編隊中每個個體的位置。所有的個體在移動中必須保持一起行動,並要求在速度、路徑上一致以及相互之間的位置和距離保持不變--如果在移動中編隊出現了大間距的縫隙,那麼它也就與組隊沒有什麼不同了。 下面給出的這個BFomation類能夠清晰的管理一個編隊的預定位置(我們要求編隊中的每個個體所處的位置以及它的方向)、編隊方向和編隊的狀態。大多數遊戲中所使用的編隊都是預先定義的,顯然,在開發過程中進行這項工作是很簡單的(通過使用一些非專業人員也能熟練操作的文本編輯器就可以很好的完成這項工作)。我們當然希望能在遊戲過程中實時的定義編隊,但這樣做就需要更多的內存以保證每一個由玩家定義的編隊都能在內存中保留一份自身定義的副本。 Listing 3. The BFormation Class
使用這個模型,我們必須時刻關注編隊的狀態。cStateBroken表示編隊並沒有被創建也沒有創建的企圖;cStateForming表明我們的編隊正在建立但還沒有達到cStateFormed狀態;一旦所有的個體都已位於它們的預定位置,我們就可以將狀態改變爲cStateFormed。爲了使編隊的移動簡單化,我們可以使一個編隊在完成組建之前(達到cStateFormed狀態之前)不可移動。 當我們準備使用一個編隊時,第一件工作就是組建這個編隊。當給定一個編隊時,BFormation(譯者注:原文這裏是BGroup,但該類並沒有編隊管理功能,經過反覆推敲認定爲編寫錯誤)控制每個個體移動到編隊中的預定位置,該位置的計算是與當前編隊方向相關的,如果這個方向發生了變化,那麼預定位置將自動被重新計算並修正爲正確的位置。 爲了組建一個編隊,我們可以使用預定安置--每一個預定位置擁有一個預設值(由定義規定或由算法確定)來指明個體組建編隊時應該按照那種順序進駐那些預定位置,這樣才能使整個組建過程從裏到外進行得相當有條理(見圖10)。下面的算法列表說明如何實現這樣的組建方式。 Listing 4. 設置組隊中的所有個體移動優先級到一個相同的低優先級 選定一個個體前往所找出的位置,要求滿足如下條件: 設置個體的移動優先級到中等值
現在我們所有的戰士都已經就位了,接下來做什麼呢?我們可以開始移動他們以穿過整個地圖,我們可以假定尋道系統找出了一條以當前編隊的形狀和大小可以通過的路徑來抵達目的地(見圖11),如果沒有這樣一條路經那就必須對整個編隊進行操作(不久我們就會探討這個問題)。當編隊在地圖上移動時我們需要選出一個指揮者來控制整個移動,當指揮者沿路徑前進並改變方向時其它所有編隊中的個體都要改變方向以追隨它,這種操作一般被稱爲flocking(聚集)。
我們有兩種方法處理編隊的方向改變:忽略這種改變或者轉動編隊的方向。忽視方向的改變是簡單的而且對於那些盒狀的編隊來說是非常合理的(見圖12)。
對編隊進行旋轉並不會增加多少複雜性而同時對於某些編隊方式(如直線形)來說是非常合理的。進行編隊旋轉時首先要做的是停止編隊移動,完成方向的旋轉之後我們要重新計算每個預定位置,然後回到cStateForming狀態(見圖13),使個體前往新的位置並在完成這一工作之後設置狀態爲cStateFormed,這樣我們就可以繼續原來的移動。
高級編隊管理技術 縮放個體間距(Scaling unit positions).由於編隊中的預定位置都是由矢量進行定義的,因此我們可以很方便的對整個編隊的間距進行放縮以使它變得更小,這就使得編隊能夠通過城牆或樹林中更小的縫隙(見圖14)。這種方法對於那些排列得較爲分散的編隊很有效,但對於那些排列緊湊的編隊就沒有什麼用處了。
簡單的障礙迴避(Simple ordered obstacle avoidance).如果我們在移動編隊時遇到與其它遊戲中實體相碰撞的情況時(無論是當前還是未來碰撞),我們可以假設即使有這樣的碰撞發生,原來尋到的道路仍是可用的。簡單的解決方法是沿着編隊前進的路線找出第一個不再發生碰撞的位置,並在該位置完成編隊的重組(見圖15)。這樣我們的步兵團就可以先分散,帶穿越障礙物之後再在另一側重新組建編隊。在使用這一方法時一定要注意有時障礙物的範圍非常大,以至於編隊的重組工作必須在走出很遠之後才能做,這時就得考慮是否應該重新尋道了。
二分和重組(Halving and rejoining).雖然簡單的迴避能夠工作的很好,但是會降低玩家對整個編隊穿越地圖的感覺,相對來說二分法可以很好的保持住編隊所帶來的視覺衝擊。當我們的編隊在前方遇到一個障礙物時我們可以找出編隊中的一個拆分點,從該點將編隊一分爲二,這兩個編隊分別通過障礙物之後再前進到重組位置恢復成一個編隊(見圖16)。這種方法只增加很少的計算量,但卻能爲編隊移動帶來良好的視覺效果。
路徑棧 路徑棧就是一種簡單的用來記錄個體移動路由信息的棧操作(後進先出,見圖17)。一個路徑棧記錄的信息一般包括個體當前所採用的路線,現在個體正在向哪個中繼點移動以及個體是否正處於巡邏中。一個路徑棧對我們的目的有兩大作用。
首先,它可以爲一次分級尋道工作提供便利。一般來說遊戲開發者會把尋道區分爲兩種明顯不同的等級--高級(high-level)和低級(low-level)(見圖18)。高級的尋道可以爲個體找尋出穿越地圖上不同地形和主要堵塞地點的道路,這就如同玩家大多數時候給個體制定的路徑一樣。低級的尋道則同時還會處理較小的障礙物並更注重處理細節。一個路徑棧可以方便的存儲高級和低級的尋道信息。我們可以先通過高級尋道找出一條路徑並把它存儲進路徑棧中,而當我們必須注意避免與大片空地中的一顆樹發生碰撞時就可以將低級尋道的一系列結果存入路徑棧頂並執行它們。每當執行完一條路徑,我們就可以將它從棧中彈出並繼續執行現在位於棧頂的路徑。
第二點,路徑棧可以允許高級尋道被重用(reuse)。如果你回顧前面的介紹將看到組隊和編隊在移動時的一大要素就是所有的成員都使用相同的路徑來移動到目的地。如果我們設計的路徑棧可以允許多個個體參考一條路徑,那就將使同一條高級尋道路徑很容易的被重用。一個編隊的指揮者將使用高級尋道找出一條路徑並把它拷貝給編隊中的每個個體,而其它個體則什麼也不用做。 這樣創建保存路徑信息的結構還能提供給我們一些其它好處。通過將一條高級尋道路徑拆分成多個低級尋道路徑,我們可以在執行具體路徑之前充分的對這些低級路徑進行更精確的計算。而且如果我們確定高級尋道的結果是可用的話,也可以將低級尋道的工作略微推後再做。如果我們正在進行高協調度的個體移動,路徑棧將允許我們向棧頂添加一條臨時的用來避免碰撞的路徑,並能夠很好的使用這一路徑修正個體移動(見圖19)。
解決混合碰撞 我們定義混合碰撞爲同時發生在兩個以上個體之間的碰撞。大多數遊戲都對於可以解決的混合碰撞中的個體個數有限制,超過這個數目就只能分幾次解決了。下面我們將探討如何使用已有的移動系統對這類情況進行簡單的處理。 如果我們遇到了一個由三個個體造成的混合碰撞(見圖20),首要的工作是找出其中優先權最高的個體。一旦找到它,我們就要立即找到與之碰撞的另一個個體並確定優先權最高的個體所遇到的最主要的碰撞(該碰撞可能發生在其與次優先的個體之間,也可能不是)。當我們找到了這兩個個體後,剩下的工作就交給原來的碰撞處理部分解決即可了。
當最初的兩個個體的碰撞被解決後,我們就要重新評估整個碰撞並更新個體之間的關係。一個更復雜的系統可以很好的解決這樣的問題,但是如果簡單的移走已經解決了碰撞問題的個體也能得到不錯的效果。 一旦我們更新了碰撞中的個體,下一步工作就又回到尋找優先權最高的個體的碰撞上來了。我們將一直重複這一步驟直到所有的碰撞都被解決。 你可以在兩個地方使用這一系統:碰撞解決部分或碰撞預測系統中。碰撞解決的規則必須被修改以適應對於個體優先級的要求,這樣的修改並不難,但會增加一定的代碼量。或者你可以修改你的碰撞預測系統使得只會發生兩個個體碰撞的情況,然而這樣做你仍然需要先找出一次碰撞中的全部個體並作出操作。 解決堆疊峽谷問題(The Stacked Canyon Problem) 所有移動系統的最終目的都是要實現智能的移動效果,而所有處理中最能體現智能的就是處理堆疊峽谷問題了(什麼是堆疊峽谷問題呢?事實上當一個個體要從一羣排列緊湊的個體之間穿過時所需要解決的問題就是堆疊峽谷問題,圖21就是一個例子)。雖然此類問題並不能簡單的一次解決,但我們可以重用前面的一些簡單方法來解決它。
第一步是鑑定是否爲一個堆疊峽谷問題。這是非常重要的,因爲我們將要利用前進個體(driving unit)的優先級。當然我們可以利用每個個體自身的優先級來要求其它個體讓出道路,但是更好的解決方法是使用前進個體的優先級。判斷一個堆疊峽谷問題可以有兩種方法:觀察前進個體是否會把一個阻礙其移動的個體推到另一個身上或者觀察移動個體的碰撞列表以尋找多重的碰撞。不論採用哪種方法,被推動的個體都應該擁有與前進個體相同的移動優先級。 一旦我們判斷出將要解決一個堆疊峽谷問題,就可以採用一種簡單的遞歸調用個體協調運動系統的方法來解決它。把第一個被推動的個體作爲前進個體處理其於第二個個體之間的關係,並如此循環。每一個個體被它的前進個體推動直到它可以移動到一邊而讓出道路。當最後一個個體也從陸上讓開後,原來的前進個體就可以繼續移動了。 一個好的習慣是將已經移開的個體在移回原位。爲了能夠這樣做,我們應該記錄整個推動過程並在問題解決後倒序的執行該過程。另外如果負責移動的代碼能夠辨別出前進個體是否歸屬於一個組隊,那就能保證組隊中每個個體都能在原來阻礙道路的個體返回原位置之前通過。 注意 優化你的整體系統。如果你只是要做一個2D遊戲,那就會有許多多餘的計算是可以取消和簡單化的。不論你是要做2D遊戲還是3D的,你的碰撞檢測系統都需要一個優秀的經過優化的個體分揀系統,這類系統已經不再僅僅用於繪圖了。 對高級尋道和低級尋道使用不同的方法。過去大多數遊戲對這兩種尋道方式使用相同的算法。這樣做的害處是如果對高級尋道使用低級尋道的算法將使高級尋道變得緩慢並且不能用於尋找長的通路;相反的,如果對低級尋道使用高級尋道的算法將會造成結果並沒有將道路上的所有障礙物考慮在內或者造成一個個體能從其它個體之中穿過。一定要抓住要點製作兩套尋道系統。 無論你做什麼,個體總會交疊碰撞在一起。個體的交疊和碰撞是不可避免的,或者按最好情況說將是非常難以操作的。你最好儘早處理這些碰撞問題,這將使你的遊戲更好一些。遊戲的地圖已經越來越複雜了,並且還會加入隨機地圖的處理。一個好的移動系統將能夠很好的處理隨機地圖和相應的一切細節。 清楚地瞭解UL是怎樣影響個體移動的。可變化的UL時間將是你的移動系統所必須解決的一大難題。可以使用一個簡單的修正機制來解決此類大部分的問題。 只涉及單個UL的做法是過時的。沒有計劃的編制不可能解決好個體移動的協調問題,如果不記錄上一次UL中的操作和將來要發生的問題又是不可能製作好的計劃的。一個能夠運作良好的移動協調系統必須在任何時候都能夠參考以前的碰撞列表和預測碰撞的列表。切記解決碰撞的過程中出現的較小的變化是可以忽略的。
簡單的個體移動是簡單的。一套優秀的協調系統是我們所應該追求的,因爲它能使你的遊戲步上一個等級並能增加玩家的樂趣。在本次的文章中我們研究了一個移動協調系統的基礎功能--使用多個UL時間制定行動計劃以及一套可以解決任何兩個個體碰撞的方法等等。現在你應該不會再滿足於你的遊戲中那些傻乎乎的個體移動了。 |