一些字段的解释

  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;//下一个灯塔idint32_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; // idint32_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_checkversionluaL_checkversion(L);
#endifregisterTowerSpaceL(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示意图

  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;
}

在此AOI模式下微服务器大世界地图分割方法和传统进程分割方法的不同

传统大世界地图分割方法

此方法为垂直分割方法,将一个一二十公里的大地图分割成很多小地图放到各自的进程当中去处理数据,这种需要处理大世界地图边缝问题,需要做镜像数据管理,还有如果角色在一个进程中也就是某个小地图上面堆积,那么这个进程的压力会很大,别的进程却很休闲,这个也需要处理,总之很多麻烦。所以我们改成了微服务器水平分割加灯塔AOI方式

微服务大世界地图处理方法

此结构基于微服务水平分割,每个相同微服务可以并行再开很多来并行处理减少压力,比如灯塔AOI开了5个微服务我发现算力还是不够,
那么我可以在增加新的灯塔AOI微服务来并行处理数据,所以理论上一个20公里的地图撑个10多万的人不成问题。而且这种模式在服务器不需要处理无缝问题

一些疑问的总结

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

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

简单测试数据

四叉树lod结合灯塔AOI相关推荐

  1. 回想四叉树LOD地形(上)

           唉! ~事实上这是在几乎相同一年前实现的东西.但当时没作好记录.放了那么久了.如果不做点总结的话.好像有点对不起自己.于是·········还是做点什么吧.        我脑洞比較小, ...

  2. 谈谈GIS三维渲染引擎

    minemap:是我们公司的产品,主要以earth的形态展示,支持矢量切片+倾斜数据(这一点我个人认为是它最大的优点,即兼容了矢量切片精美地图又兼容倾斜数据,目前倾斜数据采用的3dtile格式),目前 ...

  3. GIS三维渲染引擎 到底有什么区别

    minemap:主要以earth的形态展示,支持矢量切片+倾斜数据(这一点我个人认为是它最大的优点,即兼容了矢量切片精美地图又兼容倾斜数据,目前倾斜数据采用的3dtile格式),目前正在重构引擎架构, ...

  4. Unity无缝大世界实现调研

    无缝大世界的技术要求 世界足够大,一个地图就完整包含一个非常大的世界,如魔兽世界的整块卡利姆多大陆.面积从几平方公里到数十乃至上百平方公里.包含室外地形,城镇,也包含一定量的室内场景.室外地形包含各种 ...

  5. 三维渲染中的裁剪总汇

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/72420731 作者:car ...

  6. OpenGL视椎体 裁剪和剔除

    毕设做的是<基于四叉树的LOD地形渲染>,其中主要参考了潘李亮的<基于LOD的大规模真实感室外场景试试渲染技术的初步研究>一文,如有有兴趣做四叉树LOD的话,建议读一读这篇文章 ...

  7. 游戏服务器AOI兴趣点算法原理--四叉树与九宫格 (golang)

    定义: 获取感兴趣的区域(Area Of Interest)的算法.主要用于常用的游戏服务器压力,降低网络风暴的可能. 常见的AOI算法有九宫格,四叉树,灯塔,十字链表等算法.本文主要举例九宫格和四叉 ...

  8. 「游戏」游戏服务器中AOI的原理及四叉树实现

    前言 要不是想起来这篇文章想写一个关于游戏服务器开发过程中关于AOI相关的文章,我都差不点忘了我是一个游戏服务器开发人员

  9. LOD地形渲染技术概述

    参考文章 http://blog.sina.com.cn/s/blog_5e3213f30100zxet.html LOD技术简述 http://blog.sina.com.cn/s/blog_458 ...

最新文章

  1. 厦大计算机学硕考研复试,【图片】一战厦大计算机上岸,经验帖。慢更【考研吧】_百度贴吧...
  2. 2021-09-26
  3. IE6不支持max的解决办法
  4. HttpClientFactory系列二:集成Polly处理瞬态故障
  5. C/C 输入输出缓冲区
  6. 探求数据仓库关键环节ETL的本质
  7. crash分析中有用的管道命令
  8. C# .NET学习经验总结
  9. sql server 复制_SQL Server复制(合并)–复制架构更改中的性能问题
  10. 压力测试实践一:JMeter + JProfiler 入门
  11. ❤️Spring的声明式事务
  12. LNMP建站分离部署
  13. PL/SQL中导出整个表、表结构、部分数据、以及导入整个表
  14. 读书笔记 · AI产品经理的工作流程
  15. linux 建立ssh隧道,在Linux、Windows、macOS上创建SSH隧道并通过SSH隧道连接到MySQL
  16. Java 延迟队列 DelayQueue 的原理
  17. 电脑在桌面点击鼠标右键反应慢
  18. 兴奋神经递质——谷氨酸与大脑健康
  19. 超市会员管理系统 code
  20. 用数组统计学生各个分数段成绩的人数

热门文章

  1. 免费基金股票接口大全,macd,kdj,cci,威廉指标,神奇九转大全
  2. [Java 内存]Java内存组成
  3. Apple Watch Ultra和Apple Watch Series 8 区别 续航 功能介绍
  4. org.elasticsearch.common.util.concurrent.EsRejectedExecutionException 查询超时异常处理记录---一定要用单例模式
  5. 法兰克机器人外部自动_(完整版)KUKA机器人外部自动配置方法
  6. 苹果电脑如何同时运行Mac和Windows--pd18
  7. PS如何查看所选图层的实际像素?
  8. 新零售新模式:完整了解「快闪店」运作
  9. psd格式图片一键切图
  10. 使用Python解决Teamviewer被误认为商业用途的问题