四叉树lod结合灯塔AOI

一些字段的解释

  1. 观察者:我可以观察到那些人。
  2. 被观察者:那些人能观察到自己。
  3. #define WATCHER_MODE 0x01 观察者模式
  4. #define MARKER_MODE 0x02 被观察者模式

灯塔相关结构体

1:灯塔区域结构

struct towerSpace_s
{
     
	void (*callback)(void*pUserData,bool bAddTo,uint64_t watcher, uint64_t marker); -- 回调函数
	void*			pUserData; //用户信息
	float			fMin[2]; //最小位置
	float			fGridLength[3];//网格x y,z方向长度
	float			fMovefRange;//移动范围
	int32_t			iSplitThreshold;//拆分阈值
	int32_t 		iMaxWidth; //最大宽度
	int32_t 		iMaxHeight;//最大高度
    int32_t*  		pGrids;//网格数据
	tower_tt*		pTowers;//灯塔数据
	int32_t			iTowerNext;//下一个灯塔id
	int32_t			iTowerCapacity;//灯塔容量
	aoiObj_tt* 		pSlotObj;//格子里面对象
	int32_t			iSlotIndex;//格子索引
	int32_t     	iSlotCapacity;//格子容量
};

2:灯塔信息结构

typedef struct tower_s
{
     
	aoi_tree_tt watcher; //灯塔观察者[用来存储观察到的对象]
	aoi_tree_tt	marker;//灯塔被观察者
	int32_t     iMarkerCount;//被观察者数量
	int32_t  	iFirstChildId;//第一个儿子节点索引
} tower_tt;

3:灯塔划分后的节点结构【四个儿子节点】

typedef struct aoiNode_s
{
     
	RB_ENTRY(aoiNode_s) entry; //实体
	int32_t				iId; //id
} aoiNode_tt;

4:灯塔里面对象结构

typedef struct aoiObj_s
{
      
	int32_t		iId; // id
	int32_t 	iMode; // 模式(MARKER_MODE:被观察者模式 WATCHER_MODE:观察模式)
	uint64_t    uiMask;//掩码
	uint64_t    uiUserData; //用户数据
	float		fViewRadius; // 视野半径
	float 		last[3]; //上一个xyz位置
	float 		pos[3];//当前xyz位置
} aoiObj_tt;

灯塔AOI相关的一些操作函数

int32_t luaopen_laoi(lua_State *L)
{
     
#ifdef luaL_checkversion
	luaL_checkversion(L);
#endif
	registerTowerSpaceL(L);

	luaL_Reg lualib_funcs[] =
	{
     
		{
     "createAoiSpace",		lcreateAoiSpace},//创建aoi区域
		{
     NULL, NULL}
	};
	luaL_newlib(L, lualib_funcs);
	return 1;
}

int32_t registerTowerSpaceL(struct lua_State *L)
{
     
	luaL_newmetatable(L, "towerSpace");
	lua_pushvalue(L, -1);
	lua_setfield(L, -2, "__index");

	struct luaL_Reg lua_towerSpaceFuncs[] = 
	{
     
		{
     "setCallback",		laoi_setCallback}, //设置回调函数
		{
     "addObj",			laoi_addObj},//增加一个实体对象
		{
     "removeObj",		laoi_removeObj},//移除一个实体对象
		{
     "updateObjMask",	laoi_updateObjMask},//更新对象的mask[0x01:观察者 0x02:被观察者]
		{
     "updateObjPos",	laoi_updateObjPos},//更新对象的pos
		{
     "addObjWatcher",	laoi_addObjWatcher},//增加对象到相应的观察容器
		{
     "removeObjWatcher",laoi_removeObjWatcher},//从相应的观察容器移除对象
		{
     "addObjMarker",	laoi_addObjMarker},//增加对象到被观察者
		{
     "removeObjMarker",	laoi_removeObjMarker},//移除对象到被观察者
		{
     "__gc", 			laoi_towerSpace_gc},//此区域进行GC回收
		{
     NULL, NULL}
	};

	luaL_setfuncs(L, lua_towerSpaceFuncs, 0);
	return 1;
}

四叉树lod示意图四叉树lod结合灯塔AOI_第1张图片

  1. 黑色大框是AOI的区域大小
  2. 每个正方形块上面都有一个灯塔
  3. 暂时定的最多分裂3层
  4. 黑色的原点是场景内的实体

