在地圖上某塊區域,有數個怪物組成的 "哨兵小組",即不會移動, 但擁有警惕視野, 如圖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(); } }