322 lines
12 KiB
Markdown
322 lines
12 KiB
Markdown
# 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);
|
||
}
|
||
}
|
||
```
|
||
|
||
请确认此方案后,我将开始
|