服务器怪物位置检测,地图分割,怪物群体 检测 侵入者

在地图上某块区域,有数个怪物组成的 "哨兵小组",即不会移动, 但拥有警惕视野, 如图1.api

33a21e7ca24a898b264bb8d08be4c598.png

这5个哨兵是不会移动, 有站立点可肯定一个最小外凸包围圈, 如图2;再产生最小矩形包围圈,如图3.this

b2684b4897fa549e77dec26e12d8e073.png

4d3aa6ef155f083b05ac78e3bb49fea1.png

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

39e5afa5f083455b7c255184129d3957.png

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;

};

一张地图上有不一样的 怪物小组(此处都做为不可移动的哨兵), 有 不少不一样形状,可能会相互重叠:线程

9a85270cdfd59c146a5d73babd7648c6.png

以玩家显示器大小 进行对地图切割:3d

a4186d6907263e33bd3dd6b35c437394.png

哨兵群体 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();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值