地圖分割,怪物羣體 檢測 侵入者

在地圖上某塊區域,有數個怪物組成的 "哨兵小組",即不會移動, 但擁有警惕視野, 如圖1.api

這5個哨兵是不會移動, 有站立點可肯定一個最小外凸包圍圈, 如圖2;再產生最小矩形包圍圈,如圖3.this

typedef struct Position_t{
    INT mapid;
    INT x;
    INT y;
}Position_t, MapPieceBoundInfo_t;

typedef UINT ElementType_t;
typedef UINT GUID_t;

class GamePlayer
{
public:
    BOOL IsMoving();
    Position_t      GetPosition();
    GUID_t          GetGUID();
};

class
Monster { public: ElementType_t ElementType(); Position_t GetPosition(); BOOL FindInMyDetection( const Position_t& pos); VOID HeartBeat(); private: MonsterGroupCell* m_sharedGroupCell; };
typedef struct MonsterGroupCell
{
    // players enter this cell
    std::map< GUID_t, GamePlayer*>         m_playerList;           

    ElementType_t                   m_type;
    MapPieceBoundInfo_t             m_LeftTop;
    MapPieceBoundInfo_t             m_RightBottom;

public:
    inline size_t Size( ){ return m_playerList.size(); }

    VOID TryDetectGameObject( GamePlayer* gPlayer);

    VOID TickClearInvalidGameObjectRecord( );

};

 

按照警惕視野(r)擴寬後, 這個怪物羣體的"警惕矩形"將變成 如圖4.spa

class MapData{

public:

    const INT PIECE_SIZE = 20;

    BOOL init(); // 進行地圖切割

  
    VOID WhenMonstersCreated()
    { // 怪物建立好後, 進行羣組分類, 即產生最大包圍矩形

      // 第一部分 對怪物進行 分類顫聲道 MonsterGroupCell
        if( m_monsterList.size() > 0 )
        {
            std::map<ElementType_t, MonsterGroupCell*>  mapMonsterGroupCells;

            std::vector<Monster*>::const_iterator iter = m_monsterList.begin();
            for( ; iter != m_monsterList.end() ; iter ++ )
            {
                ElementType_t monsterType = (*iter)->ElementType();
                MonsterGroupCell* groupCell = mapMonsterGroupCells[ monsterType ];
                if( groupCell == NULL )
                {
                    MonsterGroupCell* groupCell = new MonsterGroupCell;
                    ASSERT( groupCell != NULL);

                    groupCell->m_LeftTop.x = m_col + 1;
                    groupCell->m_LeftTop.y = m_row + 1;

                    groupCell->m_RightBottom.x = 0;
                    groupCell->m_RightBottom.y = 0;

                    mapMonsterGroupCells[ monsterType ] = groupCell;
                }

                Position_t pos = (*iter)->GetPosition();
                if( pos.x < groupCell->m_LeftTop.x )
                {
                    groupCell->m_LeftTop.x = pos.x;
                }

                if( pos.y < groupCell->m_LeftTop.y )
                {
                    groupCell->m_LeftTop.y = pos.y;
                }

                if( pos.x > groupCell->m_RightBottom.x )
                {
                    groupCell->m_RightBottom.x = pos.x;
                }

                if( pos.y > groupCell->m_RightBottom.y )
                {
                    groupCell->m_RightBottom.y = pos.y;
                }
            }

            //第二部分: 非配各個 MonsterGroupCell 到 地圖切片上
            // ...    
    }// eof function 

    
    VOID GameObjectPositionCheck();

private:
    std::list<GamePlayer*>  m_playerList;
    std::vector<Monster*>   m_monsterList;  
    MapPiece**               m_Pieces;

    INT m_mapid;
    INT m_row ;
    INT m_col ;

    INT m_rowPieces;
    INT m_colPieces;
};

 

一張地圖上有不一樣的 怪物小組(此處都做爲不可移動的哨兵), 有 不少不一樣形狀,可能會相互重疊:線程

以玩家顯示器大小 進行對地圖切割:3d

哨兵羣體 MonsterGroupCell (圖中紅色虛線矩形) 也會被切割成各類 形態,而且每一個 羣體至少屬於一個地圖片元MapPiece:code

class MapPiece
{
public:
    VOID OnPlayerMoved( GamePlayer* gPlayer);

private:
    
