Skip to content

Android 接入指南

本文档面向需要将 NovaMark 运行时集成到 Android 应用的开发者。

前置理解

在开始之前,请确保已阅读 运行时、宿主与平台接入,理解以下核心概念:

  • 离散状态机:NovaMark VM 不自行推进时间,而是等待宿主调用
  • 宿主职责:Android 端负责 UI 渲染、动画、存档管理、平台适配
  • 状态驱动:渲染器只消费运行时状态,不参与剧情逻辑

架构选型

NovaMark 在 Android 平台支持两种主要接入方式:

方案一:WebView + WASM

将 NovaMark 编译为 WebAssembly 模块,在 Android WebView 中运行。

适用场景

  • 已有 Web 渲染器,希望快速复用
  • 团队熟悉 Web 前端技术栈
  • 需要热更新能力

接入要点

  • 使用 Emscripten 将 NovaMark 编译为 .wasm 文件
  • 将 Web 渲染器模板(HTML/CSS/JS)打包进 Android 资源
  • WebView 通过 JavaScript 桥接访问原生能力(存档、文件访问等)

注意事项

  • 游戏包(.nvmp)需要通过桥接从原生层传入 WASM
  • 存档操作需要桥接到 Android 原生文件系统
  • 音频播放建议使用原生 MediaPlayer 而非 WebAudio

方案二:原生渲染

通过 JNI 调用 NovaMark C API,自行实现 Android 原生 UI。

适用场景

  • 追求最优性能
  • 需要深度集成 Android 系统能力
  • 希望渲染完全可控

