Blog·Studio
文章系列日历归档关于搜索
Blog·Studio

一个记录思考、笔记与作品的技术博客。

Connect

© 2026 · Blog Studio

鄂ICP备19019526号

crafted with care

stay curious ✦

  1. 文章
  2. ›AOI 兴趣区域系统工程 2026:从九宫格、十字链表到万人同屏的统一架构

Index

  • 一、问题的提出:AOI 在多人游戏后端的不可替代位置
  • 二、形式化:AOI 的几何与拓扑基础 + 复杂度边界
  • 三、主体 1:九宫格实现 — 最朴素也最广泛
  • 四、主体 2:灯塔算法与十字链表 — 动态密度场景
  • 五、主体 3:四叉树 / R-tree / KD-tree — 大世界稀疏场景
  • 六、统一视角:从客户端到服务端再回到 P2P 拓扑
  • 七、对工程实践的推论:消息广播 / 带宽 / 热点分摊
  • 八、讨论:AOI 与同步模型 / 确定性回滚的耦合
  • 九、给后端架构师的 AOI 选型清单
  • 参考文献

AOI 兴趣区域系统工程 2026:从九宫格、十字链表到万人同屏的统一架构

把 AOI 的几何查询、消息广播、带宽预算、热点分摊、跨服融合做成可计算、可观测、可演进的统一架构。覆盖九宫格 / 灯塔 / 四叉树 / R-tree / KD-tree 五大主流算法,从 MOBA 到开放世界到跨服战的选型决策树。

2026年10月4日·约 25 分钟阅读·7,267 字·7 次阅读·博主
#游戏服务架构
AOI 兴趣区域系统工程 2026:从九宫格、十字链表到万人同屏的统一架构

Index

  • 一、问题的提出:AOI 在多人游戏后端的不可替代位置
  • 二、形式化:AOI 的几何与拓扑基础 + 复杂度边界
  • 三、主体 1:九宫格实现 — 最朴素也最广泛
  • 四、主体 2:灯塔算法与十字链表 — 动态密度场景
  • 五、主体 3:四叉树 / R-tree / KD-tree — 大世界稀疏场景
  • 六、统一视角:从客户端到服务端再回到 P2P 拓扑
  • 七、对工程实践的推论:消息广播 / 带宽 / 热点分摊
  • 八、讨论:AOI 与同步模型 / 确定性回滚的耦合
  • 九、给后端架构师的 AOI 选型清单
  • 参考文献

AOI 兴趣区域系统工程 2026:从九宫格、十字链表到万人同屏的统一架构

游戏服务端架构师每天面对的一个隐形战场:AOI(Area of Interest,兴趣区域)。它不像状态同步、回滚、AOI、回滚、撮合那么张扬,也不像 KCP 长连接、可观测性、K8s 调度那样能被 CI/CD 看板一眼看清;但任何一个 MMORPG、MOBA、SLG、开放世界生存游戏的玩家在地图上走动,背后都有一个 AOI 系统在每帧把"我周围哪些实体应该让我看到、我也应该让谁看到"这个判断回答得既快又准。AOI 的代码量往往只占战斗服 5%,但它决定的是带宽曲线、玩家卡顿感、跨服玩法天花板,以及任何一个看似无关的"全服飘字 BUG"的根因。

本文不写客户端预测、也不写确定性回滚的算法本身;我们聚焦在服务端侧的 AOI 工程——分块策略、消息广播、热点均衡、跨服融合,以及当玩家从 200 人一服增长到 10000 人同屏时,这套系统必须做哪些重构。

一、问题的提出:AOI 在多人游戏后端的不可替代位置

传统单机游戏的渲染管线把"视野内实体"这件事完全交给了客户端 + GPU 剔除:服务端只关心玩家输入与状态变化,根本不知道客户端画面上渲染了什么。但多人游戏把这个责任翻转了——服务端必须显式知道"客户端应该看到什么",否则会出现:(a) 一个玩家隐身到隔壁格子里却仍能看到战斗(视野裁剪 BUG);(b) 一个远处的玩家被攻击掉血,本地客户端根本没渲染该实体,但服务端已经扣了血(同步错位);(c) 一个玩家在场景 A 触发了全服公告,场景 B 的玩家也看到了(消息过扩散)。