灯塔AOI一些关键函数[具体代码太多了有时间上传github]

1. 更新观察者集合

inline static void changeAoiObjWatcher(towerSpace_tt* pTowerSpace,aoiObj_tt* pObj)
{
     
	float bmin[3];
	float bmax[3];

	bmin[0] = pObj->last[0] - pObj->fViewRadius;
	bmin[2] = pObj->last[2] - pObj->fViewRadius;
	bmax[0] = pObj->last[0] + pObj->fViewRadius;
	bmax[2] = pObj->last[2] + pObj->fViewRadius;
	
	int32_t minxLast = 0;
	int32_t minyLast = 0;
	int32_t maxxLast = 0;
	int32_t maxyLast = 0;

	calcGridLodLoc(pTowerSpace, 2,bmin, &minxLast, &minyLast);
	calcGridLodLoc(pTowerSpace, 2,bmax, &maxxLast, &maxyLast);

	minxLast = minxLast > 0 ? minxLast : 0;
	minyLast = minyLast > 0 ? minyLast : 0;
	maxxLast = maxxLast < pTowerSpace->iMaxWidth * 4 ? maxxLast : pTowerSpace->iMaxWidth*4 - 1;
	maxyLast = maxyLast < pTowerSpace->iMaxHeight * 4 ? maxyLast : pTowerSpace->iMaxHeight*4 - 1;


	bmin[0] = pObj->pos[0] - pObj->fViewRadius;
	bmin[2] = pObj->pos[2] - pObj->fViewRadius;

	bmax[0] = pObj->pos[0] + pObj->fViewRadius;
	bmax[2] = pObj->pos[2] + pObj->fViewRadius;

	int32_t minx = 0;
	int32_t miny = 0;
	int32_t maxx = 0;
	int32_t maxy = 0;

	calcGridLodLoc(pTowerSpace, 2,bmin, &minx, &miny);
	calcGridLodLoc(pTowerSpace, 2,bmax, &maxx, &maxy);

	minx = minx > 0 ? minx : 0;
	miny = miny > 0 ? miny : 0;
	maxx = maxx < pTowerSpace->iMaxWidth*4 ? maxx : pTowerSpace->iMaxWidth*4 - 1;
	maxy = maxy < pTowerSpace->iMaxHeight*4 ? maxy : pTowerSpace->iMaxHeight*4 - 1;
	
	//是否重合
	if(isOverlap(minx,miny,maxx,maxy,minxLast,minyLast,maxxLast,maxyLast))
	{
     
		int32_t iMinX = minx < minxLast ? minx : minxLast;
		int32_t iMinY = miny < minyLast ? miny : minyLast;
		int32_t iMaxX = maxx >= maxxLast ? maxx : maxxLast;
		int32_t iMaxY = maxy >= maxyLast ? maxy : maxyLast;

		int32_t iChanged = 0;

		//往上找到最大的网格块
		//为什么是iMinY/4 是因为除以4就像四叉树一样找最上面的父节点的索引值一样
		for (int32_t iY = iMinY/4; iY < (iMaxY+3)/4; ++iY) 
		{
     
			for (int32_t iX = iMinX/4; iX < (iMaxX+3)/4; ++iX)
			{
     
				iChanged = 0;
				if(isInInside(iX*4,iY*4,iX*4+3,iY*4+3,minxLast,minyLast,maxxLast,maxyLast))
				{
     
					iChanged = 0x1;
				}

				if(isInInside(iX*4,iY*4,iX*4+3,iY*4+3,minx,miny,maxx,maxy))
				{
     
					iChanged |= 0x2;
				}

				switch (iChanged)
				{
     
				case 0x1:
					{
     
						removeGridWatcher(pTowerSpace,pObj,iX,iY);
					}
					break;
				case 0x2:
					{
     
						insertGridWatcher(pTowerSpace,pObj,iX,iY,pObj->pos);
					}
					break;
				case 0x3:
					{
     
						int32_t iTowerId = pTowerSpace->pGrids[iX + iY * pTowerSpace->iMaxWidth];
						assert(iTowerId != -1);
						tower_tt* pTower = pTowerSpace->pTowers + iTowerId;
						if (pTower->iFirstChildId == -1)
						{
     
							continue;
						}

						for (int32_t ly = 0; ly < 2; ly++)
						{
     
							for (int32_t lx = 0; lx < 2; lx++)
							{
     
								iChanged = 0;
								if (isInInside(iX * 4 + lx * 2, iY * 4 + ly * 2, iX * 4 + lx * 2 + 1, iY * 4 + ly * 2 + 1, minxLast, minyLast, maxxLast, maxyLast))
								{
     
									iChanged = 0x1;
								}

								if (isInInside(iX * 4 + lx * 2, iY * 4 + ly * 2, iX * 4 + lx * 2 + 1, iY * 4 + ly * 2 + 1, minx, miny, maxx, maxy))
								{
     
									iChanged |= 0x2;
								}

								switch (iChanged)
								{
     
								case 0x1:
									{
     
										removeLodWatcher(pTowerSpace, iTowerId, pObj, iX, iY, iX * 4 + lx * 2, iY * 4 + ly * 2);
									}
									break;
								case 0x2:
									{
     
										insertLodWatcher(pTowerSpace, iTowerId, pObj, iX, iY, iX * 4 + lx * 2, iY * 4 + ly * 2);
									}
									break;
								case 0x3:
									{
     
										tower_tt* pLodTower = pTowerSpace->pTowers + pTower->iFirstChildId + ly * 2 + lx;
										if (pLodTower->iFirstChildId == -1)
										{
     
											continue;
										}

										for (int32_t l2y = 0; l2y < 2; l2y++)
										{
     
											for (int32_t l2x = 0; l2x < 2; l2x++)
											{
     
												iChanged = 0;
												if (isInRect(iX * 4 + lx * 2+l2x, iY * 4 + ly * 2+l2y,  minxLast, minyLast, maxxLast, maxyLast))
												{
     
													iChanged = 0x1;
												}

												if (isInRect(iX * 4 + lx * 2+l2x, iY * 4 + ly * 2+l2y, minx, miny, maxx, maxy))
												{
     
													iChanged |= 0x2;
												}

												switch (iChanged)
												{
     
												case 0x1:
													{
     
														tower_tt* pLod2Tower = pTowerSpace->pTowers + pLodTower->iFirstChildId + l2y * 2 + l2x;
														aoiNode_tt findNode;
														findNode.iId = pObj->iId;
														aoiNode_tt* pT = RB_FIND(aoi_tree_s, &pLod2Tower->watcher, &findNode);
														assert(pT);
														RB_REMOVE(aoi_tree_s, &pLod2Tower->watcher, pT);
														mem_free(pT);

														aoiNode_tt* pI;
														RB_FOREACH(pI, aoi_tree_s, &pLod2Tower->marker)
														{
     
															aoiObj_tt* pMarkerObj = pTowerSpace->pSlotObj + pI->iId;
															if ((pI->iId != pObj->iId) && (pObj->uiMask & pMarkerObj->uiMask))
															{
     
																pTowerSpace->callback(pTowerSpace->pUserData, false, pObj->uiUserData, pMarkerObj->uiUserData);
															}
														}
													}
													break;
												case 0x2:
													{
     
														tower_tt* pLod2Tower = pTowerSpace->pTowers + pLodTower->iFirstChildId + l2y * 2 + l2x;
														aoiNode_tt* pNode = mem_malloc(sizeof(aoiNode_tt));
														pNode->iId = pObj->iId;
														RB_INSERT(aoi_tree_s, &pLod2Tower->watcher, pNode);

														aoiNode_tt* pI;
														RB_FOREACH(pI, aoi_tree_s, &pLod2Tower->marker)
														{
     
															aoiObj_tt* pMarkerObj = pTowerSpace->pSlotObj + pI->iId;
															if ((pI->iId != pObj->iId) && (pObj->uiMask & pMarkerObj->uiMask))
															{
     
																pTowerSpace->callback(pTowerSpace->pUserData, true, pObj->uiUserData, pMarkerObj->uiUserData);
															}
														}
													}
													break;
												}
											}
										}
									}
									break;
								}
							}
						}
					}
					break;
				}
			}
		}
	}
	else
	{
     
		for (int32_t iY = minyLast / 4; iY <= (maxyLast + 3) / 4; ++iY)
		{
     
			for (int32_t iX = minxLast / 4; iX <= (maxxLast + 3) / 4; ++iX)
			{
     
				removeGridWatcher(pTowerSpace, pObj, iX, iY);
			}
		}

		for (int32_t iY = miny/4; iY <= (maxy+3)/4; ++iY)
		{
     
			for (int32_t iX = minx/4; iX <= (maxx+3)/4; ++iX)
			{
     
				insertGridWatcher(pTowerSpace,pObj,iX,iY,pObj->pos);
			}
		}
	}	
}