接入要点

  • 使用 NDK 编译 NovaMark 为共享库(.so
  • 通过 JNI 封装 C API 供 Kotlin/Java 调用
  • 自行实现 UI 渲染层(可使用 Jetpack Compose 或传统 View 系统)

注意事项

  • 需要理解 NovaState 结构并映射到 UI 组件
  • 需要自行处理动画、过渡效果
  • 需要管理线程模型(VM 在后台线程,UI 在主线程)

选型建议

维度WebView + WASM原生渲染
开发成本低(复用 Web 模板)高(需自建渲染层)
运行性能中等最优
热更新支持不支持
原生能力集成需桥接直接访问
UI 一致性与 Web 端一致可完全定制

接入步骤

以下以原生渲染方案为例,说明基本接入流程。

第一步:编译 NovaMark 共享库

  1. 配置 NDK 环境
  2. 使用 CMake 交叉编译 NovaMark 为 libnova.so
  3. build.gradle 中配置 NDK 构建参数

第二步:封装 JNI 接口

将 C API 封装为 Kotlin/Java 可调用的接口。核心操作包括:

生命周期管理

  • 创建 VM 实例
  • 加载游戏包(.nvmp 文件)
  • 销毁 VM 实例

剧情推进

  • advance() - 推进到下一个状态点
  • choose(choiceId) - 选择选项

状态读取

  • 获取 NovaState 结构
  • 解析对话、选项、背景、立绘等字段

第三步:实现 UI 渲染层

根据 NovaState 结构设计 Android UI:

对话显示

  • 读取 dialogue.speaker 显示角色名
  • 读取 dialogue.text 显示对话内容
  • 实现打字机效果(由宿主控制,非引擎行为)

选项渲染

  • 读取 choices 数组
  • 动态生成选项按钮
  • 点击后调用 choose()

背景与立绘

  • 读取 bg 字段获取背景图路径
  • 读取 sprites 数组获取立绘信息
  • 自行决定过渡动画的实现方式

第四步:实现事件循环

建立 VM 执行与 UI 更新的交互模式:

用户操作 → 调用 advance()/choose() → VM 更新状态 → 读取 NovaState → 刷新 UI → 等待下一次用户操作

状态驱动渲染

NovaMark 采用状态驱动模型,Android 宿主需要理解如何消费运行时状态。

NovaState 结构概览

运行时状态包含以下主要字段:

字段说明用途
dialogue当前对话显示角色名和文本
choices可选选项列表渲染选择按钮
bg背景图路径加载并显示背景
sprites立绘列表显示角色立绘
bgm背景音乐路径播放 BGM
sfx音效路径播放音效
variables变量表显示状态、解锁条件等
inventory物品背包显示背包界面
textConfig文本配置对话框样式、字体等

渲染提示字段

以下字段由脚本提供,但由宿主解释和执行

  • transition - 过渡效果提示(淡入淡出、滑动等)
  • position - 位置提示(左、中、右等)
  • opacity - 透明度提示
  • loop - 循环提示(用于 BGM 等)
  • volume - 音量提示

这些字段表达的是创作者意图,Android 宿主可以:

  • 完全遵循提示实现
  • 部分采用,部分使用平台默认值
  • 忽略某些提示(如低端设备降级渲染)

状态更新时机

VM 状态仅在以下时机发生变化:

  • 调用 advance()
  • 调用 choose()
  • 加载存档后

宿主无需轮询状态,只需在调用 VM 方法后读取新状态即可。


输入处理

NovaMark 的核心输入只有两种:advance()choose()

advance 触发时机

用户执行以下操作时,宿主应调用 advance()

  • 点击对话框空白区域
  • 点击"继续"按钮
  • 按下确认键

choose 触发时机

NovaState.choices 不为空时:

  • 显示选项列表
  • 用户点击某个选项后,调用 choose(choiceId)
  • choiceIdchoices 数组中获取

线程模型

建议的线程处理方式:

主线程(UI 线程):
  - 渲染界面
  - 接收用户输入
  - 更新 UI 组件

后台线程:
  - 调用 VM 方法(advance/choose)
  - 读取 NovaState
  - 解析资源路径

使用 LiveDataFlowHandler 在线程间传递状态更新。


存档管理

NovaMark 将存档分为两层,Android 宿主需要分别处理。

二进制存档(正式环境)

使用 C API 的快照功能:

  • nova_save_snapshot_file() - 保存二进制快照
  • nova_load_snapshot_file() - 加载二进制快照

存档文件位置建议

  • 内部存储:getFilesDir() 下的 saves/ 目录
  • 支持多存档槽位

存档时机

  • 用户手动保存
  • 自动存档(场景切换时)
  • 关键选择前

JSON 快照(调试与测试)

使用 nova_export_runtime_state_json() 获取 JSON 格式状态:

用途

  • 开发阶段查看完整状态
  • 调试工具展示
  • 自动化测试验证

不建议用于正式存档,因为:

  • 文件较大
  • 解析速度较慢

存档界面职责

存档界面的实现完全由宿主负责:

  • 存档槽位布局
  • 存档缩略图(宿主自行截图保存)
  • 存档时间戳
  • 存档元数据(如当前场景名)

NovaMark 引擎仅提供状态快照的保存与恢复功能。


调试建议

日志与错误处理

  • 在 JNI 层捕获 C API 错误,通过 Log.e() 输出
  • 使用 nova_get_error() 获取详细错误信息
  • 区分 VM 错误(如脚本逻辑)和宿主错误(如资源加载失败)

资源调试

如果资源加载失败,检查:

  • .nvmp 包是否正确打包资源
  • 资源路径是否正确传递给 Android 资源系统
  • 文件权限是否正确

状态验证

在开发阶段,可以:

  • 使用 JSON 快照导出完整状态
  • 对比期望状态与实际状态
  • 验证变量、背包、场景是否正确

性能调优

  • 图片资源使用合适的采样率
  • BGM 使用流式播放而非一次性加载
  • 立绘使用图集减少绘制调用
  • 避免每帧重复读取 NovaState,仅在状态变化后读取

接入检查清单

完成接入后,确认以下功能正常:

  • 加载 .nvmp 游戏包
  • 显示对话内容(角色名 + 文本)
  • 显示选项并响应选择
  • 显示背景图
  • 显示立绘
  • 播放 BGM 和音效
  • 保存与加载存档
  • 变量读取(用于 UI 显示)
  • 背包物品显示

相关文档

Last updated on