天天看點

不使用實體引擎實作防止群聚行為敵人紮堆

如果群聚行為的敵人沒有對群體内其他敵人的感覺能力,将造成一種很奇葩的現象:紮堆。我見過很多遊戲可以控制主角兜來兜去讓群聚敵人集中到一堆,或者你不動他們自己就會走成一條直線。

不使用實體引擎實作防止群聚行為敵人紮堆

這很煩人,玩家會認為敵人非常傻,如果玩家要采取躲避敵人的政策,挑戰性的要素隻剩下對走位的決策和移動速度的比拼。更惡心的是往往敵人比你挨着我我挨着你還要親密,甚至全部疊加集中到一個點上。

不使用實體引擎實作防止群聚行為敵人紮堆

喂,這太蠢了點吧。這是最raw最simple的實作方式,誰都能想出來。

不使用實體引擎實作防止群聚行為敵人紮堆

敵人始終單純的趨向主角(也許還會做出對主角移動預判的計算,但不在本文讨論範疇内),在主角從a點移動到b點的過程中敵人始終保持這樣的趨向性。

不使用實體引擎實作防止群聚行為敵人紮堆

用彩色曲線對例圖中敵人的移動軌迹做描繪,也許是這個樣子:

不使用實體引擎實作防止群聚行為敵人紮堆

看到了吧,敵人群體的範圍越來越小了。做為開發者兼玩家,這種prototype級别的做法會給我留下此遊戲完成度很低的印象。

實體引擎在現代遊戲中已經不是什麼稀奇物件了,不管3D遊戲還是2D遊戲,都能找到實體機制和遊戲表達結合的非常好的例子,某些遊戲走的更遠,對實體機制利用的更深入,實體就是這種遊戲的全部樂趣。如果你的遊戲中恰巧有一個可以随手拿來利用一下的實體引擎,也許你可以用它來防止敵人們過于親密,比如給每個敵人一個比渲染包圍體略大一些的防撞車碰撞體。

不使用實體引擎實作防止群聚行為敵人紮堆

這看起來就像敵人間互相有了斥力場,酷!大功告成,萬事大吉!

你得承認凡是做遊戲鬼點子多的人才不會滿足于把方案思考到能用就好的程度。我不是排斥使用實體引擎,相反我非常喜歡實體機制,我曾給我的首款App定制實作了一個實體引擎,效率良好,運轉穩定,最關鍵的是這個精簡版的實體引擎功能不多不少剛剛好滿足我的需求,​​ ​​完全沒必要用更加高大上的庫。對于防止群聚行為敵人紮堆這件事我不想用實體引擎也是因為:完全沒必要用啊。某些RTS不同兵種間有搭配性玩法,需要不同兵種的密度均衡,如果用實體引擎反而很難做。詢問了幾個同行,似乎不用實體引擎對這事都沒什麼轍,沒辦法,又得自己動手了。讓我們來看看如果不使用實體引擎自己處理敵人間的“推搡”是怎樣的情況。

不使用實體引擎實作防止群聚行為敵人紮堆

如果有兩隻敵人,隻需要做1次計算讓一隻跟另一隻保持适當距離就行了;如果有3隻敵人,需要做3次這樣的計算;如果有4隻,需要算6次;如果有5隻呢,要算10次……這種算法的複雜度是O(n(n-1)/2),可想而知敵人數量多了這将成為CPU的災難。經驗告訴我,複雜度中有高達形如“n乘以n”這樣的因子的算法都是要不得的,需要想辦法優化或做折衷。

思考優化方案從現實切入吧,我們每個人都有在方陣隊伍裡齊步走的經曆,左右腳步調的統一依靠“一二一”口号和踏步聲音做同步資料源;在方陣中相對位置的固定不變我們不需要也不可能通過擷取方陣中其他所有人的位置資訊做回報調整,事實上我們隻是瞄着視線範圍内與我們臨近的同學來做模糊判定的。先考慮某一隻敵人不管别的敵人同學自己單獨行動的行為:

不使用實體引擎實作防止群聚行為敵人紮堆

這很容易,隻需要朝着主角的位置奔去就行了,我們不妨把例圖中優先計算行動的敵人1當成走方陣時的排頭同學,他們隻需要走好自己的就行了。

取敵人1和主角位置連線(長度為R的)線段上某一點,(比如不妨定R為線段長度的一半),從主角位置到這一點(以R為半徑)做一個圓,好歹我們可以知道敵人群體的總數量有幾隻,把這個圓平均劃分為n份,每一隻都朝着相對應的劃分的端點襲去,嗯,也許還得給每隻敵人做些移動方向的微調;由于敵人1距主角越來越近,R是越來越小的,這個圓也會越來越向主角收縮,于是我們神奇的達成了敵人的這一套行為:

1. 群體移動趨勢一緻統一

2. 個體間在圓收縮到很小之前不會靠的非常近

不使用實體引擎實作防止群聚行為敵人紮堆

圓隻需要劃分一次,某一隻敵人隻需要知道自己是第幾号就可以計算出速度向量,看,複雜度一下降低到了O(n),單次計算中的向量計算也銳減。

再引申談一點點,群聚敵人分成若幹堆怎樣實作呢,不妨這樣來看,每一堆算做一個聚叢集體應用上文算法,再把某一群體看做一個整體,若幹個這樣的群體同理應用群聚算法(或其他行為模式)。

繼續閱讀