所以 AOI 的本质是:把"哪些实体在另一个实体的感知范围内"这个几何判断,从渲染层搬到服务端层,并且每帧(每 Tick)执行一次。这个看似简单的几何查询,在万人同屏下变成了 O(n2)O(n^2)O(n2) 的噩梦——10000 个实体两两比较,单帧 5000 万次距离计算,64 核服务器也会被打挂。

真实工程里,所有主流多人游戏的 AOI 都遵循同一个分治原则:空间换时间——把世界切成网格、灯塔、或者树形结构,每个实体只跟自己所在格 / 灯塔 / 树节点的邻居做比较,而不是和全服所有实体比。从 1990 年代的 MUD 到 2026 年的《王者荣耀》《原神》《魔兽世界》,AOI 的底层思想从未改变,改变的只是切分粒度、广播协议、与同步模型的耦合方式。

二、形式化:AOI 的几何与拓扑基础 + 复杂度边界

先把 AOI 抽象成可计算的数学对象。设世界是一个二维平面 W⊆R2W \subseteq \mathbb{R}^2W⊆R2(三维推广留给大世界 3D),实体集合为 E={e1,e2,…,en}E = \{e_1, e_2, \ldots, e_n\}E={e1​,e2​,…,en​},每个实体 eie_iei​ 有位置 pi∈Wp_i \in Wpi​∈W 和感知半径 ri>0r_i > 0ri​>0。AOI 的核心问题是:

Visible(ei)={ej∈E∣∥pi−pj∥≤ri}\text{Visible}(e_i) = \{e_j \in E \mid \|p_i - p_j\| \leq r_i\}Visible(ei​)={ej​∈E∣∥pi​−pj​∥≤ri​}

最朴素的暴力解法复杂度是 O(n2)O(n^2)O(n2)——对每个 eie_iei​ 遍历所有 eje_jej​,计算欧几里得距离。平方复杂度在 n=200n = 200n=200 时勉强可接受(单帧 40000 次距离计算),n=2000n = 2000n=2000 时进入百万级(40 万次/帧),n=10000n = 10000n=10000 直接打到 5000 万次/帧——按 60Hz Tick 计算,每秒 30 亿次距离运算,CPU 完全不可能支撑。

更精细的,AOI 在游戏场景下还有三个非几何约束:

  1. 感知半径通常相同:MMO 大多数玩家视野是固定值(如 50 米),只有少数职业有视野增强技能;MOBA 的视野半径随迷雾机制变化(无迷雾 800、有迷雾 400、隐身 0)。
  2. 实体类型差异:玩家、NPC、怪物、宠物、召唤物对其他实体的可见性不同——玩家看不到某些 NPC 的隐身状态,宠物能看到主人看不到的视野。
  3. 更新频率分层:战斗内实体的位置更新频率高(10-30Hz),剧情 NPC 的位置基本不变(1Hz 或更低),AOI 必须对不同频率实体做分层广播。

这三个约束决定了 AOI 不能简单套用通用空间索引(如 R-tree 的静态最近邻查询),而需要游戏特化的混合结构——后文 §3-§5 我们会逐一拆解。

带宽边界:AOI 在万人同屏场景下,最直观的带宽是"每个实体的位置包 + 状态包广播给所有 Visible 集合"。设位置包为 32 字节、状态包 16 字节、Tick 30Hz、平均 Visible 大小 50,则单帧广播量 32×30+16×30=144032 \times 30 + 16 \times 30 = 144032×30+16×30=1440 字节/实体/秒,万人同屏时总广播带宽 = 1440×10000=14.41440 \times 10000 = 14.41440×10000=14.4 MB/s——单机房内部没问题,跨机房、跨大区、玩家到客户端的公网带宽就要精打细算了。

