Skip to content

Desktop 接入指南

本文档面向 Windows、macOS、Linux 桌面应用开发者,介绍如何将 NovaMark 运行时接入桌面端应用。


1. 架构选型

桌面端有两种主流接入方式,根据你的项目需求选择:

方案 A:嵌入式 WebView + WASM

将 NovaMark 编译为 WebAssembly,在桌面应用中嵌入 WebView 运行。

适合场景

  • 已有 Web 前端团队
  • 需要快速验证原型
  • 渲染逻辑复用 Web 模板
  • 需要热更新能力

实现要点

  • 使用平台原生 WebView 控件
  • NovaMark WASM 模块通过 JS 桥接与宿主通信
  • 宿主提供文件系统、存档等原生能力桥接

注意事项

  • WebView 渲染性能略低于原生
  • 需要处理跨平台 WebView 差异
  • 原生能力调用需要额外的桥接层

方案 B:原生渲染

直接使用 C API 集成 NovaMark VM,在原生层实现渲染。

适合场景

  • 追求最佳性能
  • 需要深度定制渲染管线
  • 需要直接访问原生能力
  • 已有成熟的原生 UI 框架

实现要点

  • 通过 C API 加载 .nvmp 包并控制 VM
  • 宿主轮询或监听 NovaState 变化
  • 自行实现所有 UI 渲染逻辑

注意事项

  • 需要自行实现文本渲染、图片显示、音频播放
  • 多平台可能需要多套渲染代码
  • 开发周期相对较长

2. 接入步骤

第一步:准备运行时

无论选择哪种方案,都需要:

  1. 获取 NovaMark 运行时

    • WebView 方案:编译 WASM 模块
    • 原生方案:编译 C API 静态库 / 动态库
  2. 准备测试包

    • 使用 nova-cli build 构建一个简单的 .nvmp 测试包
    • 确保包可以正常加载

第二步:实现基础控制流

实现以下核心功能:

加载包

加载 .nvmp 文件到 VM
初始化运行时状态

推进剧情

调用 advance(),让 VM 推进到下一个需要宿主处理的状态点。

处理选择

调用 choose(choiceId),告诉 VM 玩家选择了哪个选项。

验证标准

  • 能够加载包并显示初始对话
  • 能够推进对话直到出现选择
  • 能够选择选项并继续剧情

第三步:接入运行时状态

将 NovaState 的关键字段接入你的渲染层:

状态字段用途
dialogue当前对话文本、说话角色
choices可选选项列表
bg背景图资源引用
sprites立绘资源引用
bgm / sfx音频资源引用
variables变量值(用于 UI 显示)
inventory物品背包状态

状态读取原则

  • 宿主只读取状态,不直接修改
  • 所有状态变更由 VM 驱动
  • 宿主根据状态决定如何渲染

第四步:实现渲染提示处理

NovaMark 脚本中可能包含渲染提示字段:

字段含义宿主处理建议
transition过渡效果类型解析并实现过渡动画
position元素位置映射到布局坐标
opacity透明度控制元素淡入淡出
loop是否循环播放控制音频/动画循环
volume音量控制音频播放音量

重要:这些字段是渲染提示,不是引擎自动执行的行为。宿主负责解释和实现。

第五步:实现存档功能

NovaMark 提供两种存档格式:

正式存档(二进制)

  • 用于生产环境
  • 体积小、加载快
  • 通过 C API 的存档接口操作

调试快照(JSON)

  • 用于开发和调试
  • 可读性好
  • 方便排查状态问题

建议

  • 开发阶段先用 JSON 快照验证存档逻辑
  • 生产环境切换到二进制格式

3. 状态驱动渲染

NovaMark 的核心设计是状态驱动,理解这一点对桌面端接入至关重要。

什么是状态驱动

┌─────────────┐     状态变化      ┌─────────────┐
│   NovaMark  │ ───────────────▶ │    宿主     │
│     VM      │                  │   渲染器    │
└─────────────┘                  └─────────────┘
                                      │
                                      ▼
                                 更新 UI 显示

引擎维护 NovaState,宿主负责"观察"这个状态并渲染。

事件循环模式

典型的桌面端事件循环:

1. 用户输入(点击/按键)
       │
       ▼
2. 宿主调用 advance() 或 choose()
       │
       ▼
3. VM 更新 NovaState
       │
       ▼
4. 宿主读取新状态
       │
       ▼
5. 宿主更新渲染
       │
       ▼
6. 等待下一次用户输入

宿主的渲染职责

根据 NovaState,宿主需要决定:

  • 对话如何显示:文本框样式、打字机效果、角色名显示位置
  • 选项如何呈现:按钮样式、布局、动画
  • 背景/立绘如何切换:过渡效果、动画时长
  • 音频如何播放:BGM 切换、音效触发
  • UI 何时出现:菜单、存档界面、设置面板

这些全部由宿主控制,脚本不干预。


4. 输入处理

核心输入动作

桌面端需要处理以下输入:

输入类型对应 VM 操作说明
点击/回车advance()推进到下一个状态点
选择选项choose(choiceId)玩家做出选择

扩展输入(可选)

除了核心输入,宿主可以自行决定是否支持:

  • 快捷键:存档/读档/快进/自动播放
  • 历史回看:显示之前的对话
  • 菜单按钮:打开设置/存档界面

这些功能由宿主自行实现,VM 不感知。

输入时机

只在特定状态允许输入:

  • 有对话时:允许 advance()
  • 有选项时:禁止 advance(),只允许 choose()
  • 空闲状态:允许打开菜单

宿主需要根据 NovaState 判断当前允许的输入类型。


5. 存档管理

存档数据内容

NovaMark 存档包含:

  • 当前执行位置(场景/标签)
  • 所有变量值
  • 物品背包状态
  • 已触发的结局/事件标记

存档操作流程

保存

1. 调用 VM 的存档接口获取快照数据
2. 将数据写入本地文件
3. 可选:生成存档元信息(时间戳、截图等)

加载

1. 从文件读取快照数据
2. 调用 VM 的读档接口恢复状态
3. 根据恢复的 NovaState 更新渲染

多存档槽位

如果需要多存档槽位:

  • 由宿主管理槽位列表和元信息
  • 每个槽位对应一个独立的存档文件
  • VM 只负责生成/消费单个存档数据

6. 调试建议

使用 JSON 快照

开发阶段建议使用 JSON 快照格式:

  • 可以直接查看状态内容
  • 方便定位渲染问题
  • 易于自动化测试

状态变化日志

建议在开发版本中记录:

  • 每次 advance() / choose() 调用
  • NovaState 关键字段的变化
  • 渲染提示字段的值

与 Web 模板对照

如果渲染结果不符合预期:

  1. 使用相同包在 Web 模板中运行
  2. 对照 Web 模板的状态显示
  3. 找出差异点定位问题

常见问题排查

问题排查方向
对话不显示检查 dialogue 字段是否正确读取
选项无法选择检查 choices 列表和 choiceId 映射
背景不切换检查 bg 字段和资源加载
存档无法恢复检查快照数据完整性

7. 总结

桌面端接入 NovaMark 的关键要点:

  1. 理解状态驱动模型:VM 管状态,宿主管渲染
  2. 选对架构方案:WebView 快速验证,原生渲染性能最优
  3. 按步骤接入:先跑通流程,再完善细节
  4. 重视存档分离:开发用 JSON,生产用二进制
  5. 善用调试工具:快照日志和 Web 模板对照

接入完成后,你的桌面应用就能运行 NovaMark 游戏内容了。

Last updated on