游戏中的AOI(Area of Interest)算法
游戏中的AOI(Area of Interest)算法
游戏的AOI算法应该算作游戏的基础核心了,许多逻辑都是因为AOI进出事件驱动的,许多网络同步数据也是因为AOI进出事件产生的。因此,良好的AOI算法和基于AOI算法的优化,是提高游戏性能的关键。
我在实践中所熟知的游戏AOI算法大致有两种,在此做一些总结,顺便梳理一下,打算设计出一套统一的接口封装不同的算法实现(网络上还有些其他算法,因为不熟悉不作记录了)。我所记录的这两种算法也算经典了,一个叫做网格法,一个叫做双链表法。
统一接口设计:
AOI需求大概是这样:
1.游戏地图上有一些npc和玩家在移动,每一个这样移动的对象我们叫做AOIEntity,每一个AOIEntity可以挂多个不同半径的AOI,每一个这种半径的AOI单元我们叫做AOINode,如此,AOIEntity拥有多个AOINode,然后每一个场景管理者AOIManager管理着多个这样的AOIEntity对象。
2.AOI进出事件由三种行为产生:进入场景,离开场景,在场景移动,因为这是AOIEntity相互之间的作用,故因放在AOIManager中统一管理,接口类似这样:
void AOIManager:Enter(AOIEntity *entity, cosnt Point& target_pos);
void AOIManager:Move(AOIEntity *entity, cosnt Point& target_pos);
void AOIManager:Leave(AOIEntity *entity);
3.添加一个AOINode的接口,主要参数是Id(用于标识这个AOI),半径,进出事件的callback函数:
void AOIEntity:AddNode(int aoi_id, float radius, AOICB enter_cb, AOICB leave_cb);
4.获取周围对象和观察者玩家对象集合的接口,这个可以在更上层,通过在响应进出事件的enter_cb, leave_cb中维护这样的集合。
网格算法:
既是把整个场景用网格划分成一个一个小区域(划分粒度可调整),每一个区域是当前场景该区域内的AOIEntity集合,当有一个AOIEntity移动时,根据对象移动之前坐标和目的地坐标,算出移动前所在网格SrcGrid和目的地网格DstGrid,根据一个可调的偏移参数,算出受这次移动影响的各个网格所在的一个网格区域(通常是一个包含这些网格的一个大网格),遍历每一个这样的网格里的每一个AOIEntity,与这个移动AOIEntity互相作比较,主要是比较这些事情:
1.是不是对方曾经在我的一个AOINode的半径内,移动后就不在了,是则产生离开回调;
2.是不是对方曾经不在我的一个AOINode的半径内,移动后就出现了,是则产生进入回调;
注意虽然移动是一个AOIEntity在移动,但是这种比较却要是互相的。
上面说的是网格算法的最简单实现了,当然实践上有许多地方可以优化和调整,包括使用更高效的数据结构,不细说。
双链表算法:
* 此算法名字是自己取的,因为算法基本上就是围绕两个双向链表在转--代表X轴的链表(叫做LinkListX)和代表Y轴的链表(叫做LinkLIstY)。对于每一个AOI单元,以AOIEntity的坐标位置为中心,可以构造出一个AOI矩形(以四元组[xleft,xright,ytop,ybottom]表示)。LinkListX链接的是所有这样的AOI矩形的xleft,xright,LinkListY链接的是所有这样的AOI矩形的ytop,ybottom,并且两者都是按照坐标值从小到大的顺序链接起来的。这样每一个AOI单元都在LinkListX,LinkListY上产生了总共4个节点,特殊的对于每一个可见的AOIEntity,以他们的坐标(XCenter,YCenter)在LinkListX,LinkListY上又产生了总共2个节点。现在当AOIEntity在场景中移动时,他所包含的在LinkList中的节点会相应的更改坐标值,而LinkList为了维护从小到大的顺序,会遍历链表,移动位置,直到重新有序。LinkList在这个过程,会产生AOI事件。
* 具体来说,当AOIEntity要移动到(targetX,targetY), 对应的AOI矩形变成[targetX-R, targetX+R, targetY-R, targetY+R],显然这四个节点值的改变后LinkList不再有序,现在来调整LinkList,可以这样来理解这个过程,对象先在X轴上移动到targetX,对应的是在LinkListX上移动,每次交换两个节点的位置都应该判断:1.两者的拥有者是不是不同的Entity;2.是不是一个是代表Entity的节点,一个是代表AOI矩形边界的节点;3.两者的拥有者整体上能否确实产生AOI进出事件。然后在Y轴上移动到targetY,过程与X轴对称。
* 可以总结一下,LinkList的节点的属性:
struct LinkNode {
byte _type; // 代表类型,主要是区分AOI矩形的边界和Entity本身
AOINode *_owner; // 属于哪个AOI单元,这里把代表Entity本身的节点也当作一个R=0的AOI单元
int _pos_val; // 坐标值,
struct LinkNode *_next, *prev;
}
网格算法原理和实现都简单,每次移动时遍历的受影响的单元是以网格为单位,并不是直接以Entity为单位,会产生许多次无效的遍历,对效率产生多少影响也是依赖网格的划分粒度和场景人数,不过总的来说对于不是海量的对象移动,加上一些上层逻辑相关的优化,一般的MMO已经是够用了。
双链表算法,巧妙的把一个AOI矩形拆成4个不同节点,每次移动遍历的受影响的单元直接是以Entity为单位,省去了许多无效遍历,但是在实现上要较网格算法复杂,另外其性能也是受场景中人数的影响。
游戏中的AOI(Area of Interest)算法的更多相关文章
- Unity3D 2D游戏中寻径算法的一些解决思路
需求 unity3d的3d开发环境中,原生自带了Navigation的组件,可以很便捷快速的实现寻路功能.但是在原生的2d中并没有相同的功能. 现在国内很多手机游戏都有自动寻路的功能,或者游戏中存在一 ...
- 如何在Cocos2D游戏中实现A*寻路算法(八)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 如何在Cocos2D游戏中实现A*寻路算法(六)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 如何在Cocos2D游戏中实现A*寻路算法(四)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 如何在Cocos2D游戏中实现A*寻路算法(一)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 《C++游戏开发》十六 游戏中的寻路算法(二):迷宫&A*算法基础
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/10289253 作者:七十一雾央 新浪微博:http: ...
- MMORPG服务器场景中的aoi算法思考
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/lwtbn1/article/details/37961695 最近在做一个移动平台上的MMORPG项 ...
- FPS中受伤UI在VR游戏中的实现思路
FPS中受伤UI在VR游戏中的实现思路 希望实现的效果 这几天一直在尝试各种解决方案,现在算是不完美的解决啦,记录一下心路历程,思路有了算法都比较简单. V_1 玩家胶囊体指向的方向作为正方向,计算出 ...
- 游戏中的人工智能——初探AI
一.游戏中的人工智能 让游戏具有挑战性: 让游戏好玩的关键因素是为之找到合适的难度等级: 人工智能在游戏中的作用是通过提供富有挑战性的竞争对象来让游戏更好玩,而在游戏中行动逼真的非玩家角色(NPC), ...
随机推荐
- mysql存储过程定义者
1. 执行update mysql.proc set DEFINER='root@%' WHERE NAME='p_update_rim_batch_log' AND db='otherdataonl ...
- GraduateDesign-给APP添加获取位置信息和天气预报的功能(json)
首先,我的app需要通过网络来获取当前所在的位置.这里我找到了一个json来获取本地位置信息. http://int.dpool.sina.com.cn/iplookup/iplookup.php?f ...
- 如何根据角色批量激活SAP Fiori服务
我们知道Fiori的角色跟ERP的角色是不通用的,即使你的账号有SAP_ALL的权限,但打开Fiori的时候一样是空的一片: 只有给账号加上fiori需要的角色,并激活相关服务才能用fiori app ...
- JAVA_基础反射机制
Java反射机制概述 Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法. 加 ...
- 使用Python实现的4种快速排序算法
快速排序算法,总体来说就是选一个基准值,把小于基准值的分一拨,把大于基准值的分到另一拨,然后递归. 有区别的是,分区算法有差异,最直接的是,选个基准值,定义两个列表(小值分区less和大值分区grea ...
- 在.NET Core中使用Channel(三)
到目前为止,我们一直在使用所谓的"Unbounded"通道.你会注意到,当我们创建通道时,我们这样做: var myChannel = Channel.CreateUnbounde ...
- 2021.Jan.11.Mon
人生中的机会不会有很多次,把每一次机会都当作最后一次机会,全力以赴地去做好,那么,你就不会永远在等待下一个机会. 看书心得---------By VincentAdamNemessis ...
- 常用 .gitignore 模板
前言 每次建项目的时候可以直接复制了,也算是方便自己,以后发现少的会更新 正文 作用 git提交时忽略文件 文件名 .gitignore Python # Byte-compiled / optimi ...
- 安装SVN和汉化包及基本使用
官网下载程序 和 下载汉化包. https://tortoisesvn.net/ 注意SVN汉化包版本需要和SVN版本一致,否则是无效的. 一.下载 1.进入官网,点击downloads 2.点击 ...
- Python作业---内置数据类型
实验2 内置数据类型 实验性质:验证性 一.实验目的 1.掌握内置函数.列表.切片.元组的基本操作: 2.掌握字典.集合和列表表达式的基本操作. 二.实验预备知识 1.掌握Python内置函数的基/本 ...