经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
游戏AI之感知(1)
来源:cnblogs  作者:KillerAery  时间:2018/12/3 9:48:47  对本文有异议

感知

视觉感知

视觉感知是一种常见的感知。

在许多即时战略游戏或者类DOTA游戏里,一个单位的视觉感知往往是圆形范围的。

当然在其他大部分俯视角游戏里,一个智能体的视觉感知应该是类似现实人眼观看的扇形范围

对于横板游戏,可以把视野“竖”起来,检测方式无多少差别。

对于空间更加复杂的3D游戏,可能需要视锥体形状(6个平面)检测而不是扇形或者圆锥形。
潜在的优化是照样做成扇形检测,只是再额外增加高度差检测(即看作2.5D处理)。

但是视野实际还需考虑阻挡问题。
这里提供两种解决视野遮挡的思路:

  1. 在前方扇形范围发出若干条射线进行检测,若检测到某个射线第一个碰到的物体是目标物体,则感知到该目标。

  1. 在所在区域的所有潜在目标进行遍历,每次遍历 先判断是否在扇形范围内,
    再做一条智能体到目标的射线,若射线碰到的第一个物体是该目标,
    则感知到该目标。

第一个思路比较容易实现,第二个则算法效率比较高。

第二个思路要是预先“规划”好区域,尽可能过滤不必要的目标,缩小所在区域的潜在目标数量
(例如屋外看不到房内的人,也就可以过滤掉房内的人),那么检测速度就非常快。

听力感知

听力感知一般比较简单粗暴:一个圆形/球形范围检测,
而且一般还无需考虑阻挡问题(现实中的声音传播可近似看作无阻挡)。

另外的,听力感知一般需要得到的信息:

  • 声音来源(例如发出声音的生物)
  • 声音大小和距离

通过简单的线性计算,由声音大小和距离可以计算出实际接受声音的大小。
将这个信息作为额外数据交由决策使用。
(例如一个警卫,听到太大的声音就进入敌对状态,小的声音则进入警戒状态)

其它感知

这个其实应该叫杂项感知或者根据需求随便取名的感知。
一般来说,视觉感知和听力感知已经足够一个基本的智能体所需感知了。

但极少情况还可能一些智能体需要知道各种杂项信息
(例如队长给警卫发送了一条无线电消息,要求警卫赶往队长所在位置支援)

实现

感知可以做成一种类,提供 检测函数 和 结果访问接口。

下面提供一种大致的示例(C++):

  1. //视野感知
  2. class ViewPerception {
  3. public:
  4. //进行一次视野感知探测:
  5. void check(Vector3 position) {
  6. //先清理结果
  7. perceptionResult.clear();
  8. //逐个潜在目标检测
  9. for (Biology* target : targets) {
  10. //运用简单的数学运算判断点是否在扇形范围:
  11. //先进行距离判断是否在半径内。
  12. //look向量和射线单位向量的向量积 若小于 向量积限制,
  13. //则证明该射线离look向量的角度 超出向量积限制的对应角度。
  14. Vector3 offset = target.getPosition() - position;
  15. float distanceSq = offset.lengthSquare();
  16. if (distanceSq < radiusSq)continue;
  17. float crossproduct = offset.normalize().dot(look);
  18. if (crossproduct < dotproductlimit)continue;
  19. perceptionResult.emplace_back(target);
  20. }
  21. }
  22. //访问感知目标结果
  23. const std::list<Biology*>& getResult()const {
  24. return perceptionResult;
  25. }
  26. private:
  27. float radiusSq; //扇形半径的平方
  28. Vector3 look; //朝前的单位向量
  29. float dotproductlimit; //向量积限制
  30. std::list<Biology*> perceptionResult; //使用链表存储感知到的目标
  31. };
  1. //听力感知
  2. class ListenPerception {
  3. public:
  4. //进行一次听力感知探测:
  5. void check(Vector3 position) {
  6. perceptionResult.clear();
  7. //逐个潜在声源检测
  8. for (Voice& voice : voices) {
  9. //判断目标点是否在圆形范围,即距离是否在半径内。
  10. Vector3 offset = voice.getPosition() - position;
  11. float distanceSq = offset.lengthSquare();
  12. if (distanceSq < radiusSq)continue;
  13. perceptionResult.emplace_back(voice.getBiology(),voice.getVolume()/distanceSq);
  14. }
  15. }
  16. //访问感知目标结果
  17. const std::list<std::pair<Biology*, float>>& getResult()const {
  18. return perceptionResult;
  19. }
  20. private:
  21. float radiusSq; //范围半径
  22. std::list<std::pair<Biology*,float>> perceptionResult; //使用链表存储感知到的目标+实际声音大小
  23. };

TIP:
判断点在圆形范围应->比较距离的平方和半径的平方,每次判断就可以减少一次开方的运算。

下一篇博文将介绍黑板。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号