三、主体 1:九宫格实现 — 最朴素也最广泛

九宫格(Nine-Grid / 3×3 Grid)是游戏 AOI 的"Hello World"——也是 80% 的游戏服务端在跑的实现。它的思想极其简单:把世界切成一个 N×NN \times NN×N 的等大网格,每个实体根据自己位置映射到唯一格子;查询 Visible 集合时,只查自己所在格子 + 周围 8 个格子(共 9 个),就完成了一次"圆形视野"的近似查询。

九宫格的工程细节有三层:

第一层是网格大小与视野半径的关系。设网格边长为 ggg,视野半径为 rrr,则九宫格能精确覆盖的最大距离是 r≤g2r \leq g\sqrt{2}r≤g2​——也就是说,如果视野是 50 米见方(圆形等效约 35 米半径),网格边长必须 ≥50/2≈35\geq 50/\sqrt{2} \approx 35≥50/2​≈35 米。网格太小,相邻格子数增多但单格内实体数少;网格太大,单格内实体数密集但 9 格里可能只有 1 格有内容。经验值:单格实体数控制在 50-100 之间,网格边长约为视野直径的 1/3 到 1/2。

第二层是实体进格 / 出格的事件触发。当玩家移动导致所属格子变化时(边界穿越),服务端要把玩家从旧格子的实体集合删除、加入新格子的实体集合。边界穿越是非常高频的事件——一个 60Hz Tick 的玩家在网格边界来回横跳时,单秒可能触发 60 次进格/出格事件。优化:用一个"格归属 hash"做脏标记,只有 hash 变了才真正搬移;同时维护一个"观察者索引"——记录每个格子被哪些相邻格子"观察",这样进格时只需通知相邻 9 格的观察者,不必遍历全服。

第三层是消息广播的扇出控制。九宫格每个 Tick 给每个实体构造 Visible 集合后,需要给该实体发一帧"我应该看到这些实体"的广播包。如果 Visible 大小是 50,30Hz Tick,单实体下行带宽 50 × 48 = 2400 B/s × 8 = 19.2 Kbps——单玩家带宽 19.2 Kbps(视野消息部分),万人同屏服务端总下行 = 19.2 × 10000 = 192 Mbps,约 24 MB/s。MOBA 单局 10 人时下行带宽只有 192 Kbps——这就是为什么 MOBA 客户端不卡而 MMO 客户端容易卡。

九宫格的代码实现通常是 O(100) 行:在战斗服启动时建好网格对象(哈希表 + 双向链表),每个 Tick 遍历所有实体,对每个实体做"当前位置 → 网格 hash → 取出相邻 9 格的实体集合 → 距离过滤 → 广播"。KBEngine、Skynet 的早期版本就是九宫格实现。

九宫格的致命缺陷:当世界很大(开放世界 10km × 10km)而实体分布不均匀(主城密集、野外稀疏)时,固定大小网格在主城导致单格实体爆炸(500+ 实体/格),在野外导致 80% 的格子空着、查询时遍历大量空格子。九宫格适用于"实体分布相对均匀"的场景:MOBA、单地图 MMORPG、SLG 大地图(格子化)。

四、主体 2:灯塔算法与十字链表 — 动态密度场景

灯塔算法(Lighthouse / Beacon)是九宫格的"动态密度"升级版——把网格的固定大小改为"按实体密度自动调整"。其核心思想是:当某区域实体密度升高时,自动把它切分为更细的网格;当密度降低时,自动合并邻近的稀疏网格。灯塔之名来自航海——每个灯塔覆盖一个圆形区域,多个灯塔可以重叠或嵌套。

工程实现上,灯塔算法通常用**十字链表(Orthogonal Linked List)**做底层容器——每个实体节点挂在双向链表上,链表按 x 坐标排序、按 y 坐标排序各一份。给定一个查询点 (x, y) 和半径 r,先按 x 排序链表做 O(log n) 二分定位 x 范围、再按 y 排序链表做 O(log n) 二分定位 y 范围,得到候选集合(可能有少量 false positive),再用距离过滤做精确剔除。十字链表的复杂度是 O(k+log⁡n)O(k + \log n)O(k+logn)——kkk 是真实结果集大小,比九宫格的 O(ncell)O(n_\text{cell})O(ncell​) 更精准。

