GDevelop 架构深度解析:Core、GDJS、Extensions、GDevelop.js 与 newIDE 五大模块的设计与协作
2026/9/22 7:25:17 网站建设 项目流程

GDevelop 架构深度解析:Core、GDJS、Extensions、GDevelop.js 与 newIDE 五大模块的设计与协作

【免费下载链接】GDevelop🎮 Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.项目地址: https://gitcode.com/GitHub_Trending/gd/GDevelop

导读

GDevelop 是一个开源、跨平台的 2D/3D/多人游戏引擎,其代码仓库的顶层目录结构本身就是一套清晰的架构宣言:Core负责描述与操作游戏工程结构,GDJS是纯 TypeScript 编写的运行时游戏引擎,Extensions提供可插拔的对象、行为与事件扩展,GDevelop.js通过 Emscripten/WebIDL 把 C++ 世界桥接到浏览器,newIDE则是基于 React 的图形化编辑器。本文基于 Core/GDevelop-Architecture-Overview.md 展开,结合仓库内真实源码与测试,帮助你理解"IDE 部分"与"Runtime 部分"的分界、事件如何被转译为真实代码、三个 Extensions 文件夹为何并存,以及 GDevelop.js 桥接层的工作方式——读完即可在源码树中快速定位任意功能模块。

顶层目录:五张名片,一条主线

GDevelop 的架构围绕一个核心思想展开:编辑器(IDE)与游戏引擎(Runtime)解耦,编辑器使用所有底层库来读写、校验并导出游戏,而导出的游戏只依赖运行时引擎。仓库根目录下五个主要目录的分工如下:

目录说明
CoreGDevelop 核心库,包含实现 IDE 与处理 GDevelop 游戏所需的通用工具,全部为 C++ 实现。
GDJS游戏引擎,用 TypeScript 编写,基于 PixiJS(WebGL),驱动所有 GDevelop 游戏运行。
GDevelop.jsCoreGDJSExtensions到 JavaScript(WebAssembly)的绑定层,供 IDE 使用。
newIDE游戏编辑器,用 JavaScript + React + Electron + PixiJS 编写(另有 web 版本)。
Extensions游戏引擎的扩展,提供对象、行为、事件与各种新特性。

主线关系是:newIDE(编辑器)通过GDevelop.js桥接层调用Core的 C++ 类来操作工程结构,通过GDJS/GDJS的 C++ 声明获得导出与代码生成能力,最终产出包含GDJS/Runtime代码的游戏包。

先厘清两个概念:Runtime 与 IDE

文档用两个词区分整个仓库中的所有代码:

  • IDE(Integrated Development Environment):指编辑器本身。浏览CoreGDJS的子目录时,你会看到名为IDE的文件夹,里面的类与工具只对编辑器有用,并非描述游戏结构的必需品。例如 Core/GDCore/IDE 中存放的就是编辑器侧的操作工具。
  • Runtime:指游戏运行期间使用的类、工具与源码,也就是常说的"游戏引擎"。GDJS子目录下的Runtime文件夹就是 GDevelop 的游戏引擎本体,全部由 TypeScript 编写。

扩展(Extensions)同样遵循这一区分:大多数扩展都包含两部分——一个用于IDE的声明文件JsExtension.js,以及一个或多个实现游戏内功能的Runtime文件,例如 Runtime Object、Runtime Behavior,或由动作/条件调用的工具函数。

gd::Variable理解两层世界的隔离

文档用变量类作为最佳例证:GDevelop 允许开发者在游戏中创建和操作变量,但这一概念在仓库中对应两个互不相干的实现

  • 编辑器侧的gd::Variable:属于游戏工程结构的一部分,定义在 Core/GDCore/Project/Variable.h。编辑器界面中展示的、保存到工程文件(JSON)里的就是这个类。
  • 游戏引擎侧的gdjs.Variable:定义在 GDJS/Runtime/variable.ts,是游戏运行时真正使用的 JavaScript 类。

两个类的关系近乎"失联":编辑器gd::Variable对引擎类gdjs.Variable一无所知;引擎类除了知道如何读取默认变量写入的 JSON 格式之外,对gd::Variable也几乎一无所知。从variable.ts源码可以看到gdjs.Variable的构造逻辑正是从childData(JSON 数据)递归构建子变量树。

文档还指出一个命名上的小"历史遗留":gdjs.Variable其实应该叫gdjs.RuntimeVariable,与gdjs.RuntimeObject以及引擎中绝大多数类的命名保持一致。

