游戏引擎原理与实践 01:聊聊游戏引擎的前世今生
- [Bilibili 同步视频](#Bilibili 同步视频)
- 一、到底什么是游戏引擎?边界模糊的核心底座📦
- [二、百花齐放到格局定型:自研引擎 vs 商业引擎⚖️](#二、百花齐放到格局定型:自研引擎 vs 商业引擎⚖️)
- 三、引擎一定要依附游戏而生吗?理想与现实的鸿沟🤔
- 写在最后💡
玩游戏的时候,我们总会惊叹于炸裂的特效、丝滑的动画、真实的物理碰撞。很多玩家会简单把优秀的游戏体验归功于游戏引擎,但到底什么是游戏引擎?哪怕混迹行业多年的开发者,想要用一两句话精准定义它,也不是一件容易的事。今天我们就来拆解游戏引擎,搞懂它是什么、从哪里来,以及引擎和游戏之间剪不断理还乱的关系。
Bilibili 同步视频
一、到底什么是游戏引擎?边界模糊的核心底座📦
网上的资料会给出这样一段标准化定义:
游戏引擎是一套预制好的、可编辑的游戏开发核心组件集合,它给开发者提供整套开发工具,目标是让大家不用从零造轮子,快速制作交互式游戏与实时图像应用,大多支持 Windows、MacOS、Linux 多平台。内部包含渲染模块、物理碰撞、音效、脚本、动画、AI、网络、场景管理等大大小小子系统。
通俗理解,引擎就像一堆提前造好的零部件,类似组装手机:CPU、屏幕、摄像头全部预制完毕,开发者只需要按照自己产品需求挑选组合,再填充游戏独有的美术、剧情、关卡逻辑即可。
但《游戏引擎架构》一书提出了一个很现实的观点:游戏和引擎的分界线,其实十分模糊 。
有的引擎渲染模块深度耦合业务逻辑,渲染代码直接知道如何绘制游戏里的妖兽角色;有的引擎只提供通用材质、着色器能力,怪物的外观、动作全部靠外部数据配置定义。不存在完美的切割方案,随着游戏设计不断迭代,引擎与游戏业务的边界还会不停发生变动。
我们可以用一段极简 C++ 伪代码感受两种耦合差异。
方案 1:引擎代码硬编码业务角色,引擎与游戏强耦合
cpp
// 引擎渲染模块内部,直接写死游戏角色逻辑,耦合度极高
void RenderSystem::DrawOrc()
{
// 硬编码妖兽的模型、贴图、动画参数
Mesh orcMesh = LoadOrcMesh();
Texture orcTex = LoadOrcTexture();
PlayOrcAnimation(m_animComponent);
m_renderDevice->DrawMesh(orcMesh, orcTex);
}
方案 2:通用渲染引擎,角色全部由外部数据驱动,低耦合
cpp
// 通用渲染接口,引擎不关心画的是妖兽还是英雄
void RenderSystem::DrawGameObject(GameObjectData& data)
{
// 模型、贴图、动画全部来自外部配置数据
Mesh mesh = ResourceManager::LoadMesh(data.meshPath);
Texture tex = ResourceManager::LoadTexture(data.texturePath);
PlayAnimation(data.animClip);
m_renderDevice->DrawMesh(mesh, tex);
}
代码说明:上面两段代码演示引擎耦合度区别。第一段把游戏业务逻辑写进引擎底层,换一个游戏项目就要大改引擎源码;第二种引擎只提供通用能力,游戏内容由配置数据描述,复用性更强。现实项目中,自研引擎往往偏向第一种,商业通用引擎偏向第二种。
我们换个怀旧的角度理解引擎的起源。把时钟拨回 80 年代 FC 红白机时代。
手里已经有《超级马里奥》完整代码,现在要开发《冒险岛》。两款游戏都是横版卷轴:角色在地图跳跃、踩踏怪物、卷轴滚动;区别只是美术素材、关卡、音效不一样。
没必要每做一个游戏全部从零手写。我们完全可以把角色运动、地图滚动、碰撞检测、输入响应这些通用逻辑抽离出来 ,只更换美术资源与关卡配置,就可以快速产出新游戏。这部分被抽离复用的代码,就是最原始形态的游戏引擎。
#mermaid-svg-jaA4nZXjeGcnyoo4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jaA4nZXjeGcnyoo4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jaA4nZXjeGcnyoo4 .error-icon{fill:#552222;}#mermaid-svg-jaA4nZXjeGcnyoo4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jaA4nZXjeGcnyoo4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jaA4nZXjeGcnyoo4 .marker.cross{stroke:#333333;}#mermaid-svg-jaA4nZXjeGcnyoo4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jaA4nZXjeGcnyoo4 p{margin:0;}#mermaid-svg-jaA4nZXjeGcnyoo4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jaA4nZXjeGcnyoo4 .cluster-label text{fill:#333;}#mermaid-svg-jaA4nZXjeGcnyoo4 .cluster-label span{color:#333;}#mermaid-svg-jaA4nZXjeGcnyoo4 .cluster-label span p{background-color:transparent;}#mermaid-svg-jaA4nZXjeGcnyoo4 .label text,#mermaid-svg-jaA4nZXjeGcnyoo4 span{fill:#333;color:#333;}#mermaid-svg-jaA4nZXjeGcnyoo4 .node rect,#mermaid-svg-jaA4nZXjeGcnyoo4 .node circle,#mermaid-svg-jaA4nZXjeGcnyoo4 .node ellipse,#mermaid-svg-jaA4nZXjeGcnyoo4 .node polygon,#mermaid-svg-jaA4nZXjeGcnyoo4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jaA4nZXjeGcnyoo4 .rough-node .label text,#mermaid-svg-jaA4nZXjeGcnyoo4 .node .label text,#mermaid-svg-jaA4nZXjeGcnyoo4 .image-shape .label,#mermaid-svg-jaA4nZXjeGcnyoo4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-jaA4nZXjeGcnyoo4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jaA4nZXjeGcnyoo4 .rough-node .label,#mermaid-svg-jaA4nZXjeGcnyoo4 .node .label,#mermaid-svg-jaA4nZXjeGcnyoo4 .image-shape .label,#mermaid-svg-jaA4nZXjeGcnyoo4 .icon-shape .label{text-align:center;}#mermaid-svg-jaA4nZXjeGcnyoo4 .node.clickable{cursor:pointer;}#mermaid-svg-jaA4nZXjeGcnyoo4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jaA4nZXjeGcnyoo4 .arrowheadPath{fill:#333333;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jaA4nZXjeGcnyoo4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jaA4nZXjeGcnyoo4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jaA4nZXjeGcnyoo4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jaA4nZXjeGcnyoo4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jaA4nZXjeGcnyoo4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jaA4nZXjeGcnyoo4 .cluster text{fill:#333;}#mermaid-svg-jaA4nZXjeGcnyoo4 .cluster span{color:#333;}#mermaid-svg-jaA4nZXjeGcnyoo4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jaA4nZXjeGcnyoo4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jaA4nZXjeGcnyoo4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-jaA4nZXjeGcnyoo4 .icon-shape,#mermaid-svg-jaA4nZXjeGcnyoo4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jaA4nZXjeGcnyoo4 .icon-shape p,#mermaid-svg-jaA4nZXjeGcnyoo4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jaA4nZXjeGcnyoo4 .icon-shape .label rect,#mermaid-svg-jaA4nZXjeGcnyoo4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jaA4nZXjeGcnyoo4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jaA4nZXjeGcnyoo4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jaA4nZXjeGcnyoo4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 超级马里奥完整项目代码
抽取通用逻辑:跳跃/碰撞/卷轴/输入
业务独有:马里奥美术、关卡、音效
原始横版游戏引擎
冒险岛美术关卡音效
产出冒险岛游戏
图 1:早期游戏引擎诞生逻辑示意图。从已有游戏项目剥离通用代码得到基础引擎,再填入全新游戏的特有资源,快速生成新游戏。
早期这种简陋的模板引擎有很大局限,只适配横版闯关。等到即时战略游戏兴起,需要多人联机、大批量同屏单位渲染、复杂 AI,旧模板完全扛不住。直到 id Software 卡马克带来《DOOM》、《QUAKE》,真正意义现代 3D 引擎登上舞台。《QUAKE》引擎对外开放,爱好者基于这套代码魔改,诞生了大名鼎鼎的 CS。这套引擎不光做射击游戏,不少其他品类项目也直接复用它的渲染、动画模块,大幅降低开发工作量,这也是现代游戏引擎发展史的关键转折点。
并不是纠结引擎的教科书定义有多么严谨。我们研究引擎的核心目的,是学会判断:什么引擎适合自己项目,不同引擎能力边界在哪里,帮助我们更好做游戏。
二、百花齐放到格局定型:自研引擎 vs 商业引擎⚖️
自从卡马克开启引擎商业化的苗头之后,行业分化出两条路线:团队从零打磨自研引擎,或者采购成熟商业引擎。
真正合格的商业引擎不只是一堆源码,它需要配套完善工具链、规范工作流,同时提供持续技术支持,项目踩坑的时候可以获得官方协助。但高质量商业引擎屈指可数,早年授权费用不菲。于是大量大厂选择自研引擎:育碧刺客信条引擎、EA 战地系列引擎、科乐美实况足球,每个重磅 IP 背后都有专属自研引擎持续迭代。一旦停止跟进技术潮流,引擎就会逐步被时代淘汰。
国内早期引擎生态中,Gamebryo 是应用广泛的商业引擎,Ogre 是热门开源非商业引擎。时过境迁,如今行业格局已经改变:移动端项目首选 Unity,PC 主机大量项目选用 Unreal 虚幻引擎。对比老一代引擎,二者最大优势就是低耦合、通用性强,可以支撑多种多样的游戏品类。
| 引擎名称 | 类型 | 时代定位 |
|---|---|---|
| Gamebryo | 商业引擎 | 国内早期商用主流 |
| Ogre | 开源引擎 | 早期学习、中小型项目 |
| BigWorld | 商业引擎 | 大型MMO网游常用 |
| Unity | 商业引擎 | 移动端为主,全平台通用 |
| Unreal Engine | 商业引擎 | PC/主机,高画质项目 |
| Cocos2d‑x | 开源引擎 | 2D手游项目 |
表 1:几款经典游戏引擎简单对比表
那是不是意味着自研引擎已经走向没落?答案是否定。
-
✅适合自研迭代:团队技术储备充足、开发周期宽裕,已有成熟游戏产品沉淀,持续迭代自家引擎可以最大化定制化、性能优势。
-
✅适合选用商业引擎:项目工期紧张,新项目品类和旧引擎定位差异巨大,修改老引擎的人力成本超过学习商业引擎。
两种路线没有绝对好坏,只看项目的现实条件。
三、引擎一定要依附游戏而生吗?理想与现实的鸿沟🤔
有一个很经典的议题:开发游戏引擎,是否必须依托具体游戏项目迭代?
回顾历史,绝大多数传统引擎,都是伴随游戏产品打磨成长。游戏公司的首要目标是产出游戏,引擎作为工具服务游戏,游戏需要什么新特性,引擎就补什么功能。就算是虚幻引擎,早期也是依靠自家《虚幻竞技场》来验证能力。一款引擎如果没有经过商业游戏验证,普通开发者不敢轻易上手,底层出现问题很难自己修复。所以很多引擎仅限公司内部使用,出问题可以引擎组快速跟进。
海外有一部分团队尝试让引擎技术独立演进,引擎技术反过来推动游戏设计创新,而不是完全被游戏需求牵着鼻子走。但直到今天,"万能引擎" 依旧只是幻想,不存在引擎可以同时满足下面全部三点:
-
适配全部游戏类型,覆盖所有游戏功能;
-
轻松实现设计师天马行空的各类创意;
-
极致运行效率,业内事实:性能优化做到天花板的引擎,几乎都是针对特定游戏深度定制。
引擎团队心中的理想蓝图:底层与上层游戏业务维护互相分离,统一架构,一套引擎可以赋能多款完全不同品类游戏。但理想遇到现实,最大阻碍来自人的成本,包括技术人员能力、管理、招聘等一系列人力因素。虚幻 3 足够通用,但想要完全驾驭它,对开发者技术功底要求极高。
而 Unity 的出现打破了僵局。它不仅仅是简单做到组件化架构,更是巧妙解决 "人的成本" 这个难题。Unity 自身并不拥有现象级自研游戏,但是构建起庞大社区:世界各地开发者为它开发插件、工具。地形系统、IK 反向动力学、材质编辑器、技能系统、海量美术资源,大部分扩展能力来自社区贡献。官方只维护最核心底层,开发者社区源源不断补充上层能力,开发者之间互相受益。
Unity 巨大的竞争压力倒逼竞争对手进化。Unreal 选择开放源代码,吸引更多开发者做插件、沉淀社区方案,网上可以搜到绝大多数常见坑位的解决方案,社区生态愈发壮大。
写在最后💡
游戏引擎没有唯一标准答案,没有绝对完美。
从 FC 时代剥离出来的几百行通用逻辑,到如今几十万行代码的巨型商业引擎,引擎技术一路进化。自研引擎可以极致定制,商业引擎依靠社区生态降低门槛。做项目的时候,不必盲目追逐 "最强引擎",看清项目工期、团队能力、产品需求,选出适配自己的工具,才是最重要的。
本文参考:《游戏引擎原理与实践 卷 1 基础框架》

如果你需要,我可以继续为你扩展,补充更多引擎子系统(渲染、物理)的讲解,或是增加更多 C++ 示例代码。