在地图上某块区域,有数个怪物组成的 "哨兵小组",即不会移动, 但拥有警惕视野, 如图1.api
这5个哨兵是不会移动, 有站立点可肯定一个最小外凸包围圈, 如图2;再产生最小矩形包围圈,如图3.this
typedef structPosition_t{
INT mapid;
INT x;
INT y;
}Position_t, MapPieceBoundInfo_t;
typedef UINT ElementType_t;
typedef UINT GUID_t;classGamePlayer
{public:
BOOL IsMoving();
Position_t GetPosition();
GUID_t GetGUID();
};
classMonster
{public:
ElementType_t ElementType();
Position_t GetPosition();
BOOL FindInMyDetection(const Position_t&pos);
VOID HeartBeat();private:
MonsterGroupCell*m_sharedGroupCell;
};
typedef structMonsterGroupCell
{//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( ){returnm_playerList.size(); }
VOID TryDetectGameObject( GamePlayer*gPlayer);
VOID TickClearInvalidGameObjectRecord( );
};
按照警惕视野(r)扩宽后, 这个怪物群体的"警惕矩形"将变成 如图4.spa
classMapData{public:const INT PIECE_SIZE = 20;
BOOL init();//进行地图切割
VOID WhenMonstersCreated()
{//怪物建立好后, 进行群组分类, 即产生最大包围矩形//第一部分 对怪物进行 分类颤声道 MonsterGroupCell
if( m_monsterList.size() > 0)
{
std::mapmapMonsterGroupCells;
std::vector::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 = newMonsterGroupCell;
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::listm_playerList;
std::vectorm_monsterList;
MapPiece**m_Pieces;
INT m_mapid;
INT m_row ;
INT m_col ;
INT m_rowPieces;
INT m_colPieces;
};
一张地图上有不一样的 怪物小组(此处都做为不可移动的哨兵), 有 不少不一样形状,可能会相互重叠:线程
以玩家显示器大小 进行对地图切割:3d
哨兵群体 MonsterGroupCell (图中红色虚线矩形) 也会被切割成各类 形态,而且每一个 群体至少属于一个地图片元MapPiece:code
classMapPiece
{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= newMapPiece[ 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
{if( checkPieceY >= 0 && checkPieceY
{//通知 地图片元 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();
}
}