游戏中,”玩家”看到了”怪物”,怪物却没看到玩家,往前走几步,怪物发现了玩家,开始追击玩家攻击,这是如何实现的呢?
实现流程
精灵
无论是”怪物(Monster)”还是”玩家”(Role)甚至其他等等都可以被看作”精灵(Sprite)”,在游戏中 精灵都以”场景对象(SceneObj)”的形式来体现
视野的初始化是在帧更新中进行的,
AbstractWorld -> update 中 (Gamemap) map.update(_now); //世界地图刷帧
GameMap ->update 中 (ISceneObj) item.update(now)_; //场景对象刷帧
SceneObj:场景对象
对象在刷帧时 在 initAOI( )中 通过 _getAoiManager().initAOI( )_; 初始化了该场景对象的视野
public void initAOI() {
...验证
IGameMap map = owner.getMap(); //拿到场景对象当前地图
GridManager gridmanager = map.getGridManager();//拿到地图格子管理器 (视野是通过二维来实现的)
gridmanager.addSceneObj(owner);//将自己放入到视野格子坐标列表数组内
//获取地图视野长度
int width = (int) ( (int)Math.max(1, map.getVisionLength() / gridmanager.getGridw()) * gridmanager.getGridw() * 2);
//获取地图视野宽度
int height = (int) ( (int)Math.max(1, map.getVisionLength() / gridmanager.getGridh()) * gridmanager.getGridh() * 2);
//获得当前自身的格子
pos = gridmanager.getGridPos((int)owner.getX(), (int)owner.getY(), owner);
//获得当前的视野左上到右下的格子
grids = map.getGridManager()
.getDiaxgonalVertexNotFix((int)owner.getX(), (int)owner.getY(), width, height, owner);
...遍历发送
重点看
gridmanager.addSceneObj(owner);//将自己添加到视野格子坐标内
- 两个数组 protected int[ ] _grids; protected int[ ] _pos ;
pos : 场景对象当前x坐标 除 gridw,场景对象当前y坐标 除 gridh,gridw和gridh是格子的宽度,得到 角色当前的格子坐标
grids:场景对象根据 公式(开始x点 = 当前x-((地图视距/4)42)/2,结束x点 = 当前x+((地图视距/4)42)/2,y点一样)
目的 算出当前格子下,左上格子和右下格子的坐标点,取出一个对角线GridManager
protected Map<_Integer, int[]> objOldPostion = new HashMap<>( )_;
- 两个数组 protected int[ ] _grids; protected int[ ] _pos ;
1.initAOI时将场景对象 id和当前格子坐标put进入
2.checkAoiUpdate(),时,刷帧更新当前格子坐标
因为添加前先执行移除操作,这里防止并发问题加了lock锁
这里面维护了地图上的精灵,键是精灵的ID,值是地图的格子坐标,是除以 格子宽度 之后的坐标
上面算出场景对象的视野格子后,继续往下执行
doInDiagonalVertex(_int[] diagonalVertex(场景对象视野格子(上面算出的grids)), SceneObjProcessor processor(场景对象的消息处理器))
这个方法将_得到 grids 内所有的场景对象,并执行SceneObjProcessor的run方法,调用其本身的onSeeObj(obj)方法,同时,自身作为场景对象也会调用onSeeObj(obj)
你看见我,我看见你
GridManagerUseArrayList
继承自了 GridManager,在GameMap构造中创建,内维护了 sceneObjs 二维数组,数组最大值是地图的长度和宽度,获取场景对象格子坐标(obj.pos)时,都是在场景对象地图(sceneObjs)中拿到的
ISceneObj
通过消息下发实现 看见 onSeeObj(ISceneObj obj) 和 离开 onNotSeeObj(ISceneObj obj) 两个方法,作为接口,不同的场景对象可以有不同的实现方式
分析
1.通过抽象来实现不同精灵不同的视野实现,通过刷帧实现视野消息同步,通过坐标格子来确定场景对象的位置(坐标格子是根据角色的xy坐标来换算)
2.这块没理解通透,回头深刻理解了再回来补分析
脑图结构
流程图
AOI视野初始化流程
AOI刷帧消息流程
初始化后,
怪物 将视野范围内的可攻击精灵 添加进了仇恨列表(hateMap),
玩家和视野范围内的怪物 通过消息下发已经可以看到怪物,并且怪物也对玩家进行了移动同步消息下发
玩家视野范围内如果有玩家,则会触发视野事件,将玩家添加进入了自身 AOIManage eventMap 中