架构拆分
- 网关Gate
- 游戏服务Game
- 登录服务Login
- 中心服务Center
- 全局服务Chat、Rank
各部分都可以用一个单独进程或一个Actor来表示
使用场景
🎯 必须用(尺度决定了不得不拆)
-
开放世界 RPG / Action RPG:原神、塞尔达、巫师 3、上古卷轴、黑神话方向
- 原因:几 km² ~ 几十 km² 连续地图,全装内存不可能 → 必须 Chunk 流式
-
生存沙盒 / 建造类:Rust、方舟、我的世界(理论无限)、幻兽帕鲁
- 原因:地图甚至程序化无限生成,尺度没上限 → 必须空间分块 + 按需生成
-
MMO(现代派):FF14(虽然老但地图大)、新倩女幽魂、逆水寒
- 原因:几千人同图 + 地图大 → 必须 AOI + Zone 分片
-
赛车 / 飞行开放世界:极品飞车:无界、微软飞行模拟
- 原因:移动速度极快(飞行 200+ km/h)→ 预测加载 + 极低 Pop-in 要求
🤔 可选(中小世界也能做,但大世界是卖点)
-
大逃杀 / 百人吃鸡类:PUBG、APEX(地图其实不算特别大,但 100 人 + 高速载具 → 也要 AOI + 流式,但比原神那种"真·大世界"轻)
-
FPS / TPS 开放世界:地平线:西之绝境、孤岛惊魂 ------ 单图大,但人不太多(纯 PvE),服务端压力小,客户端流式压力大
❌ 一般不用
-
MOBA(王者、LOL)→ 单局一张小地图,3 条路,没必要
-
传统 FPS 竞技(CS2、OW 占点)→ 图小、人数固定
-
卡牌 / 回合制 RPG → 根本没有"走地图"这件事
技术选型
客户端

后端

