# Extra2D 模块化脚本系统融合方案 结合 **Yosin 的配置驱动脚本加载** 和 **Kiwano 的模块系统**,为 Extra2D 实现一个强大的模块化 Squirrel 脚本架构。 ## 融合架构设计 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ Extra2D.exe (C++ 引擎) │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Application (单例) │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ ModuleList (模块列表) │ │ │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ │ │ │ │ │ ScriptModule│ │ AudioModule │ │ PhysicsModule │ │ │ │ │ │ │ │ (脚本系统) │ │ (音频系统) │ │ (物理系统) │ │ │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ - Run() - 运行应用 │ │ │ │ - Use(Module&) - 注册模块 │ │ │ │ - Update(dt) - 更新所有模块 │ │ │ │ - Render() - 渲染所有模块 │ │ │ └─────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ ScriptModule (脚本模块) │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Squirrel VM │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ ScriptConfig.cfg (配置驱动) │ │ │ │ │ │ - 定义脚本加载顺序 │ │ │ │ │ │ - 定义模块依赖关系 │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ 加载流程: │ │ │ │ 1. 加载 Core 层 (基础工具类) │ │ │ │ 2. 加载 Engine 层 (引擎封装类) │ │ │ │ 3. 执行 User/main.nut (用户入口) │ │ │ │ │ │ │ │ 每帧调用: │ │ │ │ - OnUpdate(dt) -> 调用脚本的 update 函数 │ │ │ │ - OnRender() -> 调用脚本的 render 函数 │ │ │ └─────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ Squirrel 脚本层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Core/ │ │ Engine/ │ │ User/ │ │ Modules/ │ │ │ │ │ │ │ │ │ │ │ │ │ │ _init.nut │ │ _init.nut │ │ main.nut │ │ ui.nut │ │ │ │ class.nut │ │ app.nut │ │ stages/ │ │ network.nut │ │ │ │ array.nut │ │ director.nut│ │ objects/ │ │ ... │ │ │ │ math.nut │ │ stage.nut │ │ ui/ │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ ``` ## 核心组件设计 ### 1. Module 基类(来自 Kiwano) ```cpp // base/module.h class Module { public: virtual void setupModule(); // 初始化 virtual void destroyModule(); // 销毁 virtual void onUpdate(float dt); // 更新 virtual void onRender(); // 渲染 virtual void handleEvent(Event* evt); // 事件 }; ``` ### 2. ScriptModule(脚本模块) ```cpp // script/script_module.h class ScriptModule : public Module { public: void setupModule() override { // 1. 初始化 Squirrel VM vm_ = sq_open(1024); // 2. 注册 C++ 绑定 registerBindings(vm_); // 3. 读取 ScriptConfig.cfg auto config = loadConfig("scripts/ScriptConfig.cfg"); // 4. 按顺序加载脚本 for (auto& path : config.preload) { executeFile(path); } // 5. 调用 main 函数 callMainFunction(); } void onUpdate(float dt) override { // 调用脚本的全局 update 函数 callScriptFunction("onUpdate", dt); } }; ``` ### 3. 脚本配置系统(来自 Yosin) ``` # scripts/ScriptConfig.cfg # 定义脚本加载顺序 # ========== Core 层(基础工具)========== scripts/core/_init.nut scripts/core/class.nut scripts/core/array.nut scripts/core/table.nut scripts/core/math.nut scripts/core/string.nut # ========== Engine 层(引擎封装)========== scripts/engine/_init.nut scripts/engine/application.nut scripts/engine/director.nut scripts/engine/stage.nut scripts/engine/node.nut scripts/engine/sprite.nut scripts/engine/action.nut scripts/engine/audio.nut scripts/engine/input.nut # ========== User 层(用户逻辑)========== scripts/user/stages/start_stage.nut scripts/user/objects/player.nut scripts/user/ui/main_ui.nut scripts/user/main.nut # 入口脚本(最后加载) ``` ### 4. 脚本类层次结构(来自 Yosin) ```squirrel // scripts/core/class.nut // 基础类系统 // scripts/engine/node.nut class Node { C_Object = null; // C++ 对象指针 constructor() { C_Object = Node_Create(); Register_Destruction(C_Object, this); } function setPosition(x, y) { Node_SetPosition(C_Object, x, y); } function getPosition() { return Node_GetPosition(C_Object); } } // scripts/engine/stage.nut class Stage extends Node { constructor() { C_Object = Stage_Create(); } function enter() { Director_EnterStage(C_Object); } function onUpdate(dt) { // 子类重写 } } // scripts/engine/application.nut class Application { title = "Extra2D Game"; width = 1280; height = 720; function run(stageClass) { App_SetTitle(title); App_SetSize(width, height); App_Run(stageClass); } } ``` ### 5. 用户入口脚本(main.nut) ```squirrel // scripts/user/main.nut function main(args) { // 创建应用 local app = Application(); app.title = "My Game"; app.width = 800; app.height = 600; // 运行开始舞台 app.run(StartStage); } // 定义开始舞台 class StartStage extends Stage { function onEnter() { // 创建精灵 local sprite = Sprite("assets/logo.png"); sprite.setPosition(400, 300); this.addChild(sprite); // 创建 UI local ui = MainUI(); this.addChild(ui); } function onUpdate(dt) { // 每帧更新 } } ``` ## 实现步骤 ### 阶段 1: 基础架构 1. 创建 `base/module.h/cpp`(Kiwano 风格) 2. 修改 `Application` 支持模块注册 3. 实现模块生命周期管理 ### 阶段 2: 脚本模块 1. 创建 `script/script_module.h/cpp` 2. 实现配置解析(`ScriptConfig.cfg`) 3. 实现脚本加载器 ### 阶段 3: C++ 绑定扩展 1. 扩展 `Node` 绑定(添加 `C_Object` 指针桥接) 2. 添加 `Stage` 类绑定 3. 添加 `Director` 类绑定 4. 添加 `Application` 配置绑定 ### 阶段 4: 脚本类库 1. 创建 `scripts/core/` 基础工具 2. 创建 `scripts/engine/` 引擎封装 3. 实现类继承机制 ### 阶段 5: 入口机制 1. 实现 `main()` 函数自动调用 2. 实现 `GameWindow` 封装类 3. 创建示例项目 ## 文件变更清单 ### 新增文件 ``` src/extra2d/base/module.h src/extra2d/base/module.cpp src/extra2d/script/script_module.h src/extra2d/script/script_module.cpp src/extra2d/script/sq_binding_stage.cpp src/extra2d/script/sq_binding_director.cpp scripts/ScriptConfig.cfg scripts/core/_init.nut scripts/core/class.nut scripts/engine/_init.nut scripts/engine/application.nut scripts/engine/director.nut scripts/engine/stage.nut scripts/user/main.nut ``` ### 修改文件 ``` src/extra2d/app/application.h/cpp src/extra2d/script/script_engine.cpp src/extra2d/script/sq_binding_node.cpp ``` ## 最终效果 用户只需编写脚本即可创建完整游戏: ```squirrel // 纯脚本游戏 function main() { local app = Application(); app.config({ title = "Hello World", width = 800, height = 600 }); local director = Director(); director.enterStage(MyStage()); app.run(); } class MyStage extends Stage { function onEnter() { local label = Label("Hello Squirrel!"); label.position = [400, 300]; this.addChild(label); } } ``` 请确认此方案后,我将开始