参考:
云风的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)