2026年6月1日,Casey Muratori在他的Molly Rocket频道发布了一段2.5小时的访谈视频,邀请了游戏开发传奇人物Marc "Mahk" LeBlanc,完整还原了Entity Component System(ECS)这一改变游戏编程范式的架构模式是如何在Looking Glass Studios的几款经典游戏中一步步演化出来的。
这不是一个"理论先行"的故事。ECS的诞生没有任何学术论文的背书,没有任何设计模式的教科书指导。它是一群90年代初的游戏开发者,面对真实项目中的真实问题——C++内存碎片、继承地狱、编译时间爆炸——硬生生踩出来的解决方案。
如果你是一名程序员,无论你写的是游戏引擎还是后端服务,这个故事都会让你重新思考"面向对象"的边界在哪里,以及为什么"组合优于继承"不只是GoF设计模式里的一句口号。
| 项目 | 内容 |
|---|---|
| 视频标题 | The First Entity Component System - An Interview with Marc LeBlanc |
| 频道 | Molly Rocket (Casey Muratori) |
| 发布日期 | 2026年6月1日 |
| 时长 | 约150分钟(2.5小时) |
| 核心主题 | ECS架构模式在Looking Glass Studios的历史演化 |
| 伴随文章 | computerenhance.com("The First Entity Component System") |
Marc LeBlanc(圈内人称"Mahk")的ECS故事不是从某个天才灵光一闪开始的,而是从Looking Glass Studios(最初叫Blue Sky Productions)的第一个项目——Ultima Underworld开始的。
Ultima Underworld(1992年)是第一人称3D RPG的先驱。在那个年代,"游戏对象"的概念还很原始——地牢里的剑、怪物、门、陷阱,本质上都是硬编码的数据结构。没有统一的"实体"概念,没有组件化的思维,每个游戏对象就是一个C struct,里面塞满了所有需要的字段。
但问题很快就出现了:当你的游戏里有几百种不同的物体,每种物体有不同的行为、不同的属性、不同的交互方式,硬编码的方式开始崩塌。你想让一扇门既能被打开,又能被火烧毁,还能被法师用魔法解锁——这三种行为属于完全不同的"系统",但在传统的面向对象设计中,你必须把它们都塞进一个Door类里,或者创建一个深得可怕的继承树。
Mahk在访谈中回忆道,到了System Shock(1994年)时期,这种紧张感已经非常明显了。System Shock是一个野心远超Underworld的项目——更复杂的环境交互、更多的物体类型、更丰富的AI行为。团队开始意识到,他们需要一种更灵活的方式来组织游戏对象。
这是我的延伸分析:这个痛点其实不仅限于90年代的游戏开发。2026年的今天,任何写过大型OOP项目的人都经历过类似的痛苦——当一个类的继承深度超过3层,当你需要用多继承或mixin来组合不同行为,当修改基类的一个方法导致几十个子类出bug——这些都是同一类问题的不同表现形式。Looking Glass遇到的不是游戏开发特有的问题,而是面向对象范式在复杂领域建模时的根本局限。
访谈中最令人会心一笑的段落是Flight Unlimited(1995年)的"batch file故事"。
Flight Unlimited是Looking Glass的飞行模拟器,使用了当时最先进的C++特性。但C++的动态内存管理在那个年代有一个致命的问题——内存碎片(memory fragmentation)。程序运行一段时间后,频繁的new/delete会导致堆内存变得支离破碎,即使总可用内存充足,也无法分配出连续的大块内存,最终导致崩溃。
Mahk的解决方案是什么?直接重启游戏。
Flight Unlimited的发行版里包含了一个batch文件,内容大致如下:
@echo off
set dos4g=quiet
Y:\cdrom\flight.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
:wacky
if errorlevel 44 goto done
if errorlevel 43 goto refuel
if errorlevel 42 goto credit
goto done
:credit
Y:\cdrom\credits.exe
Y:\cdrom\flight.exe +fromcredits %1 %2 %3 %4 %5 %6 %7 %8 %9
goto wacky
:refuel
Y:\cdrom\flight.exe +refuel %1 %2 %3 %4 %5 %6 %7 %8 %9
goto wacky
:done
Mahk特别指出,这个batch文件里有个goto标签叫wacky,他说:"如果有什么东西能证明这是一个真正的LG(Looking Glass)产品,那就是用'wacky'作为goto标签。"
为了验证这段历史,Mahk在访谈中当场拆封了一盘全新未拆的Flight Unlimited原版光盘,从CD上安装游戏,确认了这个batch文件的存在。
延伸分析:这个故事听起来像个笑话,但它揭示了一个深刻的教训——C++的内存管理问题直接驱动了ECS的设计哲学。后来的ECS系统普遍采用"数据导向设计"(Data-Oriented Design, DOD),将同类组件的内存连续排列,避免碎片化的堆分配。这不是巧合,而是Looking Glass一代开发者用血泪换来的经验教训。Mike Acton在CppCon 2014上关于数据导向设计的著名演讲,其精神源头可以追溯到Looking Glass的这些实践经验。
Thief: The Dark Project(1998年)是ECS模式真正成型的地方。
Thief的设计野心前所未有:一个以潜行为核心的3D游戏,NPC需要复杂的AI行为(巡逻、搜索、听声辨位、记忆玩家位置),物体需要丰富的交互(灯光可以被熄灭、地面材质影响脚步声、箭矢可以粘在墙上),环境需要动态响应(AI对环境变化的感知、声光传播系统)。
在访谈中,Mahk详细描述了Thief的entity system是如何演化的。核心思想可以概括为几个关键决策:
1. 实体只是ID
在Thief中,一个游戏实体不再是一个C++对象,而只是一个整数ID。这个看似简单的改变意味着实体不再和任何特定的类或继承层次绑定。
2. 属性(Property)是数据包
每个实体可以拥有任意数量的"属性"——位置属性、渲染属性、AI属性、物理属性、声音属性。这些属性本质上就是键值对,存储在全局的属性管理器中,按实体ID索引。
3. 行为通过消息传递
实体之间的交互不再通过方法调用,而是通过消息系统。一个AI实体"听到"声音,不是因为它有一个hear()方法,而是因为声音系统向它发送了一条"声音事件"消息。
4. 系统(System)是独立的处理器
渲染系统、物理系统、AI系统、声音系统——每个系统独立运行,遍历拥有对应属性的实体集合,执行自己的逻辑。系统之间通过消息松耦合。
这就是ECS的核心架构——Entity(实体)、Component(组件,即Thief中的属性)、System(系统)。术语不同,本质一致。
我的延伸分析:Mahk提出了一个非常关键的洞察——"a compile-time hierarchy that matches the domain model"(一个匹配领域模型的编译时层次结构)。这句话的意思是,你在代码中定义的类继承关系,应该精确反映你的游戏域模型中的"是什么"关系,而不是试图用继承来表达"有什么"和"能做什么"。
一把剑"是一个"物品,"有"攻击力属性,"能"被挥舞。在传统OOP中,这三个关系都被塞进了继承树。在ECS中,"是一个"用Entity表达,"有"用Component表达,"能"用System表达。这种分离让每个关注点都能独立变化,而不需要修改任何基类。
Casey Muratori在2025年的Better Software Conference上做了一个名为"The Big OOPs"的演讲,核心论点是:OOP的继承机制被严重滥用了。ECS的故事是这个论点的最佳证据。
在访谈的伴随文章中,Casey写道:这是"Big OOPs补充材料系列"的第一篇,后续还会发表多篇论文综述,还原ECS演化的完整历史。
延伸分析:ECS的影响早已超出了游戏开发的边界。
在Web开发中,React的Hooks和函数式组件本质上就是ECS的变体——组件(Component)只描述UI的数据和逻辑,React的调度系统(System)负责渲染和更新。Vue 3的Composition API也是类似的思想。
在数据库领域,列式存储(Column-oriented Storage)和数据导向设计如出一辙——把同类数据连续存储,而不是按行(按对象)存储。ClickHouse、Snowflake等现代数据仓库的性能优势,部分就来自这种"面向数据"的思维方式。
在微服务架构中,每个服务就是一个"System",处理特定类型的数据(Component),服务之间通过消息队列通信——和Thief的消息系统异曲同工。
Marc LeBlanc不仅是一位传奇程序员,还是游戏设计理论的重要贡献者。他的8kindsoffun.com网站详细阐述了他的"8种乐趣"游戏设计框架:
他还与人共同提出了MDA(Mechanics-Dynamics-Aesthetics)框架,这是游戏设计领域最广泛使用的形式化分析工具之一。
这种双重身份——顶尖程序员+顶尖设计师——让Mahk对ECS的理解超越了纯粹的技术层面。他不是在设计一个"更快的内存布局",他是在寻找一种架构,能让设计师更自由地创造复杂的游戏体验,而不被代码结构所束缚。
从Looking Glass的开创性工作到2026年,ECS已经发展出一个庞大的生态系统:
值得注意的是,这些现代ECS在性能优化上走得更远——利用CPU缓存行对齐、SIMD指令、无锁并发等技术——但其核心架构思想和1998年的Thief惊人地一致。
Casey和Mahk做这个访谈的意义不仅仅是怀旧。它解决了一个困扰游戏开发社区多年的问题——ECS的"发明"到底归功于谁?
在此之前,ECS的起源有多个相互矛盾的说法。有人归功于Adam Martin在2007年的博客文章,有人追溯到Scott Bilas在GDC 2002的演讲,有人提到Thatcher Ulrich的早期工作。但真正在商业产品中首次实现完整ECS架构的,是Looking Glass Studios在1998年的Thief: The Dark Project。
这个访谈通过第一手口述历史,为ECS的起源提供了权威的、可追溯的记录。对于软件工程的历史研究者来说,这是一份珍贵的史料。
mindmap
root((ECS的演化))
先驱阶段
Ultima Underworld 1992
硬编码的C struct
无统一实体概念
System Shock 1994
更复杂的物体交互
OOP继承树的痛苦开始显现
Flight Unlimited 1995
C++内存碎片灾难
用batch file重启游戏作为"解决方案"
诞生阶段
Thief The Dark Project 1998
实体 = ID
属性Property = 数据包
消息传递替代方法调用
系统System = 独立处理器
核心洞察
Mahk的关键短语
编译时层次匹配领域模型
组合优于继承
数据与行为分离
现代生态
Unity DOTS
Bevy Rust
EnTT C++
Flecs C
跨领域影响
React Hooks
列式存储数据库
微服务消息架构
如果你正在开发游戏,尤其是使用Unity、Unreal或自研引擎,这个视频传达的核心教训是:不要用继承来建模你的游戏世界。
具体来说: - 从第一天起就把游戏对象设计为ID+组件的组合,而不是一棵继承树 - 系统之间通过事件/消息通信,而不是直接调用彼此的方法 - 关注数据的内存布局——同类组件连续存储,能带来10x-100x的性能提升 - 让设计师(而非程序员)定义实体有什么组件,通过配置文件而非代码
即使你不做游戏开发,ECS的思想也值得借鉴:
ECS的本质是一种关注点分离(Separation of Concerns)的极致实践。传统的OOP把数据和行为绑定在同一个对象中,而ECS把它们彻底分离——数据在Component中,行为在System中,Entity只是两者的粘合剂。这种分离让你可以在不修改任何现有代码的情况下,给实体添加新的能力和行为。
ECS不是一个天才的发明,而是一群90年代的游戏开发者被C++继承和内存碎片逼到墙角后,用150分钟口述历史还原的"生存智慧"——而这段智慧,在今天依然是所有程序员对抗复杂性的利器。
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
