用鸿蒙开发助手推进《3D种植》鸿蒙版与 Flame 库适配
按住量杯,沿着屏幕向上拖进发光根区,松手后水流落下,番茄从播种进入幼苗阶段,生命值保持 100。退出游戏再打开,还能接着刚才的养护进度继续。这是《3D种植》在鸿蒙手机上完成的一段实际操作,也是我这次使用 HarmonyOS Dev Assistant(鸿蒙开发助手)推进第三方库适配时,最希望保住的体验。

量杯拖入根区后,番茄进入 2/8 阶段,原生背景同步切换到幼苗场景。
这次实践完成了两个相互连接的成果:将游戏现有 Dart Flame 背景绘制接到鸿蒙原生实现,保留原有养护玩法;从中提炼出独立 ArkTS 2D 基础库 flame_native,在 OHPM 公开发布。 开发助手提供了适配任务入口、HAR 工程模板、ArkTS 规则、SDK 查询与设计复核。我接着完成实现、构建和设备验证,让这些建议落到可运行的库和游戏中。
下文按实际操作展开:怎样安装和使用助手,怎样拆解 Flame 依赖,三个平台问题如何解决,以及其他 ArkTS 工程怎样接入产出的库。
从游戏真正用到的能力开始
《3D种植》通过植物、花盆、根系和养护工具呈现立体种植体验。玩家需要观察植物状态,再通过连续拖动完成浇水、移盆和配肥;操作会影响水量、浓度、生命值及下一阶段。
检查 pubspec.yaml、锁文件和源码导入后,我确认原项目使用的是 Flame 1.30.1。进一步查看游戏中的调用位置,番茄和向日葵主要借助它加载阶段 PNG、居中缩放并绘制背景;工具、连续手势、水流、生命值和结算逻辑已经在独立的 Flutter 层。
这个分析让适配目标变得具体:先让现有游戏通过 Flutter OpenHarmony 在鸿蒙上运行,再把实际需要的绘制能力接到原生层,同时形成 ArkTS 工程可以复用的基础库。
首版原生库选择了游戏循环、组件树、PNG 精灵、触摸拖动和 AABB 碰撞。AABB 用包围矩形判断接触,足以检查水壶是否进入植物区域。相机、复杂效果和完整事件体系可以按后续需求扩展。
范围明确后,验收问题也能具体化:水壶能否跟着手指移动?拖出再拖入是否重新计数?暂停后时间是否停止?回到前台是否会把后台停留时间一次性补进来?这些都是玩家能直接感受到的结果。
flame_native 是参考 Flame 概念的独立社区 ArkTS 2D 子集,保留 MIT 和 Blue Fire 来源说明,不兼容完整 Dart Flame API,也不提供 3D 引擎能力。
安装助手,打开“三方库鸿蒙化”
我参考了官方三方库鸿蒙化指南,实际使用 VS Code 扩展 HarmonyOS Dev Assistant 0.2.0,模型选择为 MiniMax-M3。不同 IDE 和扩展版本的入口可能有所差别,本文以这次使用的界面为例。
- 从官方扩展页安装助手,用 VS Code 打开项目,完成工作区信任与账号登录。
- 进入助手面板,配置模型,再打开“基础配置”。
- 填写 DevEco Studio、Flutter SDK 和 Pub 缓存的本机路径,保存配置。
- 返回任务面板,选择“三方库鸿蒙化”,描述源库版本、目标平台、首版范围和验收要求。
- 查看工具执行情况与文件输出;实现方案确定后,再用对话复核补充平台验证重点。

基础配置中的路径应指向自己的安装位置,Flutter SDK 选择根目录。
本机配置如下,其他电脑需要替换安装路径:
| 配置项 | 本次填写值 |
|---|---|
| DevEco Studio | D:/Program File/Huawei/DevEco Studio |
| Flutter SDK | E:/hm04/flutter_flutter |
| Pub 缓存 | E:/hm04/PUB |
| Pub 地址 | https://pub.flutter-io.cn |
| Flutter 存储镜像 | https://storage.flutter-io.cn |
这里有一个容易遗漏的细节:语言服务的 arkts.deveco.path 与助手自己的 DevEco 路径设置需要分别核对。只设置语言服务路径,不能代表助手的环境配置已经完成。

