本指南全面介绍 AOI(Area of Interest)系统的架构设计、实现原理和使用方法。
AOI 系统负责管理游戏世界中的对象位置和视野关系。它将地图划分为网格(灯塔),并追踪观察者(Watcher)和被观察者(Marker)的移动,实时触发视野变化回调。
为了优化观察者频繁在灯塔边界移动导致的数据抖动(频繁的 Enter/Leave),本系统引入了 延迟离开 机制。
delayLeaveTowers 列表中,并设置一个过期时间(例如 3 秒后)。AOI.Tick(now) 方法的定期检查,观察者才会被真正从灯塔中移除。package main
import (
"time"
"f1-game/internal/algorithm/aoi/tower"
"f1-game/internal/enum"
)
func main() {
// 1. 创建 AOI 系统
aoiSys := tower.New(tower.Config{
Width: 1000,
Height: 1000,
TowerWidth: 50,
TowerHeight: 50,
TowerPointOffset: 0,
TowerViewRange: 1,
})
// 2. 设置回调函数
// 观察者进入视野
aoiSys.SetOnWatcherEnter(func(watcher *tower.Object, towers tower.Towers) {
// 通知 watcher:看见了这些 towers 里的所有 markers
// send(watcher.ID, "add", towers.Markers())
})
// 观察者移动(视野变化)
aoiSys.SetOnWatcherMove(func(watcher *tower.Object, addTowers tower.Towers, delTowers tower.Towers) {
// 通知 watcher:看见 addTowers 里的 markers
// 通知 watcher:移除 delTowers 里的 markers (延迟离开机制会确保这里只在真正需要移除时触发吗?
// 不,delTowers 是视野逻辑上的离开。物理上的数据移除由 AOI 内部管理,但业务层可以根据 addTowers/delTowers
// 决定是否立即通知客户端删除,或者相信服务器持续推送更新直到彻底断开)
//
// 通常建议:
// addTowers -> 推送 CREATE 协议
// delTowers -> 推送 DELETE 协议 (客户端立即从屏幕移除)
// * 注意:虽然客户端移除了,但在服务器端,Watcher 可能还会短暂接收到来自 delTowers 的 Update用于保持数据一致性,直到 Tick 清理。
})
// Marker 动作回调
aoiSys.SetOnMarkerEnter(func(marker *tower.Object, tower *tower.Tower) {
// 通知该 tower.watchers:有 marker 进入
})
aoiSys.SetOnMarkerMove(func(marker *tower.Object, newTower *tower.Tower, oldTower *tower.Tower) {
// 通知变动
})
aoiSys.SetOnMarkerLeave(func(marker *tower.Object, tower *tower.Tower) {
// 通知 tower.watchers:marker 离开
})
// 3. 启动 Tick 循环 (处理延迟离开清理)
ticker := time.NewTicker(1 * time.Second)
go func() {
for t := range ticker.C {
aoiSys.Tick(t.Unix())
}
}()
// 4. 业务循环
watcher := tower.NewWatcher(1001, enum.ObjectType_Player, 500, 500, 1)
aoiSys.Enter(watcher)
aoiSys.Move(1001, 600, 600)
aoiSys.Leave(1001)
}
系统提供 UpdateID 回调,允许业务层传递自定义更新 ID 和上下文。
aoiSys.SetOnMarkerUpdateID(func(marker *Object, tower *Tower, updateID uint32, funcName string) {
// 业务处理
})
aoiSys.UpdateID(marker, 100, "LevelUp")
// 创建
func New(config Config) *AOI
// 生命周期
func (p *AOI) Enter(object Object) bool
func (p *AOI) Move(objectID int64, x, y int32) bool
func (p *AOI) Leave(objectID int64)
func (p *AOI) Update(object Object) bool
// 驱动
func (p *AOI) Tick(now int64) // 必须定期调用,清理过期的延迟离开连接
// 查询
func (p *AOI) GetObject(id int64) *Object
func (p *AOI) GetTower(x, y int32) *Tower
通过 SetOn... 方法设置回调。
func (p *AOI) SetOnWatcherEnter(callback OnWatcherEnterCallback)
func (p *AOI) SetOnWatcherMove(callback OnWatcherMoveCallback)
// 注意:OnWatcherLeave 已移除,Watcher 离开 AOI 系统时直接清理,不触发特定逻辑回调(通常配合 Leave 接口自行处理)
func (p *AOI) SetOnMarkerEnter(callback OnMarkerEnterCallback)
func (p *AOI) SetOnMarkerMove(callback OnMarkerMoveCallback)
func (p *AOI) SetOnMarkerLeave(callback OnMarkerLeaveCallback)
func (p *AOI) SetOnMarkerUpdate(callback OnMarkerUpdateCallback)
func (p *AOI) SetOnMarkerUpdateID(callback OnMarkerUpdateIDCallback)