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 方案:
- 使用 Emscripten 将 NovaMark 编译为 WASM 模块
- 将 WASM 文件与 Web 渲染器模板打包
- 将资源文件放入 App Bundle 或通过服务器加载
原生渲染方案:
- 将 NovaMark 编译为 iOS 支持的静态库或动态库
- 在 Xcode 项目中链接 C API 头文件
- 通过 FFI 或 Swift/C 桥接层调用
第二步:加载游戏包
NovaMark 游戏以 .nvmp 单文件格式分发。
核心操作:
- 从 App Bundle 读取游戏包
- 或从服务器下载后缓存到本地
- 调用加载接口初始化 VM
注意事项:
- 大型游戏包建议分块加载或后台预加载
- 资源文件(图片、音频)可单独管理,按需加载
第三步:实现事件循环
NovaMark 采用 离散状态机 + 宿主控制推进 模型。
引擎不会自动播放,而是等待宿主的指令:
advance()- 推进到下一个阻塞点choose(choiceId)- 玩家选择选项后继续
宿主需要:
- 监听用户输入(点击、滑动、按键等)
- 根据当前状态决定调用
advance()还是choose() - 更新 UI 呈现新状态
状态驱动渲染
NovaMark 的核心设计原则:
引擎产出状态,宿主负责渲染
NovaState 结构
运行时状态是渲染的唯一数据源,包含:
| 字段 | 说明 |
|---|---|
dialogue | 当前对话内容、说话角色、颜色 |
choices | 可选选项列表 |
bg | 背景图引用 |
sprites | 立绘列表与位置 |
bgm | 背景音乐引用 |
sfx | 音效引用 |
variables | 游戏变量 |
inventory | 玩家背包 |
渲染器职责
宿主拿到状态后,自行决定:
- 对话框样式与位置
- 立绘动画与过渡
- 背景切换效果
- 选项 UI 布局
脚本中的 transition、position、opacity 等字段是 渲染提示,不是引擎自动执行的动画。宿主可以:
- 遵循这些提示
- 或忽略它们,用自己的渲染逻辑
文本配置
运行时状态包含 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 控制台检查变量值
- 验证背包物品是否正确
- 确认角色定义是否加载
运行时状态检查
通过运行时状态接口实时检查:
- 当前场景与标签
- 变量值变化
- 物品数量
分阶段验证
推荐按以下顺序验证接入:
- 包加载 - 确认
.nvmp文件正确加载 - 状态推进 -
advance()能正常推进对话 - 选项选择 -
choose()能正确处理分支 - 状态读取 - 能获取正确的运行时状态
- 存档恢复 - 存档后能正确恢复
常见问题排查
| 问题 | 检查点 |
|---|---|
| 包加载失败 | 文件路径、格式版本、资源完整性 |
| 对话不推进 | 是否正确调用 advance() |
| 选项无响应 | 传入的 choiceId 是否正确 |
| 存档恢复异常 | 快照格式、版本兼容性 |
宿主与脚本职责边界
正确理解职责分工是顺利接入的关键:
脚本负责
- 剧情内容与分支逻辑
- 角色定义与属性
- 物品定义与效果
- 场景跳转关系
- 条件判断
宿主负责
- UI 布局与样式
- 动画与过渡效果
- 打字机效果
- 存档 UI 与管理
- 文件访问与缓存
- 音频播放控制
- 平台适配(刘海屏、安全区域等)
同一份 NovaMark 脚本可以被:
- 聊天界面风格渲染
- 视觉小说风格渲染
- 纯文字终端渲染
脚本不需要知道这些差异。
进一步参考
- 运行时、宿主与平台接入 - 核心概念详解
- C API 参考 - 底层接口文档
- 运行时状态 API - 状态结构说明
Last updated on