基於單元格的AOI(Area of Interest)算法簡析

原文地址: 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不可見).
               }           
        }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章