配置、发送任务、查看进度与设计复核的操作流程。
把适配目标写成助手能处理的任务
第一轮我把源库、产物、能力范围和技能要求一起写进提示词。下面是实际发送任务的核心内容:
把 Flame 1.30.1 的部分 2D 核心能力移植为不依赖 Flutter/Dart VM 的 HarmonyOS ArkTS 原生 HAR,最终发布 OHPM。首版范围:游戏循环、组件树、PNG Sprite、触摸拖动、AABB 碰撞。请真实使用本插件内的 arkts-rules、harmonyos-sdk-api-lookup、hardemo-template 技能。

任务明确了原生 HAR、首版能力及 SDK 查证要求。
我还单独规定时钟接口和行为:
暴露 start/stop/step/tick(timestampMilliseconds)/dispose;首帧 dt=0,暂停时间不计入 dt,dt 为秒,长帧有上限,销毁后禁止启动,允许明确单步。保留 MIT/Blue Fire 来源说明,禁止声称直接兼容 Dart Flame。
这一轮只约定输出 API 查证记录和纯逻辑时钟两个文件。任务确认工作目录并尝试读取参考代码与技能后,停在读取步骤,超过 7 分钟没有新的可见输出,两个文件也没有生成。我停止这轮任务,接着下一步,依据插件随包技能完成实现。
虽然这次自动执行没有完成约定输出,但工程模板和规则资料仍然有用:它们为源码组织、平台 API 与代码检查提供了明确起点。
| 助手随包能力 | 我怎样用在这次适配中 |
|---|---|
hardemo-template | 建立 HAR 与独立 Demo 骨架,分开库代码和消费应用 |
arkts-rules | 按 ArkTS 类型和语法约束实现,再用真实编译校正 |
harmonyos-sdk-api-lookup | 查证帧时间单位、图片解码释放和触摸接口 |
hmos-library-quality-assessment | 组织质量复核,配合 CodeLinter 检查实际源码 |
对我来说,这四部分分别回答了“工程怎样起步”“代码怎样写”“API 怎样查”和“结果怎样检查”。养护业务规则继续留在应用里,HAR 不携带植物游戏素材,其他 ArkTS 应用可以复用引擎基础能力。
再问一次:编译通过以后,还要检查什么
第二轮,我把已经确定的方案交给插件做设计复核。任务改为纯对话,重点是找出编译和宿主测试无法覆盖的设备问题:
请只在对话中做一次原生库设计复核,不读文件、不执行命令、不调用工具、不写文件。请列出最多 5 项真机验收关注点,并明确哪些不能由编译和宿主测试证明。不要声称已经验证。

把时钟、资源和输入方案交给助手,要求补充设备验收关注点。
插件返回了真实时钟节拍、生命周期边界、系统手势抢占、原生图片内存和碰撞状态等提醒。

复核把注意力从“能否构建”延伸到设备上的连续交互和资源生命周期。
这次回复推动我把检查分成两层:纯逻辑测试验证计时、坐标和碰撞规则,设备操作验证帧回调、系统取消、图片显示和恢复行为。例如,测试能证明暂停状态机正确,仍要在手机上确认暂停按钮真的停止了运行时间。
我据此整理出三个最值得展开的平台问题,也把它们作为后续实现和验收的主线。
问题一:恢复前台时,游戏时间不能突然跳动
帧回调时间单位不一致,会让植物生长、水量或动画进度出现异常。通过插件随包 SDK 资料查证,displaySync.IntervalInfo.timestamp 的单位是纳秒,而时钟接口接收毫秒,业务更新使用秒。
我把转换集中在视图接入处:
// displaySync 回调接入时钟;tick 的参数单位是毫秒。
loop.tick(intervalInfo.timestamp / 1_000_000);
FlameLoop 再计算以秒为单位的 dt:首帧为 0,暂停时清除时间基线,恢复后的首帧重新建立基线,每帧最多推进 0.1 秒。这样返回前台时,不会把整个后台间隔一次性补算。
在 API26 真机上,暂停前后两次采样都保持 88.0 秒,恢复后变为 88.9 秒;一次前后台操作相隔约 24.5 秒,游戏时间只增加约 2.1 秒。这些观察对应的是这几次实际操作。
问题二:图片旋转缩放后,手指仍要点得准
组件有父节点、位置、锚点、缩放和旋转。如果直接用手指的屏幕坐标与组件本地矩形比较,缩放或旋转后就容易发生“看着点中了,却拖不动”。
实现中先组合父级与当前组件的变换,再用逆变换把触摸位置还原到本地坐标。命中后记录指针 ID,将后续 Move、Up、Cancel 交给捕获的组件;移除或隐藏组件时结束捕获。event.world 与 event.local 的职责分开,拖动逻辑不再假设屏幕坐标就是本地坐标。
助手的复核还提醒了系统手势抢占:按下后收到 Cancel,必须结束拖动,不能一直保留“正在拿着水壶”的状态。

