AOI 十字链表法(半径相同)

AOI主要有九宫格、灯塔和十字链表的算法实现。本文阐述十字链表的实现

本文是二维地图,将地图内的对象按照坐标值,从小到大分在x轴和y轴两个链表上。

如果是三维地图,则还需要维护多一个z轴的链表

啥子都不说,上代码

AOI视野范围的节点类

import math
class CEntity(object):

    def __init__(self,cid,x,y,distance):
        self.cid = cid
        self.x = x
        self.y = y
        self.radius = distance

    def __str__(self):
        return "[%s:(%s-%s)]" % (self.cid,self.x,self.y)

AOI的场景类

class CScene(object):

    def __init__(self):
        self.m_mapEntity = {}
        self.m_listXentity = []
        self.m_listYentity = []

    def add(self,cid,x,y,distance = 2):
        pentity = self.m_mapEntity.get(cid,None)
        if pentity:
            return
        pentity = CEntity(cid,x,y,distance)
        self.m_mapEntity[cid] = pentity
        indexx = len(self.m_listXentity)
        for i in range(len(self.m_listXentity)):
            if x < self.m_listXentity[i].x:
                indexx = i
                break
        indexy = len(self.m_listYentity)
        for j in range(len(self.m_listYentity)):
            if y < self.m_listYentity[j].y:
                indexy = j
                break
        
        self.m_listXentity.insert(indexx,pentity)
        self.m_listYentity.insert(indexy,pentity)
        entitymap = self.getRangeSet(pentity)
        print("add entity {0}".format(pentity))
        for entity in entitymap.values():
            print("send {0} entermsg to {1}".format(pentity,entity)) #通知entity,pentity进入视野范围
            print("send {0} entermsg to {1}".format(entity,pentity)) #通知pentity,entity进入视野范围
        

    def move(self,cid,x,y):
        pentity = self.m_mapEntity.get(cid,None)
        if not pentity:
            return
        oldEntityMap = self.getRangeSet(pentity)
        self.updateEntityPosition(pentity,x,y)
        newEntityMap = self.getRangeSet(pentity)
        for cid,entity in oldEntityMap.items():
            if newEntityMap.get(cid,None) != None:
                print("send {0} movemsg to {1}".format(pentity,entity))
                print("send {0} movemsg to {1}".format(entity,pentity))
            else:
                print("send {0} leavemsg to {1}".format(pentity,entity))
                print("send {0} leavemsg to {1}".format(entity,pentity))
            pass
        
        for cid,entity in newEntityMap.items():
            if oldEntityMap.get(cid,None) == None:
                print("send {0} entermsg to {1}".format(pentity,entity))
                print("send {0} entermsg to {1}".format(entity,pentity))

    def leave(self,cid):
        pentity = self.m_mapEntity.get(cid,None)
        if not pentity:
            return
        print("leave entity {0}".format(pentity))
        leaveEntityMap = self.getRangeSet(pentity)
        for _,entity in leaveEntityMap.items():
            print("send {0} leavemsg to {1}".format(pentity,entity))
        
        self.m_listXentity.remove(pentity)
        self.m_listYentity.remove(pentity)
        self.m_mapEntity.pop(cid,None)
        pentity = None

    def getRangeSet(self,pentity):
        if pentity == None:
            return
        x_map = {}
        xpos = self.m_listXentity.index(pentity)
        for pos in range(xpos - 1,-1,-1):
            curentity = self.m_listXentity[pos]
            if math.fabs(curentity.x - pentity.x) <= pentity.radius:
                x_map[curentity.cid] = curentity
            else:
                break
        
        for pos in range(xpos + 1,len(self.m_listXentity),1):
            curentity = self.m_listXentity[pos]
            if math.fabs(curentity.x - pentity.x) <= pentity.radius:
                x_map[curentity.cid] = curentity
            else:
                break
        
        pEntityMap = {}
        ypos = self.m_listYentity.index(pentity)
        for pos in range(ypos - 1,-1,-1):
            curentity = self.m_listYentity[pos]
            if math.fabs(curentity.y - pentity.y) <= pentity.radius:
                if x_map.get(curentity.cid,None) != None:
                    pEntityMap[curentity.cid] = curentity
            else:
                break
        for pos in range(ypos + 1,len(self.m_listYentity),1):
            curentity = self.m_listYentity[pos]
            if math.fabs(curentity.y - pentity.y) <= pentity.radius:
                if x_map.get(curentity.cid,None) != None:
                    pEntityMap[curentity.cid] = curentity
            else:
                break
        
        return pEntityMap

    def updateEntityPosition(self,pentity,x,y):
        oldx = pentity.x
        oldy = pentity.y
        pentity.x = x
        pentity.y = y

        xpos = self.m_listXentity.index(pentity)
        if oldx <= x:
            startindex = xpos + 1
            endindex = len(self.m_listXentity)
            step = 1
        else:
            startindex = xpos - 1
            endindex = 0
            step = -1
        
        indexx = xpos
        for i in range(startindex,endindex,step):
            if x >= self.m_listXentity[i].x:
                indexx = i
            else:
                break
        
        ypos = self.m_listYentity.index(pentity)
        if oldy <= y:
            startindex = ypos + 1
            endindex = len(self.m_listYentity)
            step = 1
        else:
            startindex = ypos - 1
            endindex = 0
            step = -1
 
        indexy = ypos
        for i in range(startindex,endindex,step):
            if y >= self.m_listYentity[i].y:
                indexy = i
            else:
                break
 
        self.m_listXentity.remove(pentity)
        self.m_listYentity.remove(pentity)
        self.m_listXentity.insert(indexx,pentity)
        self.m_listYentity.insert(indexy,pentity)
        pass

    def dump(self):
        print("xlist:")
        for entity in self.m_listXentity:
            print(entity)
        print("ylist:")
        for entity in self.m_listYentity:
            print(entity)
def main():
    scene = CScene()
    print("步骤一:添加5个对象")
    scene.add(1,1,5)
    scene.add(2,2,2)
    scene.add(3,3,1)
    scene.add(4,5,3)
    scene.add(5,6,6)
    print("步骤二:添加一个新的对象6到坐标(3,3)")
    scene.add(6,3,3)
    # scene.dump()
    print("步骤三:把对象6移动到坐标(4,4)")
    scene.move(6,4,4)
    # scene.dump()
    print("步骤四:移除这6个对象")
    for i in range(7):
        scene.leave(i)
    pass

if __name__ == "__main__":
    main()

 

add:添加节点。。

move:节点移动

leave:节点离开

getRangeSet(self,pentity):获取指定对象的AOI对象列表 返回一个map

updateEntityPosition(self,pentity,x,y) 更新对象CEntity到坐标(x,y)

运行结果如下:

附带分析:

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值