2. 把被观察者转入观察者容器

inline static void changeAoiObjMaskToWatcher(towerSpace_tt* pTowerSpace,aoiObj_tt* pObj,int32_t iX,int32_t iY,uint64_t uiMask)
{
     
	int32_t iTowerId = pTowerSpace->pGrids[iX+iY*pTowerSpace->iMaxWidth];
    assert(iTowerId != -1);
    
	tower_tt* pTower = pTowerSpace->pTowers + iTowerId;
    if (pTower->iFirstChildId == -1)
    {
     
		int32_t iChanged;
		aoiNode_tt* pI; 
		RB_FOREACH(pI,aoi_tree_s,&pTower->marker)
		{
     
			if(pI->iId != pObj->iId)
			{
     
				iChanged = 0;
				aoiObj_tt* pMarkerObj = pTowerSpace->pSlotObj + pI->iId;
				if(pMarkerObj->iMode&pObj->uiMask)
				{
     
					iChanged = 0x1;
				}

				if(pMarkerObj->iMode&uiMask)
				{
     
					iChanged |= 0x2;
				}

				switch (iChanged)
				{
     
				case 0x1:
					{
     
						pTowerSpace->callback(pTowerSpace->pUserData,false,pObj->uiUserData,pMarkerObj->uiUserData);
					}
					break;
				case 0x2:
					{
     
						pTowerSpace->callback(pTowerSpace->pUserData,true,pObj->uiUserData,pMarkerObj->uiUserData);
					}
					break;
				}
			} 
		}
        return;
    }

    int32_t minGridX =iX*4;
    int32_t minGridY =iY*4;
    int32_t maxGridX =iX*4+3;
    int32_t maxGridY =iY*4+3;

    float bmin[3];
    float bmax[3];

    int32_t minx = 0;
    int32_t miny = 0;
    int32_t maxx = 0;
    int32_t maxy = 0;

    bmin[0] = pObj->last[0] - pObj->fViewRadius;
    bmin[2] = pObj->last[2] - pObj->fViewRadius;

	bmax[0] = pObj->last[0] + pObj->fViewRadius;
	bmax[2] = pObj->last[2] + pObj->fViewRadius;
    calcGridLodLoc(pTowerSpace, 2,bmin, &minx, &miny);
    calcGridLodLoc(pTowerSpace, 2,bmax, &maxx, &maxy);

    if(!isInInside(minGridX,minGridY,maxGridX,maxGridY,minx,miny,maxx,maxy))
    {
     
        for (int32_t y = 0; y < 2; y++)
        {
     
            for (int32_t x = 0; x < 2; x++)
            {
     
                tower_tt* pLodTower = pTowerSpace->pTowers + pTower->iFirstChildId + y*2+x;
                if(pLodTower->iFirstChildId == -1)
                {
     
					int32_t iChanged;
					aoiNode_tt* pI; 
					RB_FOREACH(pI,aoi_tree_s,&pLodTower->marker)
					{
     
						if(pI->iId != pObj->iId)
						{
     
							iChanged = 0;
							aoiObj_tt* pMarkerObj = pTowerSpace->pSlotObj + pI->iId;
							if(pMarkerObj->iMode&pObj->uiMask)
							{
     
								iChanged = 0x1;
							}

							if(pMarkerObj->iMode&uiMask)
							{
     
								iChanged |= 0x2;
							}

							switch (iChanged)
							{
     
							case 0x1:
								{
     
									pTowerSpace->callback(pTowerSpace->pUserData,false,pObj->uiUserData,pMarkerObj->uiUserData);
								}
								break;
							case 0x2:
								{
     
									pTowerSpace->callback(pTowerSpace->pUserData,true,pObj->uiUserData,pMarkerObj->uiUserData);
								}
								break;
							}
						}

					}
                }
                else
                {
     
                    if(!isInInside(minGridX+x*2,minGridY+y*2,minGridX+x*2+1,minGridY+y*2+1,minx,miny,maxx,maxy))
                    {
     
                        for (int32_t ly = 0; ly < 2; ly++)
                        {
     
                            for (int32_t lx = 0; lx < 2; lx++)
                            {
     
                                if(isInRect(minGridX+x*2+lx,minGridY+y*2+ly,minx,miny,maxx,maxy))
                                {
     
                                    tower_tt* pLod2Tower = pTowerSpace->pTowers + pLodTower->iFirstChildId + ly*2+lx;
									int32_t iChanged;
                                    aoiNode_tt* pI; 
                                    RB_FOREACH(pI,aoi_tree_s,&pLod2Tower->marker)
                                    {
     
										if(pI->iId != pObj->iId)
										{
     
											iChanged = 0;
											aoiObj_tt* pMarkerObj = pTowerSpace->pSlotObj + pI->iId;
											if(pMarkerObj->iMode&pObj->uiMask)
											{
     
												iChanged = 0x1;
											}

											if(pMarkerObj->iMode&uiMask)
											{
     
												iChanged |= 0x2;
											}

											switch (iChanged)
											{
     
											case 0x1:
												{
     
													pTowerSpace->callback(pTowerSpace->pUserData,false,pObj->uiUserData,pMarkerObj->uiUserData);
												}
												break;
											case 0x2:
												{
     
													pTowerSpace->callback(pTowerSpace->pUserData,true,pObj->uiUserData,pMarkerObj->uiUserData);
												}
												break;
											}
										}
										
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
     
						int32_t iChanged;
                        aoiNode_tt* pI; 
                        for (int32_t i = 0; i < 4; i++)
                        {
     
                            tower_tt* pLod2Tower = pTowerSpace->pTowers + pLodTower->iFirstChildId+i;
                            RB_FOREACH(pI,aoi_tree_s,&pLod2Tower->marker)
                            {
     
								if(pI->iId != pObj->iId)
								{
     
									aoiObj_tt* pMarkerObj = pTowerSpace->pSlotObj + pI->iId;
									iChanged = 0;
									if(pMarkerObj->iMode&pObj->uiMask)
									{
     
										iChanged = 0x1;
									}

									if(pMarkerObj->iMode&uiMask)
									{
     
										iChanged |= 0x2;
									}

									switch (iChanged)
									{
     
									case 0x1:
										{
     
											pTowerSpace->callback(pTowerSpace->pUserData,false,pObj->uiUserData,pMarkerObj->uiUserData);
										}
										break;
									case 0x2:
										{
     
											pTowerSpace->callback(pTowerSpace->pUserData,true,pObj->uiUserData,pMarkerObj->uiUserData);
										}
										break;
									}
								}
                            }
                        }
                    }
                }
            }
        }
    }
    else
    {
     
		int32_t iChanged;
		aoiNode_tt* pI; 

        for (int32_t i = 0; i < 4; i++)
        {
     
            tower_tt* pLodTower = pTowerSpace->pTowers + pTower->iFirstChildId+i;
            if (pLodTower->iFirstChildId == -1)
            {
     
                RB_FOREACH(pI,aoi_tree_s,&pLodTower->marker)
                {
     
					if(pI->iId != pObj->iId)
					{
     
						aoiObj_tt* pMarkerObj = pTowerSpace->pSlotObj + pI->iId;
						iChanged = 0;
						if(pMarkerObj->iMode&pObj->uiMask)
						{
     
							iChanged = 0x1;
						}

						if(pMarkerObj->iMode&uiMask)
						{
     
							iChanged |= 0x2;
						}

						switch (iChanged)
						{
     
						case 0x1:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,false,pObj->uiUserData,pMarkerObj->uiUserData);
							}
							break;
						case 0x2:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,true,pObj->uiUserData,pMarkerObj->uiUserData);
							}
							break;
						}
					}
                }
            }
            else
            {
     
                for (int32_t j = 0; j < 4; j++)
                {
     
                    tower_tt* pLod2Tower = pTowerSpace->pTowers + pLodTower->iFirstChildId+j;
                    RB_FOREACH(pI,aoi_tree_s,&pLod2Tower->marker)
                    {
     
						if(pI->iId != pObj->iId)
						{
     
							aoiObj_tt* pMarkerObj = pTowerSpace->pSlotObj + pI->iId;
							iChanged = 0;
							if(pMarkerObj->iMode&pObj->uiMask)
							{
     
								iChanged = 0x1;
							}

							if(pMarkerObj->iMode&uiMask)
							{
     
								iChanged |= 0x2;
							}

							switch (iChanged)
							{
     
							case 0x1:
								{
     
									pTowerSpace->callback(pTowerSpace->pUserData,false,pObj->uiUserData,pMarkerObj->uiUserData);
								}
								break;
							case 0x2:
								{
     
									pTowerSpace->callback(pTowerSpace->pUserData,true,pObj->uiUserData,pMarkerObj->uiUserData);
								}
								break;
							}
						}
                    }
                }
            }
        }
    }
}

