转自:http://www.gameres.com/thread_256279_1_1.htmlhtml
GameRes发布,文/paladin_t,转载请注明GameRes和做者
追击、群聚是极经常使用到的敌人行为模式。靠拢玩家位置的移动叫追击;群聚指一批敌人集体采用统一的行动,就像一群群沙丁鱼同样。群聚敌人每每配合追击来对玩家施加压力,所以本文隐含用追击配合作群聚示例。
若是群聚行为的敌人没有对群体内其余敌人的感知能力,将形成一种很奇葩的现象:扎堆。我见过不少游戏能够控制主角兜来兜去让群聚敌人集中到一堆,或者你不动他们本身就会走成一条直线。
<ignore_js_op>
这很烦人,玩家会认为敌人很是傻,若是玩家要采起躲避敌人的策略,挑战性的要素只剩下对走位的决策和移动速度的比拼。更恶心的是每每敌人比你挨着我我挨着你还要亲密,甚至所有叠加集中到一个点上。
<ignore_js_op>
喂,这太蠢了点吧。这是最raw最simple的实现方式,谁都能想出来。
<ignore_js_op>
敌人始终单纯的趋向主角(也许还会作出对主角移动预判的计算,但不在本文讨论范畴内),在主角从a点移动到b点的过程当中敌人始终保持这样的趋向性。
<ignore_js_op>
用彩色曲线对例图中敌人的移动轨迹作描绘,也许是这个样子:
<ignore_js_op>
<ignore_js_op>
看到了吧,敌人群体的范围愈来愈小了。作为开发者兼玩家,这种prototype级别的作法会给我留下此游戏完成度很低的印象。
物理引擎在现代游戏中已经不是什么稀奇物件了,无论3D游戏仍是2D游戏,都能找到物理机制和游戏表达结合的很是好的例子,某些游戏走的更远,对物理机制利用的更深刻,物理就是这种游戏的所有乐趣。若是你的游戏中恰巧有一个能够随手拿来利用一下的物理引擎,也许你能够用它来防止敌人们过于亲密,好比给每一个敌人一个比渲染包围体略大一些的防撞车碰撞体。
<ignore_js_op>
这看起来就像敌人间互相有了斥力场,酷!大功告成,万事大吉!
你得认可凡是作游戏鬼点子多的人才不会知足于把方案思考到能用就好的程度。我不是排斥使用物理引擎,相反我很是喜欢物理机制,我曾给个人首款App定制实现了一个物理引擎,效率良好,运转稳定,最关键的是这个精简版的物理引擎功能很少很多刚恰好知足个人需求,彻底不必用更加高大上的库。对于防止群聚行为敌人扎堆这件事我不想用物理引擎也是由于:彻底不必用啊。某些RTS不一样兵种间有搭配性玩法,须要不一样兵种的密度均衡,若是用物理引擎反而很难作。询问了几个同行,彷佛不用物理引擎对这事都没什么辙,没办法,又得本身动手了。让咱们来看看若是不使用物理引擎本身处理敌人间的“推搡”是怎样的状况。
<ignore_js_op>
若是有两只敌人,只须要作1次计算让一只跟另外一只保持适当距离就好了;若是有3只敌人,须要作3次这样的计算;若是有4只,须要算6次;若是有5只呢,要算10次……这种算法的复杂度是O(n(n-1)/2),可想而知敌人数量多了这将成为CPU的灾难。经验告诉我,复杂度中有高达形如“n乘以n”这样的因子的算法都是要不得的,须要想办法优化或作折衷。
思考优化方案从现实切入吧,咱们每一个人都有在方阵队伍里齐步走的经历,左右脚步调的统一依靠“一二一”口号和踏步声音作同步数据源;在方阵中相对位置的固定不变咱们不须要也不可能经过获取方阵中其余全部人的位置信息作反馈调整,事实上咱们只是瞄着视线范围内与咱们临近的同窗来作模糊断定的。先考虑某一只敌人无论别的敌人同窗本身单独行动的行为:
<ignore_js_op>
这很容易,只须要朝着主角的位置奔去就好了,咱们不妨把例图中优先计算行动的敌人1当成走方阵时的排头同窗,他们只须要走好本身的就好了。
取敌人1和主角位置连线(长度为R的)线段上某一点,(好比不妨定R为线段长度的一半),从主角位置到这一点(以R为半径)作一个圆,好歹咱们能够知道敌人群体的总数量有几只,把这个圆平均划分为n份,每一只都朝着相对应的划分的端点袭去,嗯,也许还得给每只敌人作些移动方向的微调;因为敌人1距主角愈来愈近,R是愈来愈小的,这个圆也会愈来愈向主角收缩,因而咱们神奇的达成了敌人的这一套行为:
1. 群体移动趋势一致统一
2. 个体间在圆收缩到很小以前不会靠的很是近
<ignore_js_op>
圆只须要划分一次,某一只敌人只须要知道本身是第几号就能够计算出速度向量,看,复杂度一降低低到了O(n),单次计算中的向量计算也锐减。
再引伸谈一点点,群聚敌人分红若干堆怎样实现呢,不妨这样来看,每一堆算作一个汇集群体应用上文算法,再把某一群体看作一个总体,若干个这样的群体同理应用群聚算法(或其余行为模式)。
<ignore_js_op>
本文算法代码可在github获取。
文/paladin_t,做者微博git