十字链表的AOI算法实现
[game] 十字链表的AOI算法实现
转载:https://www.cnblogs.com/rond/p/6114919.html
AOI主要有九宫格、灯塔和十字链表的算法实现。本文阐述十字链表的实现和尝试。
基本原理
根据二维地图,将其分成x轴和y轴两个链表。如果是三维地图,则还需要维护多一个z轴的链表。将对象的坐标值按照大小相应的排列在相应的坐标轴上面。基本接口
对对象的操作主要有以下三个接口:
add:对象进入地图;
leave:对象离开地图;
move:对象在地图内移动。
2. 算法实现
既然是链表,很自然地想到用线性表来实现。因为存在向前和向后找的情况,所以使用双链表实现。其实实现也是非常简单,就是两个双链表(这里以二维地图举例)。那么我们的节点需要四个指针,分布为x轴的前后指针,y轴的前后指针。
// 双链表(对象)
class DoubleNode
{
public:DoubleNode(string key, int x, int y){this->key = key;this->x = x;this->y = y;xPrev = xNext = NULL;};DoubleNode * xPrev;DoubleNode * xNext;DoubleNode * yPrev;DoubleNode * yNext;string key; // 只是一个关键字int x; // 位置(x坐标)int y; // 位置(y坐标)private:};
下面是地图场景信息和接口。这里的实现比较粗略,是带头尾的的双链表,暂时不考虑空间占用的问题。类Scene有分别有一个头尾指针,初始化的时候会为其赋值,主要用DoubleNode类的指针来存储x轴和y轴的头尾。初始化的时候,将_head的next指针指向尾_tail;将_tail的prev指针指向_head。
// 地图/场景
class Scene
{
public:Scene(){this->_head = new DoubleNode("[head]", 0, 0); // 带头尾的双链表(可优化去掉头尾)this->_tail = new DoubleNode("[tail]", 0, 0);_head->xNext = _tail;_head->yNext = _tail;_tail->xPrev = _head;_tail->yPrev = _head;};// 对象加入(新增)DoubleNode * Add(string name, int x, int y);// 对象离开(删除)void Leave(DoubleNode * node);// 对象移动void Move(DoubleNode * node, int x, int y);// 获取范围内的AOI (参数为查找范围)void PrintAOI(DoubleNode * node, int xAreaLen, int yAreaLen);private:DoubleNode * _head;DoubleNode * _tail;
};
2.1. add(进入地图)
将DoubleNode对象插入到十字链表中。x轴和y轴分别处理,处理方法基本一致。其实就是双链表的数据插入操作,需要从头开始遍历线性表,对比相应轴上的值的大小,插入到合适的位置。
void _add(DoubleNode * node)
{// x轴处理DoubleNode * cur = _head->xNext;while(cur != NULL){if((cur->x > node->x) || cur==_tail) // 插入数据{node->xNext = cur;node->xPrev = cur->xPrev;cur->xPrev->xNext = node;cur->xPrev = node;break;}cur = cur->xNext;}// y轴处理cur = _head->yNext;while(cur != NULL){if((cur->y > node->y) || cur==_tail) // 插入数据{node->yNext = cur;node->yPrev = cur->yPrev;cur->yPrev->yNext = node;cur->yPrev = node;break;}cur = cur->yNext;}
}
假设可视范围为x轴2以内,y轴2以内,则运行:
分别插入以下数据a(1,5)、f(6,6)、c(3,1)、b(2,2)、e(5,3),然后插入d(3,3),按照x轴和y轴打印其双链表结果;
插入d(3,3)数据,求其可视AOI范围(如图,除了f(6,6),其它对象都在d的可视范围内)。
控制台结果(前8行):
步骤1结果图示:
步骤2结果图示:
2.2. leave(离开地图)和move(移动)
其实都是双链表的基本操作,断掉其相应的指针就好了。按理,是需要
move和leave操作如图,move是将d(3,3)移动到(4,4),然后再打印其AOI范围。
控制台结果:
移动后AOI范围图示:
- 完整代码实例
#include "stdafx.h"#include "stdio.h"#include <iostream>#include <string>using namespace std;// 双链表(对象)class DoubleNode{public:DoubleNode(string key, int x, int y){this->key = key;this->x = x;this->y = y;xPrev = xNext = NULL;};DoubleNode * xPrev;DoubleNode * xNext;DoubleNode * yPrev;DoubleNode * yNext;string key;int x; // 位置(x坐标)int y; // 位置(y坐标)private:};// 地图/场景class Scene{public:Scene(){this->_head = new DoubleNode("[head]", 0, 0); // 带头尾的双链表(可优化去掉头尾)this->_tail = new DoubleNode("[tail]", 0, 0);_head->xNext = _tail;_head->yNext = _tail;_tail->xPrev = _head;_tail->yPrev = _head;};// 对象加入(新增)DoubleNode * Add(string name, int x, int y){DoubleNode * node = new DoubleNode(name, x, y);_add(node);return node;};// 对象离开(删除)void Leave(DoubleNode * node){node->xPrev->xNext = node->xNext;node->xNext->xPrev = node->xPrev;node->yPrev->yNext = node->yNext;node->yNext->yPrev = node->yPrev;node->xPrev = NULL;node->xNext = NULL;node->yPrev = NULL;node->yNext = NULL;};// 对象移动void Move(DoubleNode * node, int x, int y){Leave(node);node->x = x;node->y = y;_add(node);};// 获取范围内的AOI (参数为查找范围)void PrintAOI(DoubleNode * node, int xAreaLen, int yAreaLen){cout << "Cur is: " << node->key << "(" << node ->x << "," << node ->y << ")" << endl;cout << "Print AOI:" << endl;// 往后找DoubleNode * cur = node->xNext;while(cur!=_tail){if((cur->x - node->x) > xAreaLen){break;}else{int inteval = 0;inteval = node->y - cur->y;if(inteval >= -yAreaLen && inteval <= yAreaLen){cout << "\t" << cur->key << "(" << cur ->x << "," << cur ->y << ")" << endl;}}cur = cur->xNext;}// 往前找cur = node->xPrev;while(cur!=_head){if((node->x - cur->x) > xAreaLen){break;}else{int inteval = 0;inteval = node->y - cur->y;if(inteval >= -yAreaLen && inteval <= yAreaLen){cout << "\t" << cur->key << "(" << cur ->x << "," << cur ->y << ")" << endl;}}cur = cur->xPrev;}};// 调试代码void PrintLink() // 打印链表(从头开始){// 打印x轴链表DoubleNode * cur = _head->xNext;while (cur != _tail){cout << (cur->key) << "(" << (cur->x) <<"," << (cur->y) << ") -> " ;cur = cur->xNext;}cout << "end" << endl;// 打印y轴链表cur = _head->yNext;while (cur != _tail){cout << (cur->key) << "(" << (cur->x) <<"," << (cur->y) << ") -> " ;cur = cur->yNext;}cout << "end" << endl;};private:DoubleNode * _head;DoubleNode * _tail;void _add(DoubleNode * node){// x轴处理DoubleNode * cur = _head->xNext;while(cur != NULL){if((cur->x > node->x) || cur==_tail) // 插入数据{node->xNext = cur;node->xPrev = cur->xPrev;cur->xPrev->xNext = node;cur->xPrev = node;break;}cur = cur->xNext;}// y轴处理cur = _head->yNext;while(cur != NULL){if((cur->y > node->y) || cur==_tail) // 插入数据{node->yNext = cur;node->yPrev = cur->yPrev;cur->yPrev->yNext = node;cur->yPrev = node;break;}cur = cur->yNext;}}};// --------------------------------------------void main(){Scene scene = Scene();// 增加scene.Add("a", 1, 5);scene.Add("f", 6, 6);scene.Add("c", 3, 1);scene.Add("b", 2, 2);scene.Add("e", 5, 3);DoubleNode * node = scene.Add("d", 3, 3);scene.PrintLink();scene.PrintAOI(node, 2, 2);// 移动cout << endl << "[MOVE]" << endl;scene.Move(node, 4, 4);scene.PrintLink();scene.PrintAOI(node, 2, 2);// 删除cout << endl << "[LEAVE]" << endl;scene.Leave(node);scene.PrintLink();}
十字链表的AOI算法实现相关推荐
- noj数据结构稀疏矩阵的加法十字链表_一个算法毁了一款好游戏?算法和数据结构到底有多重要?...
来源 | 异步 | 文末赠书 前段时间大火的国产游戏--<太吾绘卷>,由于创新的玩法和精良的制作一度广受好评,然而随着玩家游戏的深入和时长的积累,发现该游戏在玩的过程中游戏外的问题很多很多 ...
- c语言建立并存储树,利用十字链表存储树结构(便于同时求出某一点的入度与出度)------C语言实现...
#include #include #include /* 利用十字链表存储有向图,可用于同时查找某个顶点的出度与入度: */ typedef struct edge {//顶点表 int headv ...
- 算法:游戏内AOI视野算法(十字链表)
为什么要有这个算法? 对于一个游戏场景内的实体来说,当战斗频繁的时候,可能存在上千实体的数据同步,例如上千实体移动时的坐标同步,大型战斗场景时全场景实体的属性的同步等等,这样就会造成一个问题,同步数据 ...
- 游戏算法-AOI十字链表入门简单版python
AOI十字链表python简单实现,仅用作学习,理解基本原理 AOI一般是C++去实现,本文章python写仅用来入门了解 场景内维护两个实体链表 list_x和list_y 所有实体根据x坐标大小排 ...
- 稀疏矩阵的十字链表存储表示和实现(第五章 P104 算法5.4)
稀疏矩阵的十字链表存储 当矩阵的非零元个数和位置在操作过程中变化较大时,就不宜采用顺序存储结构来表示三元组的线性表.对这种类型的矩阵,采用链式存储结构表示三元组的线性表更为恰当. 在链表中,每个非零元 ...
- 图十字链表并求度c语言,第5章_西安电子科技大学出版社:算法与数据结构-C语言描述(樊希平)_doc_大学课件预览_高等教育资讯网...
第5章 数组和广义表要点: 1.掌握数组元素存储位置的换算: 2.了解特殊矩阵地存储方法和元素存储位置计算: 3.了解广义表的长度.深度.head.tail等概念和操作和存储结构. 教材习题解答: 5 ...
- 经典算法题每日演练——第二十一题 十字链表
上一篇我们看了矩阵的顺序存储,这篇我们再看看一种链式存储方法"十字链表",当然目的都是一样,压缩空间. 一:概念 既然要用链表节点来模拟矩阵中的非零元素,肯定需要如下5个元素(ro ...
- 十字链表计算矩阵乘积 c语言,求用十字链表实现矩阵相加算法(C语言)急!!!...
匿名用户 1级 2010-02-09 回答 我有一个可以用的.怎么给你?百度hi我吧. 算了,我贴上来吧,由电脑编程网整理: #include #include #define smax 45 typ ...
- 游戏开发中AOI算法总结
定义 在MMO游戏中,在一些多人玩法中,通常出现很多玩家在同一张地图上移动的情况,假如一个玩家发生了移动,释放技能,更换装扮-这时就需要通知其他玩家,而如果通知整张地图上的所有玩家的话,显然是不现实的 ...
最新文章
- JSIS3D:具有多任务点向网络和多值条件随机场的3D点云联合语义-实例分割
- C++中有string类,string是一个类不是一种类型,c语言中没有
- 鸿蒙是安卓换皮UI,鸿蒙2.0是安卓换皮?还真不是
- “融合、智能、绿色”施耐德电气线上工博以全生命周期解决方案助推数字化
- 按用户设置计算机权限,巧妙设置用户权限 管理学生机房计算机
- Spring boot(8)---手动构建maven项目springboot
- 风控趋势|隐私计算几大落地场景与三方数据市场
- centos 6.4 更新源地址
- OpenCV-理想高通低通滤波器(C++)
- 算法笔记-----归并排序
- 安装Anaconda3 5.2.0后只有Anaconda Prompt,没有spyder等
- java extjs 教程_EXTJS入门教程及其框架搭建
- acm题库及答案 java_ACM试题及答案.docx
- Oracle 对 JDK收费和.NET Core 给我们的机遇
- 对计算机病毒的防治也,对计算机病毒及防范对策研究.doc
- C函数的参数中有取地址符
- 数据挖掘基础学习笔记
- SIGMOD 2021 论文简析:当公交网络连接满足通勤需求时的公共交通规划 Public Transport Planning
- 网红湾湾否认与李易峰恋情,网友:其实两人很般配!
- AP侧,BP侧如何理解?