灯塔算法的实际效果:

  • 主城场景(500+ 实体聚集):灯塔自动切出 50 米细粒度网格,十字链表查询常数项小,单帧查询总耗时 < 5ms
  • 野外场景(5-10 实体稀疏分布):灯塔自动合并为 200 米粗粒度网格,十字链表查询命中 0-1 个实体,几乎零开销
  • 跨场景移动(玩家从主城跑到野外):玩家经过灯塔边界时,触发灯塔合并事件,把该玩家从"主城细网格链表"搬移到"野外粗网格链表"——开销约 1-2ms,可接受

灯塔算法的工程难点在于边界处理。九宫格的边界是直线(格子的边),灯塔的边界是动态生成的曲线(灯塔的覆盖圆周)。当两个玩家相距 100 米、灯塔半径 60 米时,他们可能在两个相邻灯塔的边界上反复横跳——必须用一个 hysteresis(滞后机制)防止震荡:进入新灯塔的半径阈值是 60,退出旧灯塔的半径阈值是 80,二者之间形成 20 米的缓冲区,玩家进入缓冲区后即使略微回退也不退出。Skynet 的 lighthouse 模块、Unity 的 MLAPI 空间索引都用这个 trick。

十字链表的内存特性:每个实体在两条链表(x 排序 + y 排序)上各占一个节点,单实体内存开销 ~40 字节;插入 / 删除 / 查询都是 O(log⁡n)O(\log n)O(logn) 但常数项大(cache miss 较多)。在万人同屏下,十字链表总内存 10000 × 40 = 400 KB,可以完全装进 L2 cache,cache miss 率低。

灯塔算法的适用场景:实体密度差异巨大的大世界——开放世界生存游戏(《Rust》《Conan Exiles》《幻塔》)、MMORPG 的野外 + 主城混合地图、SLG 的多服合并场景。在这些场景下,灯塔算法的带宽利用率比九宫格高 3-5 倍(不会在稀疏区域做无意义的 9 格查询)。

五、主体 3:四叉树 / R-tree / KD-tree — 大世界稀疏场景

当世界尺寸达到平方公里级(10km × 10km 起步)、实体总数相对稀少(< 5000)但分布极不均匀时(少量主城 + 大量空旷野外),九宫格和灯塔都不够灵活——需要递归空间划分结构。

四叉树(Quadtree):把世界递归切分为四个等大的子区域,直到每个子区域的实体数 < 阈值(如 10)。查询时从根节点递归向下,只遍历与查询范围相交的子节点。四叉树的深度通常 4-8 层,对应网格大小从 5km 缩到 50 米。单次查询复杂度 O(log⁡n+k)O(\log n + k)O(logn+k),但插入 / 删除需要触发树的重新平衡——玩家移动导致跨层时,可能需要把节点下沉 / 上浮,复杂度最坏 O(log⁡n)O(\log n)O(logn) 但常数项比十字链表大。

R-tree(R 树):四叉树的升级版——节点是矩形包围盒(AABB),不要求等分而是按实体分布自适应切分。R-tree 的工业实现(Boost.Geometry、R-tree.js)支持动态插入 / 删除、范围查询、最近邻查询、KNN 查询,复杂度都是 O(log⁡n)O(\log n)O(logn)。R-tree 是游戏服务端 AOI 的"通用瑞士军刀"——既能处理主城密集、野外稀疏的混合场景,也能处理实体移动导致的树重构。

KD-tree(K 维树):在二维场景下,KD-tree 按 x / y 维度交替切分,类似四叉树但切分轴不固定。KD-tree 的查询性能略优于四叉树(树深度更均匀),但动态更新代价更大(KD-tree 的插入 / 删除容易破坏树的平衡,需要重建)。KD-tree 适用于"实体静态或半静态"的场景:剧情 NPC、AOI 的预计算层、地图编辑器。

