游戏服务端 - AOI九宫格算法
下面简述内容,只针对平面上的简易场景。我们将平面上的场景分为一个个格子(Grid),场景管理所有的Grid。如下(假设场景的长宽均为20,每个格子宽高定义为1):
其中可分为400个Grid,即如果一个场景每个Grid的宽高均为1(即每个单元unitSizeX为1,unitSizeY为1),那么一个场景需要同时管理400个Grid。
TIPS:每个Grid中可能有多个物体(角色),目前暂定场景中都是玩家对象,即为网络游戏,均为在线玩家角色(AOI对象)。
Grid对象
作为服务端AOI算法,那么我们应当知道,在什么情况下应该通知附近的Grid哪个AOI对象消失,哪个AOI对象出现、哪个AOI对象状态发生改变(主要针对状态同步,当状态改变时时通知)。以及对于状态改变的玩家来说,在它自己的视野里,哪些Grid的AOI即将在视野内消失,哪些Grid的AOI即将在视野内出现。也就是说,这里有一个一对多和多对一的概念,对于其它Grid中的AOI,我们应该告知它们当前状态发生改变的AOI即将消失、即将出现、状态改变,也就是多对一,多个Grid中的AOI关注一个AOI。而对于当前状态发生改变的AOI,它自己视野内有哪些Grid中的AOI即将消失、出现,也就是一个AOI关注多个Grid中的AOI,一对多。这里指的状态改变包括从一个Grid移动到另外一个Grid、即使没有走出当前Grid,但是从停止到移动等这类改变均统称为状态改变。
再给出示例之前,需要先知道如果获取一个AOI的视野范围?
bool _GetAOI(int32_t centerGridIndex,
std::vector<int32_t>& outPut) {
if (centerGridIndex == -1) {
return false;
}
//视野方向:从右方逆时针旋转,共八个方向
int32_t col = m_role->GetScene()->GetCol(); //获取列,这里为20
int deltaIndexArr[8] = {
1, -col + 1, -col, -col - 1, -1, col - 1, col, col + 1 };
//获取实体 AOI
outPut.clear();
outPut.push_back(centerGridIndex); //包括自身在内的九宫格
for (int i = 0; i < 8; i++) {
outPut.push_back(centerGridIndex + deltaIndexArr[i]);
}
return true;
}
通过上述我们可以获取一个AOI的视野范围(包括自己所在Grid)。
现假定一个AOI从Grid为21的格子向42的位置移动。那么该AOI旧的视野范围为0、1、2、20、21、22、40、41、42。新的视野范围为21、22、23、41、42、43、61、62、63。那么对于其它Grid中的AOI来说,我们应该通知它们(包括0、1、2、20、40格子内的AOI)当前AOI即将消失。同时通知(包括23、43、61、62、63格子内的AOI)当前AOI即将出现。针对当前AOI来说,它的视野范围也有变化,那就是Grid为0、1、2、20、40格子内的AOI即将消失,Grid为23、43、61、62、63格子内的AOI即将出现。那么对于Grid为21、22、41、42的格子,如果当前AOI没有发生其它的状态改变,那么是不用通知的。因为对于这些Grid中的AOI,当前AOI意味这不改变状态。
下面给出通过目的地Grid,求三个队列状态(即将出现、即将消失、状态改变)的算法。
//destGridIndex 目的地Grid,output为输入输出值
bool GetChangedAOIs(int32_t destGridIndex,
std::vector<std::vector<int32_t>>& outPut) {
outPut.clear();
outPut.resize(3);
std::vector<int32_t>& appearAOIArr =
outPut[(int)AOI_STATUS::AOI_APPEAR];
std::vector<int32_t>& disappearAOIArr =
outPut[(int)AOI_STATUS::AOI_DISAPPEAR];
std::vector<int32_t>& unChangeAOIArr =
outPut[(int)AOI_STATUS::AOI_UNCHANGE];
int32_t oldGridIndex = m_centerGridIndex;
//获取实体 旧AOI
std::vector<int32_t> oldAOIArr;
//获取实体 新AOI
std::vector<int32_t> newAOIArr;
if (oldGridIndex >= 0) {
_GetAOI(oldGridIndex, oldAOIArr);
_GetAOI(destGridIndex, newAOIArr);
}
std::sort(oldAOIArr.begin(), oldAOIArr.end());
std::sort(newAOIArr.begin(), newAOIArr.end());
//求对用的AOI区域
int32_t indexOld = 0;
int32_t indexNew = 0;
while (indexOld < oldAOIArr.size() && indexNew < newAOIArr.size()) {
//两个AOI的交集,即不变的AOI区域
if (oldAOIArr[indexOld] == newAOIArr[indexNew]) {
unChangeAOIArr.push_back(newAOIArr[indexNew]);
++indexOld;
++indexNew;
}
// oldAOI特有的区域,即需要通知的AOI,告知即将有AOI实体出现
else if (oldAOIArr[indexOld] < newAOIArr[indexNew]) {
appearAOIArr.push_back(newAOIArr[indexNew]);
indexNew++;
}
else if (oldAOIArr[indexOld] > newAOIArr[indexNew]) {
disappearAOIArr.push_back(oldAOIArr[indexOld]);
indexOld++;
}
//将剩下部分加入对应队列中
while (indexNew < newAOIArr.size()) {
appearAOIArr.push_back(newAOIArr[indexNew]);
++indexNew;
}
while (indexOld < oldAOIArr.size()) {
disappearAOIArr.push_back(oldAOIArr[indexOld]);
++indexOld;
}
}
return true;
}
AOI对象
在当前示例中,一个AOI对象实际上就是一个角色,那么如何通过角色坐标获取到它应当位于哪个Grid中呢?
int32_t index = (int)(pos.X / m_unitSizeX) + m_col * (int)(pos.Y / m_unitSizeY);
pos表示角色的平面坐标。m_unitSizeX、m_unitSizeY对应上文已经阐述,即为1。m_col为列长(宽,20)。假如当前有一个角色的坐标为(2.8,1.9),那么根据上述公式为:index = (int)(2.8 / 1) + 20 * (1.9 / 1) = 22,即它位于第22个Grid中(根据常识也可验证,这么计算是正确的)。
通过比较它即将前往的位置和当前位置,即可知是否改变Grid。
bool _IsChangeGridIndex(const struct POSITION& oldPos,
const struct POSITION& newPos){
int32_t oldGridIndex = _GetGridIndex(oldPos);
int32_t newGridIndex = _GetGridIndex(newPos);
return (oldGridIndex != newGridIndex);
}
完整实例
实现完整实例如下(仅包含AOI相关代码,仅供参考):
Scene.h
//管理所有加入场景的角色(一个玩家对应一个角色)
class Scene {
public:
Scene() {}
~Scene() {}
bool Init(int32_t width, int32_t length);
bool UnInit();
//场景逻辑帧更新
bool UpdateScene();
//角色加入场景
bool AddRole(class Player* player, class Role* role);
bool DelteRole(class Role* role);
int32_t GetCol();
int32_t GetRow();
// AOI操作, 位置同步AOI
// isStatusChange = true时,表示状态改变,即使不跨Grid也广播信息
// isStatusChange = false时,表示状态不改变,这时跨Grid或者达到边缘时广播信息
bool MoveSyncAOI(class Role* role,
const struct POSITION& newPos, bool isStatusChange);
bool EnterGrid(class Role* role);
bool ExitGrid(class Role* role);
private:
//角色退出场景
bool _OnDeleteRole(Topicype type, void* userData);
//AOI操作
//查看是否改变grid,不变则返回false,改变则返回true
bool _IsChangeGridIndex(const struct POSITION& oldPos,
const struct POSITION& newPos);
//获取坐标所在的Grid位置
int32_t _GetGridIndex(const struct POSITION& pos);
//进入一个Grid
bool _EnterGrid(class Role* role, int32_t gridIndex);
//从一个Grid退出
bool _ExitGrid(class Role* role);
//区域事件广播
bool _OtherAOIAnnounce();
//自身视野变化广播
bool _SelfAOIAnnounce();
private:
class RoleMgr* m_roleMgr; //角色管理器
//AOI模块
std::vector<Grid*> m_gridArrs;
int32_t m_unitSizeX;
int32_t m_unitSizeY;
int32_t m_col;
int32_t m_row;
//对AOI区域队列进行广播,这里表示多个AOI区域对一个Role的观察,多对一
std::vector<std::pair<
std::vector<int32_t>, class Role*>> m_enterOtherAOISightArr;
std::vector<std::pair<
std::vector<int32_t>, int64_t>> m_exitOtherAOISightArr;
std::vector<std::pair<
std::vector<int32_t>, class Role*>> m_statusChangeAOISightArr;
//更新自身的AOI,即AOI自身角度看哪些AOI消失、AOI出现,一对多
std::vector<std::pair<
class Role*, std::vector<int32_t>>> m_enterSelfAOISightArr;
std::vector<std::pair<
class Role*, std::vector<int32_t>>> m_exitSelfAOISightArr;
};
Scene.cpp
#include "Scene.h"
bool Scene::Init(int32_t width, int32_t length) {
m_roleMgr = (RoleMgr*)MALLOC(sizeof(RoleMgr));
assert(NULL != m_roleMgr);
new(m_roleMgr) RoleMgr();
m_roleMgr->Init(this);
//初始化AOI
m_unitSizeX = 1;
m_unitSizeY = 1;
m_row = length / m_unitSizeY;
m_col = width / m_unitSizeX;
for (int i = 0; i < m_row* m_col; i++) {
Grid* grid = (Grid*)MALLOC(sizeof(Grid));
assert(NULL != grid);
new(grid) Grid();
grid->Init(i);
m_gridArrs.push_back(grid);
}
m_enterOtherAOISightArr.clear();
m_exitOtherAOISightArr.clear();
m_statusChangeAOISightArr.clear();
m_enterSelfAOISightArr.clear();
m_exitSelfAOISightArr.clear();
result = true;
Exit:
return result;
}
bool Scene::UnInit() {
if (m_roleMgr) {
m_roleMgr->UnInit();
Free(m_roleMgr);
m_roleMgr = nullptr;
}
//释放AOI队列
for (auto& grid : m_gridArrs) {
grid->UnInit();
Free(grid);
}
m_gridArrs.clear();
m_enterOtherAOISightArr.clear();
m_exitOtherAOISightArr.clear();
m_statusChangeAOISightArr.clear();
m_enterSelfAOISightArr.clear();
m_exitSelfAOISightArr.clear();
return true;
}
bool Scene::UpdateScene() {
//移动同步
m_roleMgr->UpdateRoles();
//处理AOI队列
_OtherAOIAnnounce();
_SelfAOIAnnounce();
return true;
}
bool Scene::AddRole(Player* player, Role* role) {
//加入场景
m_roleMgr->AddRole(player, role);
//进入AOI
bool nRet = EnterGrid(role);
return nRet;
}
//事件系统通知
bool Scene::DeleteRole(class Role* role) {
ExitGrid(role);
//退出场景,删除role
m_roleMgr->DeleteRole(role);
return true;
}
int32_t Scene::GetCol() {
return m_col;
}
int32_t Scene::GetRow() {
return m_row;
}
bool Scene::MoveSyncAOI(Role* role,
const POSITION& newPos, bool isStatusChange) {
bool nRet = _IsChangeGridIndex(role->GetRoleStatus()->POS, newPos);
//位置合法且Grid改变,这时需要通知对该区域感兴趣的AOI
if (newPos.X >= 0 && newPos.X < m_sceneMap.GetLength() &&
newPos.Y >= 0 && newPos.Y < m_sceneMap.GetWidth() && nRet) {
int32_t newGridIndex = _GetGridIndex(newPos);
if (newGridIndex >= 0 && newGridIndex < m_gridArrs.size()) {
_ExitGrid(role);
_EnterGrid(role, newGridIndex);
//更新坐标
//role->SetPos(newPos.X, newPos.Y);
//获取即将出现、即将消息、不变的AOI区域
std::vector<std::vector<int32_t>> aoiArrs;
role->GetChangedAOIs(newGridIndex, aoiArrs);
//加入即将出现队列
m_enterOtherAOISightArr.push_back(
std::make_pair(
aoiArrs[(int32_t)AOI_STATUS::AOI_APPEAR], role));
//加入即将消失队列
m_exitOtherAOISightArr.push_back(
std::make_pair(
aoiArrs[(int32_t)AOI_STATUS::AOI_DISAPPEAR],
role->GetRoleID()));
//加入状态改变队列
m_statusChangeAOISightArr.push_back(
std::make_pair(
aoiArrs[(int32_t)AOI_STATUS::AOI_UNCHANGE], role));
//更新自身的AOI,即AOI自身角度看哪些AOI消失、AOI出现,一对多
m_enterSelfAOISightArr.push_back(
std::make_pair(
role, aoiArrs[(int32_t)AOI_STATUS::AOI_APPEAR]));
m_exitSelfAOISightArr.push_back(
std::make_pair(
role,
aoiArrs[(int32_t)AOI_STATUS::AOI_DISAPPEAR]));
role->UpdateSelfAOI(newGridIndex);
}
}
//Grid未改变,此时如果状态发生改变则加入状态改变队列中
else {
//更新坐标
//role->SetPos(newPos.X, newPos.Y);
if (isStatusChange) {
//加入状态改变队列
m_statusChangeAOISightArr.push_back(
std::make_pair(role->GetAOI(), role));
}
}
return true;
}
bool Scene::EnterGrid(Role* role) {
//AOI 进入场景
//获取加入场景角色GridIndex
int32_t gridIndex = _GetGridIndex(role->GetRoleStatus()->POS);
bool nRet = _EnterGrid(role, gridIndex);
if (nRet) {
//更新实体自身的AOI
role->UpdateSelfAOI(gridIndex);
//加入即将出现队列
const std::vector<int32_t>& gridArrs = role->GetAOI();
m_enterOtherAOISightArr.push_back(
std::make_pair(gridArrs, role));
//更新自身AOI队列
m_enterSelfAOISightArr.push_back(
std::make_pair(role, gridArrs));
}
return nRet;
}
bool Scene::ExitGrid(Role* role) {
//AOI 退出场景
bool nRet = _ExitGrid(role);
if (nRet) {
//加入即将消失队列
const std::vector<int32_t>& gridArrs = role->GetAOI();
m_exitOtherAOISightArr.push_back(
std::make_pair(gridArrs, role->GetRoleID()));
//更新自身AOI
role->UpdateSelfAOI(-1);
}
return nRet;
}
bool Scene::_IsChangeGridIndex(const POSITION& oldPos,
const POSITION& newPos) {
int32_t oldGridIndex = _GetGridIndex(oldPos);
int32_t newGridIndex = _GetGridIndex(newPos);
return (oldGridIndex != newGridIndex);
}
int32_t Scene::_GetGridIndex(const POSITION& pos) {
int32_t index = (int)(pos.X / m_unitSizeX) +
m_col * (int)(pos.Y / m_unitSizeY);
return index;
}
bool Scene::_EnterGrid(Role* role, int32_t gridIndex) {
assert(role != nullptr);
bool result = false;
if (gridIndex >= 0 && gridIndex < m_gridArrs.size()) {
result = m_gridArrs[gridIndex]->AddEntity(role);
}
return result;
}
bool Scene::_ExitGrid(Role* role) {
assert(nullptr != role);
bool result = false;
int32_t gridIndex = _GetGridIndex(role->GetRoleStatus()->POS);
if (gridIndex >= 0 && gridIndex < m_gridArrs.size()) {
result = m_gridArrs[gridIndex]->RemoveEntity(role);
}
return result;
}
bool Scene::_OtherAOIAnnounce() {
//进入视野
for (auto& gridList : m_enterOtherAOISightArr) {
//一个角色即将进入某些AOI的视野
for (auto& gridIndex : gridList.first) {
if (gridIndex >= 0 && gridIndex < m_gridArrs.size()) {
m_gridArrs[gridIndex]->OtherEntityEnterAnnounce(
gridList.second);
}
}
}
m_enterOtherAOISightArr.clear();
//离开视野
for (auto& gridList : m_exitOtherAOISightArr) {
//一个角色即将离开某些AOI的视野
for (auto& gridIndex : gridList.first) {
if (gridIndex >= 0 && gridIndex < m_gridArrs.size()) {
m_gridArrs[gridIndex]->OtherEntityExitAnnounce(
gridList.second);
}
}
}
m_exitOtherAOISightArr.clear();
//状态改变
for (auto& gridList : m_statusChangeAOISightArr) {
for (auto& gridIndex : gridList.first) {
if (gridIndex >= 0 && gridIndex < m_gridArrs.size()) {
m_gridArrs[gridIndex]->EntityStatusChangeAnnounce(
gridList.second);
}
}
}
m_statusChangeAOISightArr.clear();
return true;
}
bool Scene::_SelfAOIAnnounce() {
//进入视野
for (auto& gridList : m_enterSelfAOISightArr) {
//一个角色自身AOI的视野即将出现哪些Grid
for (auto& gridIndex : gridList.second) {
if (gridIndex >= 0 && gridIndex < m_gridArrs.size()) {
m_gridArrs[gridIndex]->NotifyEntityEnter(
gridList.first);
}
}
}
m_enterSelfAOISightArr.clear();
//离开视野
for (auto& gridList : m_exitSelfAOISightArr) {
//一个角色自身AOI的视野即将消失哪些Grid
for (auto& gridIndex : gridList.second) {
if (gridIndex >= 0 && gridIndex < m_gridArrs.size()) {
m_gridArrs[gridIndex]->NotifyEntityExit(
gridList.first);
}
}
}
m_exitSelfAOISightArr.clear();
return true;
}
Grid.h
#pragma once
#include <unordered_set>
#include <assert.h>
#include "../Role.h"
class Grid {
public:
Grid() {}
~Grid() {}
bool Init(int32_t gridIndex);
bool UnInit();
bool AddEntity(GAME_SERVICE::Role* role);
bool RemoveEntity(GAME_SERVICE::Role* role);
//多对一
bool OtherEntityEnterAnnounce(GAME_SERVICE::Role* role);
bool OtherEntityExitAnnounce(int64_t roleID);
bool EntityStatusChangeAnnounce(GAME_SERVICE::Role* role);
//一对多
bool NotifyEntityEnter(GAME_SERVICE::Role* role);
bool NotifyEntityExit(GAME_SERVICE::Role* role);
private:
bool _EnterOrStatusChangeAnnounce(GAME_SERVICE::Role* role);
private:
int32_t m_gridIndex;
std::unordered_set<GAME_SERVICE::Role*> m_entitySet; //该grid上存在的实体
};
Grid.cpp
#include "Grid.h"
bool Grid::Init(int32_t gridIndex) {
assert(gridIndex >= 0);
m_gridIndex = gridIndex;
m_entitySet.clear();
return true;
}
bool Grid::UnInit() {
m_entitySet.clear();
return true;
}
bool Grid::AddEntity(GAME_SERVICE::Role* role) {
assert(role != nullptr);
auto nRet = m_entitySet.insert(role);
return nRet.second;
}
bool Grid::RemoveEntity(GAME_SERVICE::Role* role) {
assert(role != nullptr);
m_entitySet.erase(role);
return true;
}
bool Grid::OtherEntityEnterAnnounce(GAME_SERVICE::Role* role) {
return _EnterOrStatusChangeAnnounce(role);
}
bool Grid::OtherEntityExitAnnounce(int64_t roleID) {
TCCamp::ExitSceneAnnounce exitAnnounce;
exitAnnounce.add_roleids(roleID);
for (auto& other : m_entitySet) {
other->SendMsg(
TCCamp::SERVER_CMD::SERVER_ROLE_EXIT_SCENE_ANNOUNCE,
&exitAnnounce);
}
return true;
}
bool Grid::EntityStatusChangeAnnounce(GAME_SERVICE::Role* role) {
return _EnterOrStatusChangeAnnounce(role);
}
bool Grid::NotifyEntityEnter(GAME_SERVICE::Role* role) {
TCCamp::MoveSyncAnnounce moveAnnounce;
TCCamp::PBRoleMoveSyncData* pbRoleMoveSyncData = nullptr;
for (auto& other : m_entitySet) {
if (other->GetRoleID() != role->GetRoleID()) {
pbRoleMoveSyncData = moveAnnounce.add_datas();
pbRoleMoveSyncData->set_roleid(other->GetRoleID());
other->RoleStatusConvertToPBObj(
pbRoleMoveSyncData->mutable_status());
}
}
role->SendMsg(
TCCamp::SERVER_CMD::SERVER_ROLE_MOVE_SYNC_ANNOUNCE,
&moveAnnounce);
return true;
}
bool Grid::NotifyEntityExit(GAME_SERVICE::Role* role) {
TCCamp::ExitSceneAnnounce exitAnnounce;
for (auto& other : m_entitySet) {
if (other->GetRoleID() != role->GetRoleID()) {
exitAnnounce.add_roleids(other->GetRoleID());
}
}
role->SendMsg(
TCCamp::SERVER_CMD::SERVER_ROLE_EXIT_SCENE_ANNOUNCE,
&exitAnnounce);
return true;
}
bool Grid::_EnterOrStatusChangeAnnounce(GAME_SERVICE::Role* role) {
TCCamp::MoveSyncAnnounce moveAnnounce;
TCCamp::PBRoleMoveSyncData* pbRoleMoveSyncData = nullptr;
pbRoleMoveSyncData = moveAnnounce.add_datas();
pbRoleMoveSyncData->set_roleid(role->GetRoleID());
role->RoleStatusConvertToPBObj(
pbRoleMoveSyncData->mutable_status());
for (auto& other : m_entitySet) {
other->SendMsg(
TCCamp::SERVER_CMD::SERVER_ROLE_MOVE_SYNC_ANNOUNCE,
&moveAnnounce);
}
return true;
}
AOI.h
#pragma once
//对当前区域感兴趣的格子(Grid),该区域对它们来说的状态
enum class AOI_STATUS {
AOI_APPEAR,
AOI_DISAPPEAR,
AOI_UNCHANGE,
};
class AOI {
public:
AOI() {}
~AOI() {}
bool Init(class Role* role);
bool UnInit();
//更新实体AOI(通知场景 更新实体能看到的其它实体信息)
bool UpdateAOI(int32_t destGridIndex);
//获取当前AOI区域
const std::vector<int32_t>& GetAOI();
// 获取实体,包括即将出现、即将消失、状态不变的AOI
// TIPS:(不保证gridIndex合法,后续使用需判断合法性)
bool GetChangedAOIs(int32_t destGridIndex,
std::vector<std::vector<int32_t>>& outPut);
private:
// 获取以当前场景的centerGridIndex为中心的AOI区域
// TIPS:(不保证gridIndex合法,后续使用需判断合法性)
bool _GetAOI(int32_t centerGridIndex, std::vector<int32_t>& outPut);
private:
int32_t m_centerGridIndex;
Role* m_role;
std::vector<int32_t> m_aoiGridIndexArr;
};
AOI.cpp
#include "AOI.h"
#include "../Scene.h"
#include "../Role.h"
bool AOI::Init(Role* role) {
assert(nullptr != role);
m_centerGridIndex = -1;
m_role = role;
m_aoiGridIndexArr.clear();
return true;
}
bool AOI::UnInit() {
m_aoiGridIndexArr.clear();
m_centerGridIndex = -1;
m_role = nullptr;
return true;
}
bool AOI::UpdateAOI(int32_t destGridIndex) {
// 更新aoi
m_centerGridIndex = destGridIndex;
m_aoiGridIndexArr.clear();
_GetAOI(m_centerGridIndex, m_aoiGridIndexArr);
return true;
}
const std::vector<int32_t>& AOI::GetAOI() {
return m_aoiGridIndexArr;
}
bool AOI::GetChangedAOIs(int32_t destGridIndex,
std::vector<std::vector<int32_t>>& outPut) {
bool result = false;
outPut.clear();
outPut.resize(3);
std::vector<int32_t>& appearAOIArr =
outPut[(int)AOI_STATUS::AOI_APPEAR];
std::vector<int32_t>& disappearAOIArr =
outPut[(int)AOI_STATUS::AOI_DISAPPEAR];
std::vector<int32_t>& unChangeAOIArr =
outPut[(int)AOI_STATUS::AOI_UNCHANGE];
int32_t oldGridIndex = m_centerGridIndex;
//获取实体 旧AOI
std::vector<int32_t> oldAOIArr;
//获取实体 新AOI
std::vector<int32_t> newAOIArr;
if (oldGridIndex >= 0) {
_GetAOI(oldGridIndex, oldAOIArr);
_GetAOI(destGridIndex, newAOIArr);
}
std::sort(oldAOIArr.begin(), oldAOIArr.end());
std::sort(newAOIArr.begin(), newAOIArr.end());
//求对用的AOI区域
int32_t indexOld = 0;
int32_t indexNew = 0;
while (indexOld < oldAOIArr.size() && indexNew < newAOIArr.size()) {
//两个AOI的交集,即不变的AOI区域
if (oldAOIArr[indexOld] == newAOIArr[indexNew]) {
unChangeAOIArr.push_back(newAOIArr[indexNew]);
++indexOld;
++indexNew;
}
// oldAOI特有的区域,即需要通知的AOI,告知即将有AOI实体出现
else if (oldAOIArr[indexOld] < newAOIArr[indexNew]) {
appearAOIArr.push_back(newAOIArr[indexNew]);
indexNew++;
}
else if (oldAOIArr[indexOld] > newAOIArr[indexNew]) {
disappearAOIArr.push_back(oldAOIArr[indexOld]);
indexOld++;
}
//将剩下部分加入对应队列中
while (indexNew < newAOIArr.size()) {
appearAOIArr.push_back(newAOIArr[indexNew]);
++indexNew;
}
while (indexOld < oldAOIArr.size()) {
disappearAOIArr.push_back(oldAOIArr[indexOld]);
++indexOld;
}
}
return true;
}
bool AOI::_GetAOI(int32_t centerGridIndex,
std::vector<int32_t>& outPut) {
if (centerGridIndex == -1) {
return false;
}
//视野方向:从右方逆时针旋转,共八个方向
int32_t col = m_role->GetScene()->GetCol();
int deltaIndexArr[8] = {
1, -col + 1, -col, -col - 1, -1, col - 1, col, col + 1 };
//获取实体 AOI
outPut.clear();
outPut.push_back(centerGridIndex); //包括自身在内的九宫格
for (int i = 0; i < 8; i++) {
outPut.push_back(centerGridIndex + deltaIndexArr[i]);
}
return true;
}