Skip to content

iOS 接入指南

本指南面向需要在 iOS 平台接入 NovaMark 运行时的开发者。

架构选型

iOS 平台有两种主流接入方式,各有优劣:

WebView + WASM 方案

将 NovaMark 核心编译为 WebAssembly,在 WKWebView 中运行。

优点

  • 复用现有 Web 渲染器
  • 热更新友好,无需重新上架
  • 跨平台渲染一致性高
  • 开发迭代快

缺点

  • WASM 运行有额外开销
  • 原生能力调用需要桥接
  • 首次加载需要下载 WASM 模块

适用场景

  • 已有 Web 渲染器可复用
  • 需要快速上线
  • 对原生性能要求不高

原生渲染方案

通过 C API 直接集成 NovaMark VM,使用 Swift 或 Objective-C 实现原生 UI 渲染。

优点

  • 性能最优,无中间层开销
  • 直接访问 iOS 原生能力
  • 渲染效果完全可控
  • 可深度定制动画与交互

缺点

  • 需要自行实现完整渲染逻辑
  • 对话、选择、立绘、背景等都需要独立开发
  • 维护成本较高

适用场景

  • 追求极致性能
  • 需要深度原生定制
  • 已有成熟的 iOS UI 框架

接入步骤

第一步:准备 NovaMark 运行时

根据选择的方案:

WebView + WASM 方案

  1. 使用 Emscripten 将 NovaMark 编译为 WASM 模块
  2. 将 WASM 文件与 Web 渲染器模板打包
  3. 将资源文件放入 App Bundle 或通过服务器加载

原生渲染方案

  1. 将 NovaMark 编译为 iOS 支持的静态库或动态库
  2. 在 Xcode 项目中链接 C API 头文件
  3. 通过 FFI 或 Swift/C 桥接层调用

第二步:加载游戏包

NovaMark 游戏以 .nvmp 单文件格式分发。

核心操作

  • 从 App Bundle 读取游戏包
  • 或从服务器下载后缓存到本地
  • 调用加载接口初始化 VM

注意事项

  • 大型游戏包建议分块加载或后台预加载
  • 资源文件(图片、音频)可单独管理,按需加载

第三步:实现事件循环

NovaMark 采用 离散状态机 + 宿主控制推进 模型。

引擎不会自动播放,而是等待宿主的指令:

  • advance() - 推进到下一个阻塞点
  • choose(choiceId) - 玩家选择选项后继续

宿主需要:

  1. 监听用户输入(点击、滑动、按键等)
  2. 根据当前状态决定调用 advance() 还是 choose()
  3. 更新 UI 呈现新状态

状态驱动渲染

NovaMark 的核心设计原则:

引擎产出状态,宿主负责渲染

NovaState 结构

运行时状态是渲染的唯一数据源,包含:

字段说明
dialogue当前对话内容、说话角色、颜色
choices可选选项列表
bg背景图引用
sprites立绘列表与位置
bgm背景音乐引用
sfx音效引用
variables游戏变量
inventory玩家背包

渲染器职责

宿主拿到状态后,自行决定:

  • 对话框样式与位置
  • 立绘动画与过渡
  • 背景切换效果
  • 选项 UI 布局

脚本中的 transitionpositionopacity 等字段是 渲染提示,不是引擎自动执行的动画。宿主可以:

  • 遵循这些提示
  • 或忽略它们,用自己的渲染逻辑

文本配置

运行时状态包含 textConfig

  • defaultFont - 默认字体
  • defaultFontSize - 默认字号
  • defaultTextSpeed - 打字机速度

宿主应读取这些配置,实现打字机效果。


输入处理

advance() 触发时机

advance() 表示「继续推进,直到下一个需要宿主处理的状态点」。

常见的触发方式:

  • 点击对话框或屏幕空白区域
  • 按下特定按键
  • 语音指令(如果支持)

注意事项

  • 如果当前有选项,应禁止 advance() 调用
  • 应根据状态判断是否有对话待消费

choose(choiceId) 触发时机

choose(choiceId) 表示「玩家已选择某个选项」。

实现要点

  • 读取 choices 列表渲染选项 UI
  • 玩家选择后,传入对应的 choiceId
  • 选项 UI 应在调用后清空或隐藏

事件循环示例

用户点击 → 检查当前状态
         → 有选项?调用 choose(choiceId)
         → 无选项?调用 advance()
         → 等待状态更新
         → 重新渲染 UI

存档管理

NovaMark 提供两层存档格式:

二进制存档(正式)

用于玩家正式存档,格式紧凑、加载快。

宿主职责

  • 管理存档槽位
  • 存档缩略图(可选)
  • 存档时间戳
  • 云同步(可选)

JSON 快照(调试)

用于开发调试、测试验证。

用途

  • 在 Xcode 控制台打印状态
  • 导出快照在桌面端调试
  • 单元测试验证

不建议作为正式存档格式。

存档时机

NovaMark 不自动决定存档时机,宿主需要:

  • 在关键节点(章节结束、重要选择后)提示存档
  • 提供自动存档槽位
  • 实现快速存档 / 快速读档功能

调试建议

使用 JSON 快照

在开发阶段,导出 JSON 格式的运行时快照:

  • 在 Xcode 控制台检查变量值
  • 验证背包物品是否正确
  • 确认角色定义是否加载

运行时状态检查

通过运行时状态接口实时检查:

  • 当前场景与标签
  • 变量值变化
  • 物品数量

分阶段验证

推荐按以下顺序验证接入:

  1. 包加载 - 确认 .nvmp 文件正确加载
  2. 状态推进 - advance() 能正常推进对话
  3. 选项选择 - choose() 能正确处理分支
  4. 状态读取 - 能获取正确的运行时状态
  5. 存档恢复 - 存档后能正确恢复

常见问题排查

问题检查点
包加载失败文件路径、格式版本、资源完整性
对话不推进是否正确调用 advance()
选项无响应传入的 choiceId 是否正确
存档恢复异常快照格式、版本兼容性

宿主与脚本职责边界

正确理解职责分工是顺利接入的关键:

脚本负责

  • 剧情内容与分支逻辑
  • 角色定义与属性
  • 物品定义与效果
  • 场景跳转关系
  • 条件判断

宿主负责

  • UI 布局与样式
  • 动画与过渡效果
  • 打字机效果
  • 存档 UI 与管理
  • 文件访问与缓存
  • 音频播放控制
  • 平台适配(刘海屏、安全区域等)

同一份 NovaMark 脚本可以被:

  • 聊天界面风格渲染
  • 视觉小说风格渲染
  • 纯文字终端渲染

脚本不需要知道这些差异。


进一步参考

Last updated on