工程实践中的取舍:

  • 四叉树:实现简单(500 行代码),性能稳定,适合中小规模(< 10000 实体 / 服务器);缺点是动态插入导致树倾斜严重(如果实体都聚到主城,主城区域会变成"针状"深树)
  • R-tree:工业级空间索引的标准选择(PostGIS、JTS 都用 R-tree),支持百万级实体,动态平衡良好;缺点是依赖成熟的第三方库(如 Boost.Geometry),自己实现容易踩 R*-tree 的强制重插入(forced reinsert)的坑
  • KD-tree:静态场景专用——比如一次性的 AOI 预计算(地图编辑器、剧情过场动画);动态场景不建议用

真实生产案例:《魔兽世界》经典版采用 R-tree 变种(每个地图分区用一个 R-tree 实例),配合"分区切换"机制(玩家跨分区时挂载到另一个 R-tree);《原神》大世界 AOI 用四叉树 + 灯塔的混合结构——四叉树做粗粒度分片(防止空区域遍历),灯塔做细粒度动态密度;Skynet 的 lighthouse 模块本质上是四叉树 + 十字链表的组合。

六、统一视角:从客户端到服务端再回到 P2P 拓扑

AOI 不是服务端孤立的问题——它必须和客户端的渲染剔除、服务端的同步模型、甚至 P2P 模式下的拓扑结构协同设计。

客户端与服务端的 AOI 协同:客户端知道自己屏幕分辨率、视野范围、镜头缩放比例,做的是"渲染剔除"——把屏幕外、低 LOD 的实体不绘制。但客户端的渲染剔除是 GPU 友好的(顶点变换前的 early-out),与服务端的 AOI 查询不共享数据结构(GPU 渲染剔除在 shader 里做,服务端 AOI 在 CPU 上做)。协同原则:服务端 AOI 半径 ≥ 客户端实际渲染范围的 1.2 倍(防止客户端抖动时被边界实体"卡出来");服务端 AOI 不应包含客户端绝对不会渲染的实体(如玩家在屏幕外 500 米的实体)。

P2P 模式下的 AOI 拓扑:CS 架构下,AOI 完全由服务端权威,玩家之间不直接通信;P2P 架构(如《我的世界》局域网、《反恐精英》老版本)下,玩家之间需要互相知道对方位置,AOI 退化为"客户端自己 ping 周围 peers"。P2P AOI 的工程难点是 NAT 穿透——玩家在路由器后面,没有公网 IP,无法直接接收 peers 的位置包。解决方案:(a) STUN/TURN 服务器中继(增加 50-100ms 延迟);(b) 选一个玩家做"伪主机"(host migration 复杂);(c) 退化为 CS 架构(最稳)。真实工程:99% 的多人游戏都选择 CS 架构,P2P 只用于轻量化场景(小规模合作、大厅匹配前的房间协调)。

大世界分块加载与服务端 AOI 的镜像:开放世界游戏的客户端是分块流式加载的(Streaming World),玩家走到地图边缘时,新地块的实体信息需要从服务端拉取。服务端 AOI 必须能"主动推送"即将进入视野的实体,而不是让客户端拉取(拉取模式会引入 100-300ms 的感知延迟)。协同设计:服务端 AOI 通知机制不仅要"已可见",还要"即将可见"——比如视野边界外 100 米的实体也要预推送,客户端拿到后暂存到"等待进入"队列。

跨服 AOI 的拓扑难题:跨服战、合服、全球同服等场景下,玩家分布在不同机房、不同大洲的多个战斗服上。AOI 必须能跨服查询——玩家 A 在上海机房、玩家 B 在法兰克福机房,A 视野内的实体可能跨多个机房分布。常见方案:(a) 中心化的"位置索引服"——所有战斗服把位置信息写入中心索引,跨服 AOI 查询走索引(高延迟 100-300ms,但准确);(b) gRPC 广播链路——跨服战时把多个机房拉成一个"虚拟大服",AOI 在虚拟大服上跑(带宽压力大);(c) 接受"跨服 AOI 滞后"——跨服实体的位置更新比同服慢 200ms,玩家肉眼感知不到(实测可行)。网易《逆水寒》、腾讯《天涯明月刀》的全球同服架构走方案 (a) + (c) 的混合。