    // 地圖片元 所擁有的 怪物羣體
    std::vector< MonsterGroupCell*> m_monsterGroupCells;    

    MapPieceBoundInfo_t             m_LeftTop;
    MapPieceBoundInfo_t             m_RightBottom;
};
BOOL  MapData::init()
{

        m_rowPieces = m_row / PIECE_SIZE + 1;
        m_colPieces = m_col / PIECE_SIZE + 1;
        m_Pieces = new MapPiece[ m_rowPieces][ m_colPieces ];
        for( INT row = 0; row < m_rowPieces; row ++ )
        {
            for( INT col = 0; col < m_colPieces; col ++)
            {
                m_Pieces[ row][ col].m_LeftTop.mapid    = m_mapid;
                m_Pieces[ row][ col].m_LeftTop.x        = col * PIECE_SIZE;
                m_Pieces[ row][ col].m_LeftTop.y        = row * PIECE_SIZE;

                m_Pieces[ row][ col].m_RightBottom.mapid    = m_mapid;
                m_Pieces[ row][ col].m_RightBottom.x        = col * PIECE_SIZE + PIECE_SIZE;
                m_Pieces[ row][ col].m_RightBottom.y        = row * PIECE_SIZE + PIECE_SIZE;
            }
        }
} // eof function init
    VOID     MapData::WhenMonstersCreated()
    { 
      // 第一部分 對怪物進行 分類顫聲道 MonsterGroupCell
        ...
       
         //第二部分: 非配各個 MonsterGroupCell 到 地圖切片上
        const INT DETECT_RANGE = 10;
            std::map< ElementType_t, MonsterGroupCell*>::const_iterator cellIter = mapMonsterGroupCells.begin();
            for( ; cellIter != mapMonsterGroupCells.end(); cellIter ++ )
            {
                MonsterGroupCell* cell = cellIter->second;
                cell->m_LeftTop.x = max( cell->m_LeftTop.x - DETECT_RANGE, 0);
                cell->m_LeftTop.y = max( cell->m_LeftTop.y - DETECT_RANGE, 0);

                cell->m_RightBottom.x = min( cell->m_RightBottom.x + DETECT_RANGE, m_col);
                cell->m_RightBottom.y = min( cell->m_RightBottom.y + DETECT_RANGE, m_row);


                for( INT cX = cell->m_LeftTop.x; cX <= cell->m_RightBottom.x; cX += PIECE_SIZE )
                {
                    for( INT cY = cell->m_LeftTop.y; cY <= cell->m_RightBottom.y; cY += PIECE_SIZE )
                    {
                        m_Pieces[ cX / PIECE_SIZE ][ cY / PIECE_SIZE ].m_monsterGroupCells.push_back(  cell );
                    }
                }
            }
    }// eof function

 引擎內至少有 兩個線程:對象

1.更新遊戲對象, 如玩家 或 怪物的屬性狀態, 諸如 breath / heartbeat / frameCome / tick ...blog

  進行 行走 , 地理位置變動.遊戲

2.管理類型性質的 管理類, 當玩家位置變動時, 通知其所在的 地圖片元 MapPiece, MapPiece 再根據 所分配的 MonsterGroupCell(s)  和 玩家位置 檢測是否進入 了 被檢測區域, 若是是, 則 通知 相應的 MonsterGroupCell(s) , 這裏有一點注意事項, 一個MonsterGroupCell 可能會過大, 範圍超過一個 MapPiece 大小, 這種 MonsterGroupCell 會受到相同的多條 玩家移動的事件 通知.另外只須要 以 玩家所在 MapPiece 爲中心的九宮格 的 九個MapPiece 事件檢測:事件