这种刻意隔离正是 GDevelop 架构的精髓:编辑器保存的工程结构只是"设计图",游戏运行时则是完全独立的执行世界,两者通过序列化(JSON)单向沟通。

Core 内部:游戏结构的描述与操作

Core(即GDCore文件夹)本质上包含描述和操作游戏结构(内部称为Project)所需的全部内容:事件、场景(Layout)、对象、行为、变量等,均以 C++ 类实现于 Core/GDCore/Project 目录。从目录清单可以直观看到它的覆盖面:

  • 工程与场景:Project.hLayout.hLayersContainer.hExternalLayout.hExternalEvents.h
  • 对象与行为:Object.hBehavior.hBehaviorsContainer.hCustomBehavior.hEventsBasedObject.hEventsFunctionsExtension.h
  • 变量:Variable.hVariablesContainer.h
  • 初始实例与资源:InitialInstance.hInitialInstancesContainer.hResourcesContainer.h

除了数据模型,Core还提供操作 Project 的工具。Core/GDCore/IDE 目录包含允许对游戏结构执行复杂操作的 C++ 类,其中最典型的是 WholeProjectRefactorer——一个非常强大的工具,用于在项目中重命名所有对象、在对象被删除后自动更新事件,以及执行各种全局性的工程重构。该目录下还有其他工具函数,例如操作项目资源的系列类(ResourcesMergingHelperResourcesRenamerArbitraryResourceWorker等,均可在 GDevelop.js/Bindings/Wrapper.cpp 的 include 清单中看到),以及在事件中搜索的工具(EventsIdentifiersFinderEventsVariablesFinderEventsRefactorer等)。

GDJS 内部:为什么这里也有 C++ 文件

GDJS目录下同时存在两个世界:

  • GDJS/Runtime:真正的游戏引擎,全部用 TypeScript 编写,是游戏运行期间被执行的代码。
  • GDJS/GDJS:GDJS 的 "IDE 部分",即用 C++ 编写的、向编辑器描述各种能力的类,例如:
    • 导出如何完成:导出流程相关的声明;
    • 默认扩展有哪些:该目录下有SpriteExtensionAudioExtensionCommonInstructionsExtensionKeyboardExtensionMouseExtensionTimeExtensionVariablesExtensionSceneExtension等 19 组内置扩展,负责把编辑器中的动作/条件/表达式映射到具体的 TypeScript 或 C++ 函数;
    • 如何从事件生成 JS 代码:该目录包含EventsCodeGeneratorLayoutCodeGeneratorObjectCodeGeneratorBehaviorCodeGeneratorEventsFunctionsExtensionCodeGenerator等核心代码生成器。

事件系统:从空壳到真实代码

事件是一块"几乎为空"的容器

在 GDevelop 中,一个"事件"(event)默认情况下几乎什么都没有。用传统编程语言类比,事件相当于一个作用域/代码块(如 C 系语言里的{ 一些代码 })。

内置事件默认在 GDevelop Core 中定义。从目录可见既有StandardEvent(标准事件,含条件与动作),也有ForEachEventWhileEventRepeatEventGroupEventCommentEventElseEventLinkEventAsyncEvent等控制流事件。其中StandardEvent拥有条件(conditions)与动作(actions),而条件和动作本质上都是gd::Instruction的列表。

gd::Instruction:一个"函数调用"

一个gd::Instruction只是一个类型(动作或条件的名称)加若干参数。可以把它想象成编程语言中的函数调用:add(2, 3)就是调用名为 "add" 的函数并传入参数 "2" 和 "3"。条件特殊之处在于它是返回 true 或 false 的函数,并且可能被用来对对象进行过滤——从而影响后续条件和动作"拾取"(picking)到的对象集合。

为什么游戏运行时看不到任何 "RuntimeEvent"?

因为它们已经不存在了。事件会被翻译(文档中也称"转译"或"生成",即 transpiled / generated)成真正的编程语言代码,这个过程叫Code Generation(代码生成),对 TypeScript 游戏引擎而言发生在 GDJS/GDJS/Events/CodeGeneration。也就是说,编辑器中可视化编排的事件,在导出时被EventsCodeGenerator等 C++ 类直接转译为GDJS/Runtime中可执行的 JavaScript/TypeScript 逻辑,运行时不再保留事件对象本身。这也是 GDevelop 事件系统性能与运行时纯净度的根源。

三个 Extensions 文件夹:为什么会有三个?