七、对工程实践的推论:消息广播 / 带宽 / 热点分摊

AOI 的工程推论集中在三个方向:消息广播的扇出控制、带宽的预算管理、热点的分摊策略。

消息广播的扇出控制:

  1. 可见集分组广播:Visible 集合按"实体类型 + 移动频率"分组——玩家一组(30Hz)、NPC 一组(10Hz)、剧情实体一组(1Hz)。客户端收到三组包,按不同频率更新本地实体位置,CPU 占用减少 50%。
  2. 进入 / 离开事件:实体进入 Visible 集合时,发"Enter"包(含完整状态);实体离开时,发"Leave"包(仅 ID);Tick 内 Visible 集合不变的实体只发"位置增量"包。典型带宽配比:Enter 包 100B / Leave 包 16B / 增量包 32B——配比失衡(如 Enter 包占比 > 30%)说明 AOI 抖动剧烈。
  3. 广播合并:当 Tick 内 50 个玩家都看到同一个 NPC 时,服务端不发 50 个独立 NPC 位置包,而是发 1 个 NPC 包 + 50 个订阅者标记——CDN 思路在游戏内的应用。
  4. 跨服广播合并:跨服战的全局公告、走马灯、战报可以走"广播中心服"统一推送,避免每个战斗服各自发包。

带宽预算管理:

AOI 的带宽消耗可以用公式预估:

BAOI=n×f×(spos+sstate)×kVisibleB_{\text{AOI}} = n \times f \times (s_{\text{pos}} + s_{\text{state}}) \times k_{\text{Visible}}BAOI​=n×f×(spos​+sstate​)×kVisible​

其中 nnn 是实体数、fff 是 Tick 频率、sposs_{\text{pos}}spos​ + sstates_{\text{state}}sstate​ 是单实体包大小、kVisiblek_{\text{Visible}}kVisible​ 是平均可见集大小。万人同屏(n=10000n=10000n=10000, f=30f=30f=30, s=48s=48s=48, k=50k=50k=50)时:

BAOI=10000×30×48×50=720 000 000 B/s=687 MB/sB_{\text{AOI}} = 10000 \times 30 \times 48 \times 50 = 720\,000\,000 \text{ B/s} = 687 \text{ MB/s}BAOI​=10000×30×48×50=720000000 B/s=687 MB/s

——这超过了单机房出口带宽的极限。实际工程压缩:用 Protobuf + delta encoding 把单实体包压到 24B、用 Tick 分层(核心玩家 30Hz / 周边 10Hz)把平均 fff 降到 15、用 AOI 半径差异化把平均 kkk 降到 25,最终带宽压缩到 ~250 MB/s,可接受。

热点分摊策略:

主城、国战、跨服战是 AOI 的热点——单点实体密度可能是普通区域的 100 倍。常见分摊策略:

  1. 分线(Sharding):把热点拆成多个"线"(实例),玩家登录时分配到不同线。原神的璃月主城、逆水寒的汴京都用 4-8 线的分线机制,把单点 1000 实体降到 250。
  2. 兴趣区域合并:把视野内的多个 NPC 合并成一个"区域包"广播,客户端收到区域包后只关心区域内自己感兴趣的 NPC——最终幻想 14 的部分场景用这个机制。
  3. 服务端预测 + 客户端延迟呈现:服务端不全量广播实体位置,而是按"客户端可能看到的范围"做超集广播;客户端收到后做客户端预测剔除。带宽下降但客户端计算量上升,需权衡。
  4. 专用 AOI 网关:在战斗服前加一层 AOI 网关——网关订阅所有战斗服的位置更新,自己维护一个全机房范围的 AOI 索引,玩家客户端只连 AOI 网关、不直连战斗服。腾讯IEG的部分 FPS 游戏用这个架构。

