原文地址: http://www.cnblogs.com/corefans/archive/2009/07/23/1529699.html、
基於格子的AOI算法
AOI( Area Of Interest )是網遊服務器中必不可少要考慮的一個問題,當前主流的AOI算法依然是
基於2D的格子的, 場景均分成爲等大的格子,每個Entity都根據其位置放到所屬格子的鏈表中.
關鍵問題是當Entity移動後:
一是要找到該Entity看到了哪些新的otherEntitys,
二是要找到哪些otherEntitys以前可以看到而現在看不到了,
三是要找到該Entity被哪些新的otherEntitys看到了,
四是要找出以前看得到自己現在看不到自己的otherEntitys.
1, 假定所有Entity的看到見的格子的數量都一樣,爲N*N,這意味着自己看得見的Entity也一定看得見自己,而
自己看不見的Entity也一定看不見自己.因此當Entity移動後:
<1>,找出Entity移動後新增的可見格子,將這些格子中的其它Entity加入自己的可見列表中(或者通知客戶端有新的Entity可見).
<2>,找出Entity移動前可見而移動後不可見的格子,將這些格子中的其它Entity從自己的可見列表中移除(或者通知客戶端這些Entity不可見).
<3>,找出Entity移動後新增的可見格子,將自已加入到這些格子中的其它Entity的可見列表中(或者通知其對應的客戶端有新的Entity可見).
<4>,找出Entity移動前可見而移動後不可見的格子,將自己從這些格子中的其它Entity的可見列表中移除(或者通知其對應的客戶端本Entity不可見).
2, 如果每個Entity的視野大小不等。每個格子增加一個observerGrids鏈表,保存所有"存在看得見該格子的對象"的格子。
當Entity移動後:
假定Entity移動前所在的gird命名爲oldGrid, 移動後所在的grid命名爲newGrid.
<1>,找到該Entity看到了哪些新的otherEntitys.
找出Entity移動後新增的可見格子, 記爲newVisibleGrids.
算法如下:
foreach nGrid in newVisibleGrids
{
foreach nEntity in nGrid.entityList
{
將nEntity加入到thisEntity的可見列表中.(通知thisEntity對應的客戶端nEntity可見).
}
將newGrid加入nGrid.observerGirds中.
}
<2>,找到哪些otherEntitys以前可以看到而現在看不到了.
找出Entity移動前可見而移動後不可見的格子,記爲newHideGrids.
算法如下:
foreach nhGrid in newHideGrids
{
//找出以前看得到而移動後看不到的entity.
for nhEntity in nhGrid.entityList
{
把nhEntity從thisEntity的可見列表中移除(通知客戶端nhEntity不可見).
}
如果oldGrid.entityList中的所有entity都看不見nhGrid,則將oldGrid從nhGrid.observerGrids中移除.
}
注:可以考慮在每個grid中記下所屬entity的最大視野,最小視野,平均視野優化移除算法.
<3>,找到該Entity被哪些新的otherEntitys看到了.
foreach nGrid in newGrid.observerGrids
{
//優化:這裏可以先排除掉同時存在於oldGrid.observerGrids中的nGrid?
foreach otherEntity in nGrid.entityList
{
oldDist = otherEntity.pos - thisEntity.oldPos; //oldPos爲entity移動前的位置.
newDist = otherEntity.pos - thisEntity.pos;
//檢測對於otherEntity來說是否爲新增的可見entity.
如果oldDist > otherEntity.viewDist 且 newDist <= otherEntity.viewDist
將thisEntity加入到otherEntity的可見列表中(通知otherEntity對應的客戶端thisEntity可見).
}
}
<4>,找出以前看得到自己現在看不到自己的otherEntitys.
foreach oGrid in oldGrid.observerGrids
{
//優化:這裏可以先排除掉同時存在於newGird.observerGrids中的oGrid?
foreach otherEntity in oGrid.entityList
{
oldDist = otherEntity.pos - thisEntity.oldPos; //oldPos爲entity移動前的位置.
newDist = otherEntity.pos - thisEntity.pos;
//檢測對於otherEntity來說是否爲新增的不可見entity.
如果oldDist <= otherEntity.viewDist 且 newDist > otherEntity.viewDist
將thisEntity從otherEntity的可見列表中移除(通知otherEntity對應的客戶端thisEntity不可見).
}
}