核心问题
前置语境:大世界和普通关卡的差别
-
普通关卡:一张地图 200m×200m,全部塞内存,所有玩家互相看得见,服务端一帧把所有人的位置广播给所有人------没问题,因为总量小。
-
大世界:8km×8km 甚至更大,几千玩家同时在,地图本身几百 MB 到 GB 级。
于是下面 5 个问题一个个蹦出来。
视野同步怎么做到不丢也不炸?
起因:你站在大世界里,地图上其实有 2000 个玩家、3000 个怪。如果你的手机/电脑要把这 5000 个实体的位置每帧都收一遍------
-
带宽炸:每秒几十 MB,4G/WiFi 都扛不住
-
但你根本看不见他们:大部分人在地图另一头,跟你半毛钱关系没有
解决方案
-
AOI(Area of Interest,兴趣区域):服务端给每个玩家划一个"我关心这个范围",只把范围内的事发给他。类似"你只订阅自己周围的新闻"。
-
九宫格:把地图切成象棋盘一样的格子,你在中间那格,服务端只发你 + 上下左右 + 四个对角这 9 格里的实体给你。
-
Diff(增量):你从格子 A 走到格子 B,不用重新发"你周围所有人",只发"刚才那 9 格里没了谁、新进了谁"------这就是上一轮伪代码里 leave/ enter的由来。
跨 Chunk / 跨 Zone 怎么无感?
起因:客户端把地图切成了 Chunk(比如 128m×128m 一块)。你走路"1 号 Chunk → 2 号 Chunk"本来是内部小事,但有两件事会露馅:
-
客户端侧:2 号 Chunk 还没 Load 完,你眼前一片空白 → "Loading 感"
-
服务端侧:2 号 Chunk 属于另一个 DS 进程(Zone B),你走过去如果让客户端断线重连 → 屏幕中间一个"正在连接..." → 体验崩了
玩家期待的是:骑马从草原冲进森林,不停、不卡、不 Loading。
解决方案
客户端 Chunk 边界重叠 + 服务端 DS 切流协议
-
Chunk(客户端):地图切块的基本单位,流式加载/卸载的最小颗粒。
-
Zone / DS 分片(服务端):服务端把大地图切成几块,每块跑一个 DS 进程。比如左半边 Zone A(DS-1),右半边 Zone B(DS-2)。
-
热迁移 / 切流:玩家从 Zone A 走到 Zone B 时,服务端把"这个玩家的状态快照"从 DS-1 拷到 DS-2,客户端悄悄把网络连接从 DS-1 切到 DS-2------你还在骑马,完全不知道背后换了台服务器。
高速移动 Chunk 来不及 Load 怎么办?
起因:
你走路 → Chunk 加载来得及(人速 ~6m/s)。
你骑马 → 还行(马速 ~15m/s)。
你开载具 / 滑翔翼 → 50--80 m/s。
流式加载的逻辑是"你走到哪、加载到哪"。如果你速度太快,等你踩到 Chunk 边界时,那个 Chunk 的美术资源(地形、树、房子)还在硬盘→内存→GPU 的路上 → 你眼前突然"地没刷出来,掉下去了"或者"树啪一下冒出来"。
解决方案
预测加载(速度向量 × 系数)+ 低模占位
-
预测性预加载(Predictive Streaming):不光加载"你脚下这格",还加载"你面朝方向再往前 N 格"。类似你开车,导航不光显示你车轮底下,还显示前面 500m。
-
速度向量 × 系数:Client 拿你的朝向 + 速度,算出"你 2 秒后会到哪",提前发 Load 请求。
-
低模占位(Proxy / Impostor):真资源没到之前,先摆一个超低模的"假房子"顶着,资源到了再换真身------玩家不至于看到空气。
内存碎片 / GC spike?
起因:
你玩游戏时偶尔会"突然卡一下,0.5 秒画面不动"------这叫 Spike。
大世界里,你走一步就可能有:
-
旧的 Chunk 卸载 → 几百个 GameObject 销毁
-
新的 Chunk 加载 → 几百个 GameObject + Texture + Mesh 新建
如果每次都真的 new/ delete(C++)或让 GC(C#/Java)去回收:
-
频繁 new/delete → 内存像被咬了很多小洞(碎片),后来想申请一块大内存申请不到
-
GC 触发 → 虚拟机暂停所有线程去扫垃圾,画面就卡住一帧 → 玩家:"又卡了?"
解决方案
对象池 + BufferGeometry 复用 + 异步分帧,绝不主线程 Instantiate
-
对象池(Object Pool):Chunk 里的树、石头、怪物,别真 Destroy,丢回池子里下次拿来改个坐标复用 → 零分配,GC 就安静了。
-
Buffer / Mesh 复用:地形、植被的 GPU 资源也别反复创建销毁,池化。
万人同图服务端怎么扛?
起因:
假设 8km×8km 大世界,在线 1w 人,每人带宠物/坐骑,地图上还有 2w 个野怪、采集物------3w 实体。
如果一个服务端进程全扛:
-
每帧要遍历 3w 实体算 AI、算物理
-
AOI 广播就算九宫格剪过,CPU 还是爆
-
一个进程崩 → 全图 1w 人掉线
解决方案
空间分 Zone + AOI 剪枝 + 云原生按 Key 闪回
-
Zone 分片(Space Sharding):把地图按空间切成几块,每块一个 DS 进程,各管各的 → 问题 2 里的"跨 Zone 热迁移"就是为了把这个切分藏起来不让玩家看见。
-
云原生扩缩容:大世界白天 2k 人在线、晚上 1w 人,Zone 数可以动态加(比如把原来 1 个 Zone 拆成 2 个)------但要配合"按 Key 分片"的数据层(Redis/Mongo 按 Zone ID 或 Player ID hash)。
-
DS(Dedicated Server):专职跑游戏逻辑的服务器进程,不带渲染,纯算。