八、讨论:AOI 与同步模型 / 确定性回滚的耦合

AOI 不是一个独立组件——它必须和游戏的同步模型协同设计。本节讨论三个耦合点。

AOI 与状态同步的耦合:状态同步(State Sync)下,服务端是权威,客户端是哑终端。AOI 在服务端完成过滤后,把可见集内的实体位置 / 状态直接广播给客户端;客户端不需要做预测,只需要渲染。典型代表:MMORPG(《魔兽世界》、最终幻想 14)。AOI 的带宽消耗与同步模型成正比——状态越多、状态变化越频繁,AOI 带宽越大。

AOI 与帧同步(Lockstep)的耦合:帧同步下,所有客户端在同一个 Tick 上跑同一段逻辑,AOI 在客户端本地完成——每个客户端只关心自己 Visible 集合内的实体,每个 Tick 给自己发一份输入、上行带宽极低、下行带宽由锁步步进决定。典型代表:王者荣耀、英雄联盟。帧同步的 AOI 难点是确定性——所有客户端必须看到相同的实体集合、相同的实体顺序,否则逻辑分歧。AOI 必须保证:(a) 不同客户端的可见集排序稳定(按 ID 升序);(b) 不同客户端的距离计算结果完全一致(无浮点误差累积)。工程 trick:用整数坐标(厘米或毫米)+ 平方距离比较避免浮点。

AOI 与确定性回滚(Rollback NetCode)的耦合:回滚模式下,服务端保留最近 1-2 秒的历史快照,客户端做本地预测、错时回滚。AOI 的责任扩展了——不仅要广播"当前可见",还要支持"过去某个 Tick 可见"(回滚时的查询)。典型代表:GGPO、《真人快打》《街头霸王》等格斗游戏的回放。工程难点:历史 AOI 状态需要时序数据库(每帧的位置 + 可见集合存档),数据量爆炸(30Hz × 2 秒 × 万级实体 = 60 万条 / 战斗)。实际工程用压缩 + 分层——只对参与回滚的玩家做完整时序,其他玩家用线性外推。

AOI 与 MMO 单线程战斗服的限制:早期 MMO 战斗服是单线程的(Skynet actor 模型),AOI 必须在单线程 Tick 内完成所有查询。性能天花板:单线程战斗服在 5000 实体 + 30Hz Tick 下,AOI 查询耗时控制在 3-5ms 是底线;超过 5ms 整帧卡顿明显。优化路径:从九宫格升级到灯塔(节省 50% 查询时间)+ 批量处理(多帧合并一次广播,节省 30% 协议栈开销)+ SIMD 距离计算(一次性算 8 个实体的距离,节省 70% CPU 时间)。

九、给后端架构师的 AOI 选型清单

最后给一张选型清单——读者按游戏品类直接对号入座。

MOBA(5v5 / 10v10):九宫格 + 30Hz Tick + 十字链表备选。视野半径 800-1500 单位、实体数 50-150、AOI 带宽 < 5 Mbps/玩家。参考实现:Skynet、KBEngine 的 MOBA 模板。

MMORPG 副本(5-25 人):九宫格 + 30Hz Tick。视野半径 50 米、实体数 20-80、AOI 带宽 < 1 Mbps/玩家。参考实现:魔兽世界经典版、最终幻想 14 副本。

MMORPG 主城 + 野外(100-1000 玩家同图):灯塔 + 十字链表 + R-tree 备选。视野半径 30-80 米、实体数密集 500+ / 稀疏 5-、AOI 带宽 1-5 Mbps/玩家。参考实现:逆水寒、天涯明月刀、原神主城。

开放世界生存(5000-20000 实体同服):四叉树 + 灯塔混合。视野半径 100-200 米、AOI 带宽 5-20 Mbps/玩家。参考实现:Rust、幻塔、Conan Exiles。

