技术标签: 算法/数据结构 业务-游戏 视野 aoi 编程语言-c/c++
参考:
云风的BLOG http://blog.codingnow.com/2012/03/dev_note_13.html
网易pomelo开源项目的灯塔aoi模块 https://github.com/NetEase/pomelo-aoi
网上看到的一个对十字链表法的实现 http://www.codedump.info/?p=388
1.最直接了当的实现:扫格子,每次地图上对象出现、消失、移动都扫描该对象所属格子的周边的格子(扫几格的范围就据视野而定了)找到玩家角色做通知;如果移动的是玩家,则要把周边地格的对象出现和消失通知给玩家
2.十字链表,没细研究,上面有一篇介绍和实现,感觉有些粗糙
3.灯塔,前几天把pomelo中的tower aoi的js实现看了一遍,总结如下:
1>js代码写得不是很好,发现了几个小问题;
2>“对象(包括观察者)出现”“对象(包括观察者)消失”“对象(包括观察者)位置变化”“观察者位置变化”的回调通知(前三者通知对应灯塔区域的观察者,第四个通知观察者本身)没有可测试的样例,采用的话需要自己实现和测试;
3>只考虑了起点和终点,移动路径上的玩家被忽视了,路径短的话也可能不是问题(长路径切分成多个短路径做位置更新);
4>观察者可能收到超出自己视野范围的消息;
5>优点是可处理视野不同的观察者,相对于普通扫格子的实现在代码层面耦合度降低、效率提升不明显(把扫格子实现的地格看做一个灯塔区域,在地格上记录观察者就可以模拟这种灯塔模型,削去了遍历周边地格所有对象的逻辑)
6>这里做的是四边形灯塔区域,云风提的那种六边形灯塔区域减少查询灯塔个数是特指视野半径<=六边形边长的一半这种情况
7.tower aoi其实就是处理地图视野的一个设计,类似于订阅-发布,我订阅某一块区域表示对这一块区域感兴趣,那么有对象在这一块区域出现消失移动你就通知我
这里是我对pomelo-aoi的C++改写:https://github.com/xiarendeniao/pomelo-aoi
除了改写代码以外也修复了一个小问题:AddWatcher对于订阅区域的所有对象出现、RemoveWatcher对于取消订阅区域的所有对象消失,这两项没有通知watcher
这个版本的实现完全是对pomelo-aoi改写,如果要加到游戏项目中需要根据需要稍微定制以提升效率或节省内存,既然是项目无关,那么公开到网上也无可厚非,哈哈哈哈
还有一些改进的想法是:把每个watcher的视野半径和位置记录在aoi内部,这样AddWatcher/RemoveWatcher/UpdateWatcher的时候可以做一下校验;在灯塔记录该区域所有watcher的同时,在watcher身上记录其所有订阅的灯塔,这样游戏业务中不可避免且频繁获取watcher视野内对象时,直接遍历watcher身上的灯塔拿灯塔记录的所有对象(灯塔身上的对象,不等同于灯塔身上的watcher!)
最后,贴一张C++实现灯塔aoi的测试界面(不善于图形编程故没法像云风那样可视化显示 :( )
Valgrind检测内存泄漏,结果正常:
sudo yum install valgrind valgrind-devel -y g++ -g -o0 -o aoi test.cpp valgrind -v ./aoi Q --29416-- REDIR: 0x35c18bb330 (operator delete[](void*)) redirected to 0x4a05a9f (operator delete[](void*)) press enter to continue... ==29416== ==29416== HEAP SUMMARY: ==29416== in use at exit: 0 bytes in 0 blocks ==29416== total heap usage: 21,667 allocs, 21,667 frees, 914,829 bytes allocated ==29416== ==29416== All heap blocks were freed -- no leaks are possible ==29416== ==29416== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6) --29416-- --29416-- used_suppression: 4 U1004-ARM-_dl_relocate_object --29416-- used_suppression: 2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a ==29416== ==29416== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
文章浏览阅读1.5k次。z-index默认情况下,网页是一个二维空间,并根据在DOM中的顺序,从左到右,从上到下,依次排列各个元素。当页面上出现相对定位、或绝对定位、或固定定位的元素后,如果对一个元素设置了偏移,就很可能出现元素相互重叠的情况。如果把页面作为 x-y 轴,垂直于页面的方向就是 z 轴,重叠的情况就发生在 z 轴。元素在 z轴 的位置,取决于它在DOM中的先后顺序。如果两个元素发生重叠,在DOM中先出现的元...
文章浏览阅读1k次。esp8266 freertos linux wsl_esp8266 rtos sdk
文章浏览阅读301次。原文地址:http://www.williamlong.info/archives/2700.html首先,欢迎来到程序员的世界。在这个世界上,不是有很多人想创造软件并解决问题。你是一名hacker,属于那些愿意做一些有挑战性的事情的人。 “当你不创造东西时,你只会根据自己的感觉而不是能力去看待问题。” – WhyTheLuckyStiff 对于下面的文字你不必完全
文章浏览阅读148次。_nio transferto底层原理
文章浏览阅读5.6k次,点赞2次,收藏2次。根据项目需求需要对搜索词进行IK分词后,然后按照是否可售卖>是否推荐>发布日期进行排序,如下所示BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();boolQueryBuilder.must(QueryBuilders.multiMatchQuery("酒店","主标题","副标题"));SearchRequestBu_es sort 分数为空
文章浏览阅读402次。【时间】2019.01.14【题目】从香农信息量、信息熵和交叉熵到GANs中的KL散度和JS散度概述 本文转载自生成对抗网络(GANs)系列文章之一:KL散度和JS散度,侵权删。 主要从香农信息量、信息熵和交叉熵开始讲起,到引导出GANs中的KL散度和JS散度的概念,并介绍他们之间的关系。一.香农信息量、信息熵和交叉熵 只考虑连续型随机变量的情况。设p为随..._香农信息量、信息熵、交叉熵
文章浏览阅读121次。LeetCode 144.二叉树的前序遍历1.题目描述:给定一个二叉树,返回它的 前序 遍历。示例:输入: [1,null,2,3]12/3输出: [1,2,3]2.解题思路:二叉树的前序遍历就是按照访问根节点——左子树——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。使用递归函数可以简单的实现这种功能。递归终止的的条件是遇到空节点。3.python实现:class Solution: def preorderTrave
文章浏览阅读429次。ansible定义变量和管理事实
文章浏览阅读160次。 本文讲gulp-mock-server的应用,用于虚拟一个服务器,模拟后台返回json数据给前端,这样可以一定程度上实现前后端分离,约定好接口之后,前后端即可同时开发,从而提高效率。 在gulpfile里新建任务://mock servergulp.task('mock', function() { gulp.src('.') .pipe(g.moc...
文章浏览阅读7.5k次。ftp服务器在网上较为常见,Linux ftp命令的功能是用命令的方式来控制在本地机和远程机之间传送文。下面由学习啦小编为大家整理了linux下查询ftp命令的相关知识,希望对大家有所帮助。Linux ftp命令的格式$ ftp 主机名/IP其中“主机名/IP”是所要连接的远程机的主机名或IP地址。在命令行中,主机名属于选项,如果指定主机名,ftp将试图与远程机的ftp服务程序进行连接;如果没有指..._ftp linux 文件列表
文章浏览阅读420次。众数问题时间限制:3000 ms | 内存限制:65535 KB难度:3描述所谓众数,就是对于给定的含有N个元素的多重集合,每个元素在S中出现次数最多的成为该元素的重数,多重集合S重的重数最大的元素成为众数。例如:S={1,2,2,2,3,5},则多重集S的众数是2,其重数为3。现在你的任务是:对于给定的由m个自然数组成的多重集S,计算出
文章浏览阅读501次。语法格式如下:<a th:href="@{/channel/page/add}">添加渠道 </a><a href="/channel/page/add">添加渠道 </a>在默认项目路径为空时,打Jar包单独运行时。二者效果一致。在使用Maven内嵌Tomcat或打War包部署到Servlet容器,或者在项目内执行App启动类,且有配置项目路径时。二者区别如下:href始终从端口开始作为根路径,如http://localhost:80_th:href