一个链接:
(99+ 封私信 / 5 条消息) 四叉树 - 搜索结果 - 知乎 (zhihu.com)
但这个太水了,经过我一番仔细思考,还是有很多细节值得记录的
首先写一个平面四叉树类,提供三个API:
1 | class Tree { |
上面是伪代码,什么语言都不是
四叉树有节点。四叉树是完美四叉树,要么有孩子,要么没有孩子,一旦有孩子,就是四个孩子。
每个节点都能容纳N个物体。树高度H层,这两个参数可以自定义调节。
但是当物体在当前框框的十字线相接触了,那么只能塞到当前节点里了,不能再往下赛了。这个情况超过N也无所谓。
一开始树里面没有什么物品,对象,所以第一个进来的对象会直接塞到根节点上,而不是细化到某个非常小的区域所对应的节点上。
可以设计一个挂载物品对象类型
1 | interface NodeObjectCircle { |
可能要挂载的敌人对象或者子弹对象本身内部有xyr属性,但是为了统一类型格式,外面又包上了三个属性,自己自身绑定到了object字段上,形成一个新的对象。
然后,四叉树里的每个节点可能 是这样定义的
1 | interface treeNode { |
实际上可以考虑优化性能,把数组改成集合,或者字典类型,优化的是remove方法。
add方法
一开始啥都没有,肯定放在根节点的current里。满了才往下新创建四个子节点。兜住了就不创建,撑爆了才创建。
add的时候首先判断一下当前方框里的十字线是否和自己这个对象相交,相交了就只能放在current里。即使超过了N。
然后写四个if或者两个两个嵌套的if,判断四个子框。
然后一直深入下去,直到到底。或者触碰到十字。
remove方法
用递归来写。因为可能涉及到删除回收节点,防止长时间使用整个树里节点过多占用内存过多。并且这个删除回收节点不是只删除一个,可能是多层的链式的,删除好几个。只要把删除写在递归口的下面就行。
如果四个子节点都是空的,就删除所有的子节点。将他们设置为null。
在删除之前肯定要先找到。对于一个父节点和四个子节点,先看父节点的current里是否有当前这个对象,如果用哈希优化了,O1就能看到是否存在。然后判断一下要删除对象的位置处于哪个子框中。继续深入下去递归。
getCollish方法
传入一个对象,获取和这个对象碰撞的所有对象。
最理想情况:
如果所有的对象都没有和十字相交,那好说了,就看传入的这个对象所在的框框里,直接和所有其他的对象一一配对,看看是否发生相交,例如就调用圆和圆的相交的方法就行了。
但是还是要把这个节点所在的所有子孙节点的current里的对象都扫描一一检测一下碰撞。
还要考虑其他上层十字上的或者current上的对象。
如果传入的对象是在框里的,但是有其他对象和框框相交。那就看,在一路找下来,树上经过的节点,所有节点的current里,是否有节点和当前对象相碰。
也就是看所有上层的current里的所有对象是否和自己碰撞。因为这是一个递归过程,可以在找到之后返回的过程中进行一一比较。
缺点:
当节点本来就在根节点上的current里的时候,这无异于和全部对象都一一比了一下。
当圆形对象半径太大了的时候,那几乎是必定触碰最大的十字线的。