SLG(1000+ 玩家同大地图):自定义网格(SLG 本身就是格子化地图)+ 兴趣区域裁剪。视野半径 1-10 格子、AOI 带宽 < 0.5 Mbps/玩家。参考实现:率土之滨、三国志战略版、万国觉醒。

FPS(10v10 / 64v64):九宫格 + 客户端预测。视野半径 100-300 米、实体数 50-200、AOI 带宽 10-30 Mbps/玩家(FPS 需要精确命中判定,带宽最高)。参考实现:CSGO、Valorant、Apex Legends。

跨服战 / 全球同服:中心索引服 + 跨服 AOI 滞后容忍。视野半径 50-100 米、跨服实体数 1000+、AOI 带宽 1-10 Mbps/玩家(跨服部分带宽降级)。参考实现:魔兽世界经典版跨服、原神跨服、最终幻想 14 数据中心跨服。

Serverless / 边缘游戏后端:边缘节点预计算 AOI + 中心服校验。AOI 推到 Cloudflare Workers / Lambda@Edge,节省跨大区延迟。参考实现:Cloudflare 边缘游戏 demo、AWS GameLift Edge。

选型的最终决策树:

  1. 实体数 < 200 + 视野均质 → 九宫格
  2. 实体数 200-2000 + 密度差异大 → 灯塔 + 十字链表
  3. 实体数 2000+ + 世界巨大 → 四叉树 / R-tree
  4. 跨服 / 全球同服 → 中心索引服 + 边缘缓存
  5. 帧同步 / 回滚 → AOI 必须确定性 + 历史回溯支持

希望这份清单能帮后端架构师在项目早期就把 AOI 的设计对齐到合适的工程范式上——而不是等到卡顿、带宽超限、跨服玩法做不出来的时候才发现选错了。

参考文献

  1. Skywind3001. KCP — A Fast and Reliable ARQ Protocol. GitHub. https://github.com/skywind3000/kcp
  2. Cloudwu. Skynet — A Lightweight Actor Framework for Online Games. GitHub. https://github.com/cloudwu/skynet
  3. KBEngine. A MMOG Engine. GitHub. https://github.com/kbengine/kbengine
  4. Valve. Source Multiplayer Networking — Lag Compensation. https://developer.valvesoftware.com/wiki/Lag_Compensation
  5. Riot Games. Riot's Approach to Determinism. GDC Talk 2014. https://www.youtube.com/watch?v=NtEtAsA5eFc
  6. Epic Games. Unreal Engine Networking — Replication Graph. https://docs.unrealengine.com/ReplicationGraph
  7. Unity. Unity Multiplayer — Netcode for GameObjects. https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects
  8. Glenn Fiedler. Gaffer on Games — Snapshot Interpolation, Deterministic Lockstep. https://gafferongames.com
  9. Microsoft. PlayFab Multiplayer Server — Geo-filtering and Region Affinity. https://learn.microsoft.com/en-us/gaming/playfab
  10. AWS. GameLift — Fleet Scaling and Location. https://aws.amazon.com/gamelift
  11. Hecker, C. et al. Practical Networked Lighting in Black & White. GDC 2001. https://www.gdcvault.com/play/1413/Practical-Networked-Lighting-in-Black
  12. Bernier, Y. W. Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization. GDC 2001. https://www.gdcvault.com/play/1014346/Latency-Compensating-Methods-in-Client
  13. Valve. Steamworks — Game Networking. https://partner.steamgames.com/doc/features/multiplayer/networking
  14. NetEase Games. 逆水寒 — 全球同服架构演进. GAConf 2023. https://arch.overwatch.game
←返回文章列表

Related

可能也会喜欢

  • 确定性回滚与延迟补偿 2026:游戏同步模型的三层落地10月24日
  • 游戏玩家数据分片与冷热分层工程 2026:从位域分配到合服迁移10月23日
  • 容器化游戏服编排 2026:房间级弹性调度10月22日

Conversation

0 条

留下你的想法

加载评论中…

New comment