游戏世界与游戏对象
Game World & Game Objects
游戏由玩法 (gameplay) 而不是技术定义;游戏机制 (game mechanics) 是支配游戏中各实体交互的规则,以及目标、成败标准、玩家能力、非玩家实体和整体流程(GEA 引用的论文称实现玩法的软件系统为游戏的 G 因子)。大多数游戏世界由静态元素和动态元素组成,划分为若干世界块,并由高层游戏流程组织玩家目标;动态元素通常实现为游戏对象 (GO),引擎提供的建模设施称为游戏对象模型,且分为工具侧和运行时两套(GEA4 卷 II 16、16.1–16.2)。
静态元素与动态元素
(卷 II 16.1.1)
| 类别 | 例子 |
|---|---|
| 静态元素 | 地形、建筑、道路、桥梁,几乎所有不移动、不主动参与玩法的东西 |
| 动态元素 | 角色、载具、武器、漂浮的道具和血包、收集品、粒子发射器、动态光源、检测事件的不可见区域、定义路径的样条 |
- 玩法集中在动态元素上。静态布局当然影响玩法(空旷方形房间里的掩体射击不好玩),但玩法软件主要负责更新动态元素的位置、朝向和内部状态。全部动态元素的当前状态合称游戏状态 (game state)。
- 动态元素比静态元素更耗 CPU,所以多数 3D 游戏是"大片静态背景 + 少量动态元素";动态比例越高世界越"活",硬件进步让这个比例不断升高。《小行星》《几何战争》几乎没有静态元素。
- 区分主要是优化手段:知道对象状态不会变,就可以少做工作,例如为静态网格预计算顶点光照、光照贴图、阴影贴图、静态 AO 或 PRT 球谐系数(见 预计算光照与光照贴图)。界线常常模糊:Hydro Thunder 的瀑布有动画纹理和水雾,但不与船交互,工程上按静态处理;可破坏环境可以为每个静态元素准备完好、受损、全毁三个版本,爆炸时动态替换。有的引擎干脆不区分。GEA 的结论是静态与动态只是一系列优化选择的两端,界线随优化方法和设计需求移动。
- 静态几何:通常在 Maya 等工具里制作,可以是一个大网格或多块。常用实例化 (instancing) 节省内存:少量独特网格在不同位置、朝向多次渲染,例如五种短墙段随机拼成几英里的墙。也可以用源自 Quake 的笔刷几何 (brush geometry):用一组平面围成的凸体描述形状,制作快、易与 BSP 渲染引擎集成,适合快速白盒 (block out) 关卡,尽早低成本地测试玩法;布局可行再由美术贴图细化或替换成精细网格,需要重做也不会浪费美术工作(卷 II 16.1.1.1)。
世界块
很大的世界通常分成离散的可玩区域,GEA 称为世界块 (world chunk),也叫关卡、地图、舞台、区域。玩家同一时刻通常只看到少数几块(卷 II 16.1.2)。
- "关卡"最初是为了在早期硬件的内存限制下提供更多变化:内存里一次只放一个关卡。
- 现代拓扑:仍然线性但块间界线不明显;星形(中心枢纽连到各区域,可能需要解锁);图形(区域任意连接);营造"巨大开放世界"假象,用 LOD 降低内存和提升性能(见 细节层次)。
- 除了最小的游戏,世界仍然要分块,原因有三:内存限制、控制游戏流程、分工(每块由一小组策划和美术负责)。UE5 用网格单元格自动流送的做法见 世界分区。
高层游戏流程
高层流程定义玩家目标的序列、树或图;目标也叫任务、阶段、关卡或波次。它还定义每个目标的成功条件(清光敌人拿到钥匙)和失败惩罚(回到区域起点、可能丢一条命)。剧情游戏的流程里还有过场,叫 cut-scene、游戏内过场 (IGC) 或非交互序列 (NIS);离线渲染后全屏播放的叫全动态视频 (FMV)(卷 II 16.1.3)。
早期游戏的目标和世界块一一对应(所以"关卡"有双重含义),如《大金刚》每关都是爬到顶。现代设计里每个目标关联一个或多个世界块,但有意保持松耦合,以便独立修改目标和世界划分。很多游戏再把目标归入更粗的章节/幕。下图示意 GEA 图 16.3 的结构:章节包含目标(含可选目标),目标映射到一个或多个世界块。
flowchart LR
subgraph "第1章"
O1A["目标 1A"] --> O1B["目标 1B"] --> O1C["目标 1C"]
O1B --> O1D["可选目标 1D"]
end
subgraph "第2章"
O2A["目标 2A"] --> O2B["目标 2B"]
end
O1C --> O2A
O1A -.-> C1["世界块 1"]
O1B -.-> C2["世界块 2"]
O1C -.-> C2
O1C -.-> C3["世界块 3"]
O2A -.-> C4["世界块 4"]游戏对象
动态元素通常用面向对象的方式设计:这与策划对世界的直观认识一致,策划自然希望在世界编辑器里创建和操作它们,程序员也自然地把它们实现为运行时大体自治的代理。GEA 用游戏对象 (game object, GO) 泛指几乎任何动态元素,业界也叫实体 (entity)、Actor、代理 (agent) 等(卷 II 16.2)。
- 游戏对象 = 属性(当前状态)+ 行为(状态如何随时间和事件变化)。
- 按类型分类:同类型的所有实例共享属性结构和行为,但属性值各不相同;如果行为是数据驱动的(脚本或数据定义的规则),行为也可以逐实例不同。
- 类型与实例的区别至关重要:吃豆人有幽灵、豆子、能量豆、吃豆人四种类型,但任一时刻最多 4 个幽灵实例、50–100 个豆子、4 个能量豆、1 个吃豆人(GEA 的数字)。
原书问题:街机版《吃豆人》每个迷宫开局有 240 个小豆和 4 个能量豆,共 244 个(Jamey Pittman《The Pac-Man Dossier》第 2 章,Game Developer 转载)。所以豆子实例最多是 240 个,"50–100"偏低。用数据定义"类型"本身的做法见 类型对象。
- 大多数系统支持属性和/或行为的继承,以复用代码和设计。
游戏对象模型
"对象模型"在计算机科学中有两层含义:某种语言或设计语言提供的特性(如 C++ 对象模型),或为解决特定问题设计的一套面向对象接口(如 Excel 对象模型)。GEA 的游戏对象模型指引擎为建模和模拟虚拟世界中的动态实体提供的设施,兼具两层含义(卷 II 16.2.1):
- 它是模拟某个游戏特定实体集合的一套具体面向对象接口;
- 它常常扩展引擎所用的语言:用 C 写的引擎可以自行加上面向对象设施;即使用 C++,也常加上反射、持久化、网络复制等高级特性;还可能融合多种语言,例如 C/C++ 加 Python、Lua 或 Pawn 脚本,提供两边都能访问的统一对象模型。UE5 用宏和代码生成给 C++ 加上反射、序列化、复制和垃圾回收,就是这种扩展,见 UObject 与反射系统。
工具侧与运行时
世界编辑器展示给策划的对象模型,不必和运行时实现游戏的对象模型相同(卷 II 16.2.2):
- 工具侧模型在运行时可能用根本没有面向对象特性的语言(如 C)实现;
- 工具侧的一个 GO 类型在运行时可能是一组类,而不是一个类;
- 工具侧的每个 GO 在运行时可能只是一个唯一 id,状态全部存在表或松耦合的对象集合里。
因此游戏实际上有两个密切相关的对象模型:工具侧对象模型由策划在世界编辑器里看到的 GO 类型集合定义;运行时对象模型由程序员用来实现它的语言构造和软件系统定义,可能与工具侧完全相同、直接对应,也可能底层完全不同。有的引擎两者界线模糊甚至共享实现,有的界线分明、运行时看起来"像外星人"。实现细节几乎总会渗透到工具侧,策划要了解自己搭建的世界和设计的规则对性能和内存的影响。下图示意同一个工具侧类型在运行时的三种可能实现。
flowchart LR T["工具侧 GO 类型 例如 宝箱"] --> R1["运行时一个类"] T --> R2["运行时一组协作的类 或组件"] T --> R3["运行时只是一个 id 状态存在各系统的表里"]
运行时对象模型的具体架构(以对象为中心、以属性为中心、组件化等)由 GEA 第 17 章展开。UE5 中工具侧的 Actor/组件与运行时基本是同一套类,见 Gameplay 框架;MassEntity 数据导向框架 则更接近"只是 id + 表"的那一端(这是对比归纳)。
GEA 第 17 章的补充:运行时如何实现上述概念(卷 II 17.1–17.10)
第 17 章把本页的工具侧概念落到运行时,统称玩法基础系统,分页记录如下:
- 对象模型的架构(以对象为中心 vs 以属性为中心、单体层次与组件):运行时对象模型架构
- 世界块里游戏对象的存储格式与生成器:世界块数据格式与生成器
- 世界块的加载、流送、对象生成的内存管理与存档:游戏世界的加载与流送
- 对象引用与查询:游戏对象引用与查询
- 实时更新与并发更新:游戏对象的实时更新、游戏对象并发更新
- 事件与脚本:事件与消息传递、游戏脚本系统
高层游戏流程的实现(卷 II 17.10):对象模型只定义世界里有哪些对象、各自如何行为,并不涉及玩家的目标、完成后发生什么、失败了怎样。这需要一个控制高层游戏流程的系统,常实现为有限状态机:每个状态通常代表一个玩家目标或遭遇,并与虚拟世界中的某个地点关联;玩家完成任务后状态机前进到下一状态,给出新目标;状态机也定义失败时怎么办,常见的是送回当前状态的开头重试,失败足够多次、"命"用完后回到主菜单。从菜单到第一"关"再到最后一关,整个游戏的流程都可以由这个高层状态机控制。
Naughty Dog 在《杰克与达克斯特》、神秘海域和最后生还者系列中使用的任务系统就是这类基于状态机的系统:支持线性的状态序列(Naughty Dog 称之为任务 (task)),也支持并行任务:一个任务分出两个以上并行任务,最终再汇合回主任务序列。GEA 指出,正是并行任务让 Naughty Dog 的任务图有别于普通状态机,因为状态机通常一次只能处于一个状态。
flowchart LR T1["任务 1"] --> T2["任务 2"] T2 --> P1["并行任务 A"] T2 --> P2["并行任务 B"] P1 --> T3["任务 3:汇合"] P2 --> T3
上图示意任务图的形态:主序列在任务 2 后分叉,两个并行任务都完成后汇合到任务 3(示意图,非书中原图)。状态机的通用实现见 状态模式与有限状态机。
出处
- Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 16 章 16.1–16.2 节
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 17 章 17.1 节
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 17 章 17.10 节