   VOID     MapData::GameObjectPositionCheck()
    {
        std::list< GamePlayer*>::const_iterator iter = m_playerList.begin();
        // 遍歷每一個 該地圖上的全部玩家
        for( ; iter != m_playerList.end(); iter ++ )
        {
            GamePlayer* gPlayer = (*iter);
            if( gPlayer->IsMoving() )
            {
                  // 玩家所屬 九宮格的中心 地圖片元
                Position_t pos = gPlayer->GetPosition();
                INT curPieceX = pos.x / PIECE_SIZE ;
                INT curPieceY = pos.y / PIECE_SIZE;

                INT checkPieceX;
                INT checkPieceY;

                //遍歷九宮格
                for( INT rowOff = -1; rowOff <= 1; rowOff ++ )
                {
                    for( INT colOff = -1; colOff <= 1; colOff ++ )
                    {
                        checkPieceX = curPieceX + colOff;
                        checkPieceY = curPieceY + rowOff;

                        if( checkPieceX >= 0 && checkPieceX < m_colPieces)
                        {
                            if( checkPieceY >= 0 && checkPieceY < m_rowPieces)
                            {
                                // 通知 地圖片元 piece, 玩家 移動了
                                MapPiece* piece = m_Pieces[ checkPieceY][ checkPieceX];
                                piece->OnPlayerMoved( gPlayer);
                            }
                        }
                    }
                }
            }
        }
    }

地圖片元 請求 所分配的 怪物羣體 MonsterGroupCell(s) 是否 玩家在其 檢測範圍內:

    VOID     MapPiece::OnPlayerMoved( GamePlayer* gPlayer)
    {
        if( m_monsterGroupCells.size() > 0 )
        {
            std::vector< MonsterGroupCell*>::const_iterator iter = m_monsterGroupCells.begin();
            for( ; iter != m_monsterGroupCells.end(); iter ++ )
            {
                (*iter)->TryDetectGameObject( gPlayer);
            }
        }
    }

地圖片元 MonsterGroupCell 根據其檢測範圍 ( 由 左上角座標 - 右下角座標 肯定), 記錄侵入者信息:

VOID     MonsterGroupCell::TryDetectGameObject( GamePlayer* gPlayer)
    {
        const Position_t& pos = gPlayer->GetPosition();
        
        if( pos.x >= m_LeftTop.x && pos.y >= m_LeftTop.y 
            &&
            pos.x <= m_RightBottom.x && pos.y <= m_RightBottom.y )
        {
            m_playerList[ gPlayer->GetGUID()] = gPlayer;
        }else{
            if( m_playerList[ gPlayer->GetGUID()] != NULL )
            {
                //標記爲離開, 但此時 仍是有該玩家的信息, 只是對象實體爲 null, 
                m_playerList[ gPlayer->GetGUID() ]= NULL;
            }
        }
    }

另外, 玩家離開後, 並非實時從 m_playerList 刪除, 而是在 其餘 較爲 不頻繁的時刻進行刪除.

在怪物的邏輯處理線程內,經過 怪物羣體 共享的 MonsterGroupCell, 檢測被標記的 玩家 是否確實在 各個具體怪物的 境界範圍內:

    VOID     Monster::HeartBeat()
    {
        if( m_sharedGroupCell->Size() > 0 )
        {
            std::map< GUID_t, GamePlayer*>::const_iterator iter = m_sharedGroupCell->m_playerList.begin();
            for( ; iter != m_sharedGroupCell->m_playerList.end(); iter ++ )
            {
                //檢測是否進入 實際 警惕範圍內
                if( FindInMyDetection( iter->second->GetPosition() ))
                {
                    // do some operation
                    // 由 ai 決定
                }
            }

        }
    }
//全局 地圖信息管理線程
extern std::vector< MapData*>  g_MapDataList;
static VOID MapDataManagerThreadCallback( VOID* pMapData)
{
    std::vector< MapData*>::const_iterator iter = g_MapDataList.begin();
    for( ; iter != g_MapDataList.end(); iter ++ )
    {
        (*iter)->GameObjectPositionCheck();
    }
}
相關文章
相關標籤/搜索