GDevelop 编辑器和游戏引擎的设计理念是:引擎本身保持精简,几乎不内置任何功能,通过"模组 / 插件 / 模块"来按需添加能力,GDevelop 称之为Extensions(扩展)。仓库中有三个 Extensions 相关目录,职责各不相同:

目录职责
Core/GDCore/Extensions默认(内置)扩展的声明,任何游戏都可用且"必须存在"。虽然名为 Extensions,但本质相当于编程语言中的标准库(Standard Library)。
GDJS/GDJS/Extensions复用上述声明并追加自己的声明。主要工作是为每个动作、条件或表达式指定要调用的函数名(可以是 TypeScript 函数或 C++ 函数)。
Extensions真正的"模组 / 插件"目录——非必需的扩展。它们不属于 GDCore,独立运作。

文档特别说明:理论上所有扩展都可以搬到Extensions/,但实践中保留一组"内置扩展"提供基础能力更务实。

GDevelop.js:把 C++ 世界桥接给 JavaScript 编辑器

GDevelop.js的一切都服务于一个目标:为 IDE 建立 C++ 与 JavaScript 之间的"桥",让编辑器完全用 JavaScript 编写,并能在浏览器中运行(即newIDE)。

其技术要点:

  1. Emscripten 编译 C++:与编译"原生二进制"不同,Emscripten 产出的是能在浏览器中运行的文件(本质是 JavaScript + WebAssembly)。
  2. Bindings.idl是核心文件:GDevelop.js/Bindings/Bindings.idl 描述了 C++ 中需要暴露给 JavaScript 的每一样东西。需要强调:这些暴露只服务于编辑器——游戏运行时(Runtime)中这一切都不存在。
  3. 其余文件是桥接代码:负责 JS ↔ C++ 的双向翻译。这需要理解 Emscripten 生成的名为 WebIDL 的"桥"机制。除非你想把某个 C++ 类暴露给编辑器、且仅写Bindings.idl接口还不够,否则通常不需要深入这些文件——90% 的情况下,在Bindings.idl中读写一个类的声明即可。

GDevelop.js 的底层细节

所有需要参与编译的 C++ 文件都被集中引入到 GDevelop.js/Bindings/Wrapper.cpp 这个巨大的头文件清单中(该文件共 984 行,前 90 行即包含GDCore/Events/Builtin/*全部内置事件、GDCore/IDE/Events/*全部事件工具、GDCore/Project/*全部工程模型,以及GDCore/Extensions/Metadata/*元数据类)。C++ 编译由 CMake 构建系统驱动,依据 GDevelop.js/CMakeLists.txt 决定编译内容。

文档作者也坦言:理想情况下应有自动化手段完成这一过程,那样 GDevelop.js 文件夹甚至都不需要存在。

常见疑问:为什么这么多 C++ 与 JavaScript/TypeScript?

为什么用这么多 C++?

GDevelop 最初就是用 C++ 编写的。C++ 初学起来有些"吓人",但它几乎可以在现存任何机器上移植,配合最新的 C++ 特性可以写出相当高效、安全且可读的代码。Core、GDJS 的 IDE 部分以及扩展的声明层都依赖它。

为什么又用这么多 JavaScript/TypeScript?

JavaScript(配合最新语言提案)能力很强、编写快速,且有类型保障:

  • 现代浏览器 JIT 特性使性能不断提升;
  • 用于 GDevelop IDE 的前端框架 React 支持非常快速、模块化的界面开发;
  • Web 是跨平台(以及跨形态)应用无可比拟的发布目标。

更宏观地看,随着 WebGL 与 WebAssembly 的兴起,Web 也是游戏发布的绝佳目标——同时 GDevelop 也保持模块化,以便未来为导出游戏适配更新的平台。

总结:一张地图定位整个仓库

把全文浓缩成一张"寻路地图":想看工程结构模型去 Core/GDCore/Project;想看编辑器侧的重构/搜索工具去 Core/GDCore/IDE;想看事件如何变成代码去 GDJS/GDJS/Events/CodeGeneration;想看游戏真正跑起来的逻辑去 GDJS/Runtime;想看可插拔新特性怎么声明去 Extensions/ExampleJsExtension;想看C++ 如何暴露给 JS 编辑器去 GDevelop.js/Bindings/Bindings.idl。理解了 "IDE 部分"与 "Runtime 部分"这条分界线,GDevelop 的每一行代码都会各归其位。

【免费下载链接】GDevelop🎮 Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.项目地址: https://gitcode.com/GitHub_Trending/gd/GDevelop

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询