水壶跟随连续拖动;离开目标后再次进入,接触计数增加。暂停与恢复同时检查运行时间。
这段交互中,累计拖动 898 vp,接触 2 次。另一轮首版检查中,三次位置采样对应 293、587、881 vp,接触计数依次是 1、1、2,与“进入、离开、再次进入”的动作一致。
问题三:PNG 能显示,还要能正确释放
图片从应用 rawfile 读取,经 ImageSource 解码为 PixelMap,再创建 ImageBitmap 供 Canvas 绘制。三类对象有各自的释放责任,页面退出时需要清理,快速切换阶段时还要处理尚未完成的解码。
我把资源所有权放在消费页面:页面持有 game 和 images,先等待 PNG 加载完成再显示视图;最终离开时销毁游戏,并处理图片释放 Promise。解码后的 ImageSource 及时释放,退出时继续释放位图与 PixelMap。异常路径也要执行其余资源的清理,不能因为一张图释放出错而跳过后面的图片。
这部分采用 ImageKit mock 检查正常、异常和并发清理,再用设备核对显示与冷启动重载。长时间原生内存表现仍需要专项压力验证,不能仅凭 mock 的通过结果推断。
接回《3D种植》:保住同一段养护操作
2026 年 10 月 7 日,我把原生实现接回完整游戏。Flutter 的 PlantSceneView 通过 OhosView 连接 NativePlantSceneFactory,由 FlameGame、SpriteComponent、NativeImages 与 FlameView 绘制原来的真实 PNG。原生背景使用 IgnorePointer,养护手势继续由现有业务层接收。
| 同一条体验链路 | 接入前 | 接入后 |
|---|---|---|
| 阶段背景 | Dart Flame 加载并绘制番茄、向日葵 PNG | 鸿蒙原生组件加载并绘制相同 PNG |
| 量杯与养护手势 | Flutter 业务层处理连续拖动和落点 | 保留相同处理,背景不抢占手势 |
| 阶段反馈 | 数值结算后切换背景、更新生命值 | 原生场景随同一业务状态切换 |
| 退出与恢复 | 应用保存养护进度 | 恢复进度,同时重新加载原生场景资源 |
游戏源码、pubspec.yaml 和锁文件中的 Dart Flame 引用已经移除。胡萝卜、黄瓜、草莓原有的独立 Flutter 互动组件继续沿用,其他平台使用相同 PNG 的 Flutter 图片组件。这里完成的是游戏现有 Dart Flame 使用点的替换,Flutter 页面与业务仍然保留。 游戏接入采用首版原生库的本地源码模块;标准 ArkTS 工程的公开 HAR 接入方法见下一节。
在最终 release 游戏包中,我重新完成番茄第一阶段的操作:
- 观察发光根区、10ml 量杯和生命值。
- 按住量杯,连续向上拖入根区后松手。
- 页面从阶段 1/8 进入 2/8,生命保持 100,出现“刚刚好,我准备发芽啦!”。
- 切到桌面停留 6 秒再返回,保持当前阶段;停止应用后重新启动,也能恢复阶段 2/8 与生命 100。

操作前:阶段 1/8,量杯与发光根区可见。