3. 更新AOI的被观察者

void towerSpace_updateAoiObjMask(towerSpace_tt* pTowerSpace,int32_t iObjId,uint64_t uiMask)
{
     
	aoiObj_tt* pObj = pTowerSpace->pSlotObj + iObjId;
	assert(pObj->iId == iObjId);
	if(pObj->uiMask == uiMask)
	{
     
		return;
	}

	if(pObj->iMode&MARKER_MODE)
	{
     
		int32_t iX;
		int32_t iY;
		calcGridLoc(pTowerSpace,pObj->last,&iX,&iY);
		int32_t iTowerId = pTowerSpace->pGrids[iX+iY*pTowerSpace->iMaxWidth];
		assert(iTowerId != -1);
		tower_tt* pTower = pTowerSpace->pTowers + iTowerId;
		if(pTower->iFirstChildId == -1)
		{
     
			int32_t iChanged = 0;
			aoiNode_tt* pI; 
			RB_FOREACH(pI,aoi_tree_s,&pTower->watcher)
			{
     
				if(pI->iId != pObj->iId)
				{
     
					aoiObj_tt* pWatcherObj = pTowerSpace->pSlotObj + pI->iId;
					iChanged = 0;
					if(pWatcherObj->iMode&pObj->uiMask)
					{
     
						iChanged = 0x1;
					}

					if(pWatcherObj->iMode&uiMask)
					{
     
						iChanged |= 0x2;
					}

					switch (iChanged)
					{
     
					case 0x1:
						{
     
							pTowerSpace->callback(pTowerSpace->pUserData,false,pI->iId,pObj->iId);
						}
						break;
					case 0x2:
						{
     
							pTowerSpace->callback(pTowerSpace->pUserData,true,pI->iId,pObj->iId);
						}
						break;
					}
				}
			}
		}
		else
		{
     
			int32_t iLodX;
			int32_t iLodY;
			calcGridLodLoc(pTowerSpace,1,pObj->last,&iLodX,&iLodY);
			int32_t iTowerLodId = pTower->iFirstChildId + (iLodX -iX*2)+(iLodY - iY*2)*2;
			tower_tt* pLodTower = pTowerSpace->pTowers + iTowerLodId;
			if(pLodTower->iFirstChildId == -1)
			{
     
				int32_t iChanged = 0;
				aoiNode_tt* pI; 
				RB_FOREACH(pI,aoi_tree_s,&pTower->watcher)
				{
     
					if(pI->iId != pObj->iId)
					{
     
						aoiObj_tt* pWatcherObj = pTowerSpace->pSlotObj + pI->iId;
						iChanged = 0;
						if(pWatcherObj->iMode&pObj->uiMask)
						{
     
							iChanged = 0x1;
						}

						if(pWatcherObj->iMode&uiMask)
						{
     
							iChanged |= 0x2;
						}

						switch (iChanged)
						{
     
						case 0x1:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,false,pI->iId,pObj->iId);
							}
							break;
						case 0x2:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,true,pI->iId,pObj->iId);
							}
							break;
						}
					}
				}

				RB_FOREACH(pI,aoi_tree_s,&pLodTower->watcher)
				{
     
					if(pI->iId != pObj->iId)
					{
     
						aoiObj_tt* pWatcherObj = pTowerSpace->pSlotObj + pI->iId;
						iChanged = 0;
						if(pWatcherObj->iMode&pObj->uiMask)
						{
     
							iChanged = 0x1;
						}

						if(pWatcherObj->iMode&uiMask)
						{
     
							iChanged |= 0x2;
						}

						switch (iChanged)
						{
     
						case 0x1:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,false,pI->iId,pObj->iId);
							}
							break;
						case 0x2:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,true,pI->iId,pObj->iId);
							}
							break;
						}
					}
				}
			}
			else
			{
     
				int32_t iLod2X;
				int32_t iLod2Y;
				calcGridLodLoc(pTowerSpace,2,pObj->last,&iLod2X,&iLod2Y);
				int32_t iTowerLod2Id = pLodTower->iFirstChildId + (iLod2X -iLodX*2)+(iLod2Y - iLodY*2)*2;
				tower_tt* pLod2Tower = pTowerSpace->pTowers + iTowerLod2Id;

				int32_t iChanged = 0;
				aoiNode_tt* pI; 
				RB_FOREACH(pI,aoi_tree_s,&pTower->watcher)
				{
     
					if(pI->iId != pObj->iId)
					{
     
						aoiObj_tt* pWatcherObj = pTowerSpace->pSlotObj + pI->iId;
						iChanged = 0;
						if(pWatcherObj->iMode&pObj->uiMask)
						{
     
							iChanged = 0x1;
						}

						if(pWatcherObj->iMode&uiMask)
						{
     
							iChanged |= 0x2;
						}

						switch (iChanged)
						{
     
						case 0x1:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,false,pI->iId,pObj->iId);
							}
							break;
						case 0x2:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,true,pI->iId,pObj->iId);
							}
							break;
						}
					}
					
				}

				RB_FOREACH(pI,aoi_tree_s,&pLodTower->watcher)
				{
     
					if(pI->iId != pObj->iId)
					{
     
						aoiObj_tt* pWatcherObj = pTowerSpace->pSlotObj + pI->iId;
						iChanged = 0;
						if(pWatcherObj->iMode&pObj->uiMask)
						{
     
							iChanged = 0x1;
						}

						if(pWatcherObj->iMode&uiMask)
						{
     
							iChanged |= 0x2;
						}

						switch (iChanged)
						{
     
						case 0x1:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,false,pI->iId,pObj->iId);
							}
							break;
						case 0x2:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,true,pI->iId,pObj->iId);
							}
							break;
						}
					}
					
				}

				RB_FOREACH(pI,aoi_tree_s,&pLod2Tower->watcher)
				{
     
					if(pI->iId != pObj->iId)
					{
     
						aoiObj_tt* pWatcherObj = pTowerSpace->pSlotObj + pI->iId;
						iChanged = 0;
						if(pWatcherObj->iMode&pObj->uiMask)
						{
     
							iChanged = 0x1;
						}

						if(pWatcherObj->iMode&uiMask)
						{
     
							iChanged |= 0x2;
						}

						switch (iChanged)
						{
     
						case 0x1:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,false,pI->iId,pObj->iId);
							}
							break;
						case 0x2:
							{
     
								pTowerSpace->callback(pTowerSpace->pUserData,true,pI->iId,pObj->iId);
							}
							break;
						}
					}
				}
			}
		}
	}

	if(pObj->iMode&WATCHER_MODE)
	{
     
		float bmin[3];
		float bmax[3];

		bmin[0] = pObj->last[0] - pObj->fViewRadius;
		bmin[2] = pObj->last[2] - pObj->fViewRadius;


		bmax[0] = pObj->last[0] + pObj->fViewRadius;
		bmax[2] = pObj->last[2] + pObj->fViewRadius;

		int32_t minx = 0;
		int32_t miny = 0;
		int32_t maxx = 0;
		int32_t maxy = 0;

		calcGridLoc(pTowerSpace, bmin, &minx, &miny);
		calcGridLoc(pTowerSpace, bmax, &maxx, &maxy);

		minx = minx > 0 ? minx : 0;
		miny = miny > 0 ? miny : 0;
		maxx = maxx < pTowerSpace->iMaxWidth ? maxx : pTowerSpace->iMaxWidth - 1;
		maxy = maxy < pTowerSpace->iMaxHeight ? maxy : pTowerSpace->iMaxHeight - 1;

		for (int32_t iY = miny; iY <= maxy; ++iY)
		{
     
			for (int32_t iX = minx; iX <= maxx; ++iX)
			{
     
				changeAoiObjMaskToWatcher(pTowerSpace,pObj,iX,iY,uiMask);
			}
		}
	}

	pObj->uiMask = uiMask;
}

一些疑问的总结

  1. 为什么有了观察者集合,还需要被观察者集合

因为有时候想主动检查对象的状态,从怪物AI会定时检查被观察者集合的距离,决定是否发动攻击;又比如释放技能需要遍历被观察者集合,判断它们是否命中。如果没有被观察者集合,就必须遍历整个场景的对象

你可能感兴趣的:(游戏方面)