高级数据结构——十字链表

十字链表多用于AOI(Area Of Interest),即同步当前实体所能看到的其他实体的数据。

四叉树在场景中的应用,当主角周围的静态对象(场景物件等)非常多的时候,它比较合适,因为在场景初始化的时候就可以根据场景情况分配四叉树的子节点数,而在运行时,只用激活主角周围的节点。

而十字链元素的动态增减,更加适合移动的对象,比如同步或者显示周围移动的玩家,怪物等。

基本原理

算法的大概思想如下:

每个场景维护两个链表,分别为X轴和Y轴的坐标按序排列好的链表,也就是比如在X轴链表上,越在前的对象,X坐标越小,Y轴链表同理.这样,每次需要更新状态的时候,只需要在这个链表上向前或者向后遍历结点就知道该通知谁了.

这里假设有三个接口:

Add(向场景中添加一个对象),
Leave(某对象离开场景),
Move(某对象在场景中移动).

进入时:(Add)
1.对比x,y的值,插入合适的位置
2.获取周围列表
3.同步周围列表信息

根据新增对象的X,Y坐标,依次遍历X,Y轴坐标链表,这里有两个目的,一个是获得这个新增对象的坐标在X,Y轴坐标的位置,另一方面获得该通知哪些结点.通知的范围,每个对象可以自己定制自己的通知范围.但是为了简单起见,在这里我们假设每个结点X,Y坐标相差1,而通知的范围是2.比如原有的X轴坐标为:

a->b->c->d->e->f->g->h

假设新增一个对象z,它最终所在的位置是c和d之间,根据前面的假设,它只需要通知b,c,d,e四个结点就好了.所以,新增一个结点的时候,并不需要遍历完链表的.
但是这里还需要注意的是,一个结点,必须X,Y坐标同时都在通知范围内才可以进入通知集合.

离开时
1.获取周围列表
2.同步周围列表
3.更新离开节点的前后节点

在添加了对象之后,对象身上挂了两个结点,分别存放在X,Y轴坐标链表上的位置,那么在这个对象要离开场景时,也只需要向前向后探索一定的范围,就可以得到需要通知该对象要离开的集合了.

移动时
1.获取移动之前的周围列表
2.获取移动之后的周围列表
3.取并集中的非进入列表,作为最终离开列表
4.取交集为移动列表
5.取并集中的非离开列表,作为最终进入列表

移动操作比较麻烦,但是也可以比较漂亮的解决.在更新位置之前,同样根据前面的算法得到要通知的结点集合,称为old_set;更新位置之后,再获取另一个通知集合,称为new_set;然后,old_set和new_set的交集,称为move_set,在此集合中的结点,在移动前后都在通知范围,因此要向这个集合的结点发送该对象移动的消息;而old_set-move_set的集合,在移动之后已经离开了视野,因此要向它们发送该对象离开的消息;最后,new_set-move_set是移动之后才看见该结点的结点集合,这个集合的结点,要发送该结点进入场景的消息

发布了175 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43461641/article/details/102980268