重新打开后:阶段与生命值保持,显示“已恢复上次动作,从当前阶段继续”。
这次替换同时通过全工程静态分析、原有 361 项回归和新增 4 项场景边界测试,release 构建成功。完整游戏的 profile 真机验证还通过了 11 项业务用例:向日葵八阶段手势、其他植物的选定阶段和真实原生存档。
向日葵的配肥玩法则更能说明为什么要检查连续交互。下面是原生渲染替换前的鸿蒙玩法演示:把清水容器拖到量筒口,水量从 15ml 增至 97ml,继续补足后达到 100ml。水量和浓度会跟着操作变化。

替换前的养护玩法:拖动补水,液位与配肥数值连续变化。
这轮操作最终配出肥液 11ml、清水 89ml。倒入盆土后进入阶段 6/8,生命从 91 降至 71,提示“肥液太浓了,根尖被灼伤”。适配需要保住这种“动作改变数值、数值影响植物”的链路。
设备画面检查还覆盖了五种植物的八个阶段及番茄倾倒状态,共 41 个画面。下面是番茄阶段图集:

番茄从播种到结果的八阶段画面。
在自己的 ArkTS 工程中使用这个库
截至 2026 年 10 月 11 日,OHPM 公开最新版为 flame_native@0.1.1。它更新了中文文档,运行时代码与完成首版验证的 0.1.0 保持一致。下面的示例固定使用公开版本,避免把审核中的接口带入接入步骤。
第一步,在应用的 entry 模块目录安装依赖:
ohpm install flame_native@0.1.1
第二步,合并构建配置。 字节码 HAR 消费工程需要在项目 build-profile.json5 的应用产品 buildOption 中启用标准化 OHM URL:
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
}
}
请与已有 buildOption 合并,保留项目自己的其他配置。这个步骤适用于标准 ArkTS 消费工程;Flutter 宿主的构建接入需按其工程结构单独处理。
第三步,准备图片与页面。 将自己的 plant.png 放到 entry/src/main/resources/rawfile/,下面是可放入 pages/Index.ets 的最小页面:
import { FlameGame, FlameView, NativeImages, SpriteComponent, Vector2 }
from 'flame_native';
@Entry
@Component
struct Index {
@State ready: boolean = false;
@State failure: string = '';
@StorageLink('nativeFlameForeground') foreground: boolean = true;
private gone: boolean = false;
private game: FlameGame = new FlameGame();
private images: NativeImages = new NativeImages();
aboutToAppear(): void { this.loadPlant(); }
private async loadPlant(): Promise<void> {
try {
const manager = this.getUIContext().getHostContext()?.resourceManager;
if (manager === undefined) { throw new Error('资源管理器不可用'); }
await this.images.loadRawFile(manager, 'plant', 'plant.png');
if (this.gone) { return; }
const plant = new SpriteComponent('plant');
plant.position = new Vector2(20, 20);
plant.size = new Vector2(180, 220);
this.game.add(plant);
this.ready = true;
} catch (error) {
if (!this.gone) { this.failure = (error as Error).message; }
}
}
aboutToDisappear(): void {
this.gone = true;
this.game.dispose();
this.images.dispose().catch((error: Error) => {
console.error(error.message);
});
}
build() {
Column({ space: 12 }) {
Text('Flame Native 植物场景').fontSize(20).fontColor('#183D30')
if (this.failure.length > 0) {
Text(this.failure).fontColor('#9C2630')
} else if (this.ready) {
Stack() {
FlameView({ game: this.game, images: this.images,
active: this.foreground,
onError: (message: string): void => { this.failure = message; } })
}.width('100%').layoutWeight(1)
} else {
Text('正在加载植物…').fontColor('#183D30')
}
}.width('100%').height('100%').padding(20).backgroundColor('#F1F5EA')
}
}
第四步,连接前后台。 在项目已有 UIAbility 的对应回调中加入以下语句,保留原有逻辑:
onForeground(): void {
AppStorage.setOrCreate('nativeFlameForeground', true);
}
onBackground(): void {
AppStorage.setOrCreate('nativeFlameForeground', false);
}
缓存多个路由页面时,还应把页面可见状态与 active 合并。已经销毁的 game 和 images 不可复用,重新进入应创建新实例。源码仓库的 ohos_hardemo/ 提供更完整的交互示例,真机安装需要配置自己的签名。
首版验证完成了 23 项源码行为测试、八套 CodeLinter 规则检查、独立本地 HAR 消费工程 release 构建、验签及 API26 基础真机检查。公开 0.1.1 的 HAR 下载与完整性核验通过,上面的最小页面也已从 OHPM 安装精确版本,在独立消费工程中完成 release HAP 构建。这个最小示例的构建不含签名与新增设备运行检查。库的最低兼容配置为 API18、首版编译目标为 API20,实际设备验证为 API26,尚未覆盖 API18 真机与长时间资源压力。
后续扩展:继续用规则与质量评估推进
截至 10 月 11 日,0.2.0 已加入精灵动画、计时器、World/Camera/Viewport、异步组件生命周期,以及曲线、反向、延迟、有限重复和序列效果控制器。这轮继续使用鸿蒙开发助手的 ArkTS 规则与库质量评估技能,配合上游执行轨迹检查,累计 90 项行为测试通过,八套规则复扫无报告项,独立本地 HAR 消费者构建成功。
API26 真机的八项检查还验证了普通、放大、旋转状态下的拖动接触,暂停恢复,以及移除后重新挂载不重复解码。该版本已提交 OHPM、仍在审核,公开安装示例继续使用 0.1.1。 最新扩展尚未接入完整游戏,不代表 Flame 主包全部移植完成。
这段扩展让我更看重助手提供的规则与评估框架:随着模块增多,可以持续对照 API、生命周期与验收条件推进,而不是每次都从一个笼统的移植需求重新开始。
这次实践中,开发助手最有价值的地方
首先是帮我把大任务拆成可以落实的工程问题。 三方库入口让任务能够围绕源版本、能力范围、平台接口和交付目标展开;模板与独立 Demo 则让库和应用的责任分开,便于逐层验证。
其次是把平台资料带到实现过程中。 ArkTS 规则、HAR 模板和本地 SDK 查询分别服务于语言、工程和 API。时间单位、资源释放与消费配置都有查证依据,对第一次做原生库适配尤其有帮助。
再次是设计复核补充了设备视角。 编译成功之后,助手继续提醒我关注系统手势取消、前后台和原生内存。把建议转成可操作的检查,再用实际数据判断,能让验收覆盖到玩家真正使用的过程。
最后是成果可以复用。 游戏保住了连续养护体验,原生基础能力则形成有文档、示例和公开仓库的库。开发者既能从本文看到适配路线,也能在自己的 ArkTS 工程中尝试接入。
这次没有独立统计请求数、token 消耗或对照工时,因此不把“减少多少请求”“节省多少 token”写成实测结论。助手是否节省沟通与查资料时间,可以从实际任务、技能使用和工程结果判断;量化结论需要单独记录同范围的对照数据。
三点改进建议
这次使用也遇到了几个值得改进的地方。我希望优先完善以下能力:
| 实际遇到的问题 | 希望助手提供的支持 |
|---|---|
| 保存配置后仍提示未配置 Flutter 环境 | 一键体检,逐项展示路径、版本与失败原因,给出明确修复动作 |
| 首轮读取停滞超过 7 分钟,约定文件未生成 | 显示当前工具耗时,支持超时结束和从已完成步骤恢复 |
| 复核混用了 HAR 与设备安装概念,回复超过要求的关注项数量 | 关联 SDK 依据,明确 HAR 由消费工程编译进 HAP,并区分建议、已验证与待验证 |
此外,一键导出提示词、工具结果、文件差异、截图和用量,会让持续实践与经验分享更方便。
经过这次《3D种植》适配,我会继续把鸿蒙开发助手用于依赖分析、工程起步、平台 API 查证和设计复核。把建议落到源码、独立消费者和真实设备上,再回到同一段游戏操作核对结果,是这次最有收获的使用方式。
库与参考资料
- Flame Native 的 OHPM 详情与版本
- AtomGit 源码与可运行示例
- 公开 0.1.1 版本 HAR
- 鸿蒙开发助手三方库鸿蒙化指南
- HarmonyOS Dev Assistant VS Code 扩展
- Flame 上游源码
flame_native 采用 MIT 许可证。支持范围与版本状态请以对应版本文档及 OHPM 页面为准。
更多推荐


所有评论(0)