package mapAOI import ( aoiTower "f1-game/internal/algorithm/aoi_tower" "f1-game/internal/enum" nameRemote "f1-game/internal/name/remote" mapCall "f1-game/nodes/map/internal/call" mapTypes "f1-game/nodes/map/internal/types" "time" clog "github.com/cherry-game/cherry/logger" cactor "github.com/cherry-game/cherry/net/actor" ) // TODO 待重构:不要绑定死 actorBase 与 objectType // actorBase 实现为通用方法集合,在每一层 AOI 中做定制化调用 // 每一层 AOI 各自做实现,这样可以灵活地把多种不同的对象放在一起,比如:行军对象和军团对象 type actorBase struct { cactor.Base aoi *aoiTower.AOI aoiUpdateTime time.Duration objectType enum.ObjectType printLog bool } func newActorAOIBase(objectType enum.ObjectType, aoi *aoiTower.AOI, aoiUpdateTime time.Duration) actorBase { return actorBase{ aoi: aoi, aoiUpdateTime: aoiUpdateTime, objectType: objectType, } } func (p *actorBase) OnInit() { p.Remote().Register(nameRemote.MapAOI_Enter, p.enter) p.Remote().Register(nameRemote.MapAOI_Move, p.move) p.Remote().Register(nameRemote.MapAOI_Leave, p.leave) p.Remote().Register(nameRemote.MapAOI_Update, p.update) p.Timer().Add(p.aoiUpdateTime, p.aoiUpdate) p.initAOIFuncs() } func (p *actorBase) setPrintLog(printLog bool) { p.printLog = printLog } // enter 玩家登录进入地图 func (p *actorBase) enter(req *mapTypes.AOIRequest) { if req.IsMarker() && req.ObjectType != p.objectType { return } object := aoiTower.NewObject(req.ObjectID, req.ObjectType, req.X, req.Y, req.IsWatcher(), req.IsMarker(), req.OwnerID()) p.aoi.Enter(object) if p.printLog { clog.Debugf("[enter %s] object = {%s}", enum.GetObjectTypeName(p.objectType), object.Info()) } } // move 玩家拖动屏幕 func (p *actorBase) move(req *mapTypes.AOIRequest) { if req.ObjectType != enum.ObjectType_Player && req.ObjectType != p.objectType { return } p.aoi.Move(req.ObjectID, req.X, req.Y, time.Now().Unix()) if p.printLog { clog.Debugf("[move %s] req = {%v}", enum.GetObjectTypeName(p.objectType), req) } } // leave 玩家下线离开 func (p *actorBase) leave(objectID int64) { // TODO 需要判断,待改进 if p.aoi.GetObject(objectID) == nil { return } p.aoi.Leave(objectID) if p.printLog { clog.Debugf("[leave %s] object = %d", enum.GetObjectTypeName(p.objectType), objectID) } } func (p *actorBase) update(req *mapTypes.AOIRequest) { if req.ObjectType == enum.ObjectType_Player || req.ObjectType != p.objectType { return } object := p.aoi.GetObject(req.ObjectID) if object == nil { return } p.aoi.UpdateID(*object, req.UpdateID(), req.FuncName()) if p.printLog { clog.Debugf("[update %s] object = %d", enum.GetObjectTypeName(p.objectType), req.ObjectID) } } func (p *actorBase) initAOIFuncs() { p.aoi.OnMarkerEnter = p.onMarkerEnter p.aoi.OnMarkerMove = p.onMarkerMove p.aoi.OnMarkerLeave = p.onMarkerLeave p.aoi.OnMarkerUpdateID = p.onMarkerUpdateID p.aoi.OnWatcherEnter = p.onWatcherEnter p.aoi.OnWatcherMove = p.onWatcherMove p.aoi.OnTowerExpire = p.onTowerExpire } func (p *actorBase) aoiUpdate() { p.aoi.Tick(time.Now().Unix()) } // marker进入的时候通知灯塔内所有watcher func (p *actorBase) onMarkerEnter(marker *aoiTower.Object, tower *aoiTower.Tower) { clog.Debugf("[onMarkerEnter] marker = (%v %s) towerId:%d", marker.ObjectID, enum.GetObjectTypeName(marker.ObjectType), tower.GetID()) if tower.GetWatchers().IsEmpty() { return } mapCall.Logic.AOIMarkerEnterView(mapTypes.NewAOIMarkerEnterView(marker, tower.GetWatchers())) } // marker移动 func (p *actorBase) onMarkerMove(marker *aoiTower.Object, newTower *aoiTower.Tower, oldTower *aoiTower.Tower) { clog.Debugf("[onMarkerMove] marker = (%v %s) newTowerId = %d oldTowerId = %d", marker.ObjectID, enum.GetObjectTypeName(marker.ObjectType), newTower.GetID(), oldTower.GetID()) enterWatchers := aoiTower.Objects{} newTower.GetWatchers().Range(func(watcher *aoiTower.Object) { if !oldTower.GetWatchers().Contains(watcher.ObjectID) { // 不在watcher的视野内,视为新加入的对象 enterWatchers.Add(watcher) } }) if !enterWatchers.IsEmpty() { mapCall.Logic.AOIMarkerEnterView(mapTypes.NewAOIMarkerEnterView(marker, enterWatchers)) } leaveWatchers := aoiTower.Objects{} oldTower.GetWatchers().Range(func(watcher *aoiTower.Object) { if !newTower.GetWatchers().Contains(watcher.ObjectID) { // 移出了视野 leaveWatchers.Add(watcher) } }) if !leaveWatchers.IsEmpty() { mapCall.Logic.AOIMarkerLeaveView(mapTypes.NewAOIMarkerLeaveView(marker, leaveWatchers)) } } // marker退出的时候通知灯塔内所有watcher func (p *actorBase) onMarkerLeave(marker *aoiTower.Object, tower *aoiTower.Tower) { clog.Debugf("[onMarkerLeave] marker = (%v %s) towerId = %d", marker.ObjectID, enum.GetObjectTypeName(marker.ObjectType), tower.GetID()) mapCall.Logic.AOIMarkerDespawn(mapTypes.NewAOIMarkerDespawn(marker, tower.GetWatchers())) } // marker更新通知 func (p *actorBase) onMarkerUpdateID(marker *aoiTower.Object, tower *aoiTower.Tower, updateID uint32, funcName string) { clog.Debugf("[onMarkerUpdateID] marker = (%v %s) towerId = %d updateID = %d funcName = %s", marker.ObjectID, enum.GetObjectTypeName(marker.ObjectType), tower.GetID(), updateID, funcName) mapCall.Logic.AOIUpdate(funcName, mapTypes.NewAOIMarkerUpdate(marker, tower.GetWatchers(), updateID)) } // watcher进入的时候推送范围内所有marker func (p *actorBase) onWatcherEnter(watcher *aoiTower.Object, towers aoiTower.Towers) { towers.Range(func(tower *aoiTower.Tower) { if !tower.GetMarkers().IsEmpty() { mapCall.Logic.AOIMarkerEnterView(mapTypes.NewBatchAOMarkerEnterView(tower.GetMarkers(), p.objectType, watcher.OwnerID())) } }) } // watcher移动时的新灯塔内对象全视为新加入对象,因为延迟删除所以不需要处理oldTowers func (p *actorBase) onWatcherMove(watcher *aoiTower.Object, newTowers aoiTower.Towers, oldTowers aoiTower.Towers) { newTowers.Range(func(tower *aoiTower.Tower) { if !tower.GetMarkers().IsEmpty() { mapCall.Logic.AOIMarkerEnterView(mapTypes.NewBatchAOMarkerEnterView(tower.GetMarkers(), p.objectType, watcher.OwnerID())) } }) } // 灯塔过期 func (p *actorBase) onTowerExpire(watcher *aoiTower.Object, tower *aoiTower.Tower) { clog.Debugf("[onTowerExpire] watcher = %v towerId = %d", watcher.ObjectID, tower.GetID()) if tower.GetMarkers().IsEmpty() { return } // 移出了视野 mapCall.Logic.AOIMarkerLeaveView(mapTypes.NewBatchAOIMarkerLeaveView(tower.GetMarkers(), p.objectType, watcher.OwnerID())) }