M3 复盘:采集 × 种植 × 昼夜 × 睡觉 × HUD 可玩闭环¶
本文是对 magic-plant-demo 里程碑 M1–M3(dev_manual §10)推进进度的截图复盘 + 技术复盘。 依据:dev_manual.md §2/§4/§5/§7/§9 · content_manual.md §1–§2 · map_progress.md。 日期:2026-09-02 · 版本:0.1-preview
0. 一图总览(截图复盘)¶
用 tools/capture.gd 在窗口模式下取 viewport 纹理截图(headless 渲染不到纹理,见 §9.4)。四张图为同一时刻自洽的白昼/黑夜对照:
| 截图 | 内容 | 验证点 |
|---|---|---|
![]() |
基地 + 3 作物格 + 床 + 门占位,玩家居中,12:00·昼 |
基地/种植/门渲染、HUD 天数+时刻+三维条、白昼亮度 |
![]() |
同区域夜态 20:00·夜,暗色覆盖层 + 蓝色夜生蘑菇散落 |
昼夜双环境、夜生蘑菇仅夜里显隐 |
![]() |
全图(关相机=世界原点)12:01·昼 |
区域色块 / 魔法门 / 黑暗障碍布局 |
![]() |
全图夜态 20:01·夜 |
夜态真菌森林光景、夜生蘑菇种群密度 |
结论:M1–M3 的核心闭环已从「只能移动的静态地图」推进到「可采集 → 可种植 → 可睡觉推进天 → 收获 → 可解锁能力」的可玩状态,白昼/黑夜两套环境肉眼可辨。
1. 里程碑对照(dev_manual §10)¶
| 里程碑 | 目标 | 状态 | 说明 |
|---|---|---|---|
| M1 | 工程 + 渲染器 + 输入层 + 可移动 Player + 相机 + 占位地图 | ✅ | Compatibility(GLES3)、640×360+NEAREST+整数缩放、7 个 autoload、WASD/摇杆移动、全图占位、门/封墙物理阻挡 |
| M2 | GameClock(一天24分钟可配) + 昼夜双环境 + 睡觉跳天 + 三维资源 HUD | ✅ | GameClock 连续时钟;CanvasModulate 昼夜覆盖层;睡觉跳天 + 扣饱食度/回满蓝/小回血;HUD 三维资源条+时刻 |
| M3 | 种植:种植区 + 作物生长(GameClock 驱动) + 收获进背包 | ✅ | 基地 3 作物格、Crop 按天成熟(阶段色环)、收获进 Inventory;外加野生蘑菇采集 + 首次采集解锁能力(content §2.1 的核心耦合) |
| M4 | 合成:RecipeData + 一条开门配方 + 门解锁 | ⬜ | 下一步 |
| M5 | 战斗:自动瞄准 普攻/施法/闪避 + 机型怪 | ⬜ | 能力已解锁、施放未接 |
| M6–M8 | 死亡捡尸 / bosss + 结算 / 移动端打磨+换皮 | ⬜ | — |
M2/M3 达成,还额外完成了 content_manual §2.1 的「能力首次采集解锁」(7 种能力的数据 + 解锁逻辑已就位),这是 M3 里最贴合「种田=变强」的一环。
2. 关键技术落地(与文档一致性)¶
| 设计点 | 落地 |
|---|---|
数据驱动 .tres |
tools/generate_content.gd 一次性引导生成 10 CropData + 10 ItemData + 7 AbilityData;Content 静态注册表按 StringName 检索 |
| 单一真相(dev §4 红线) | 作物 yields / 能力 grant_mushroom / upgrade_cost 均以 ext_resource 引用 items/*.tres(path 托管),杜绝内联副本漂移 |
| 换皮层(§7.4) | Player / Mushroom / Plot / Crop / Bed 全用 _draw() 程序化色块,共用一个交互接口,重做美术只换 Sprite2D/AnimatedSprite2D |
| 信号向上、调用向下(§5) | HUD 只连 Autoload 信号(GameClock/PlayerState/Inventory/EventBus.toast);Plot/Mushroom 为逻辑层查询 Content + Inventory 驱动 PlayerState |
| 昼夜低成本(§8) | 全图一次 CanvasModulate 调色,非逐节点 |
| 交互归一(§7.3) | F 交互统一走 InputManager.interact_pressed();摇杆 should_show_joystick() 判端 |
后台兜底 toast |
EventBus.toast(text)(§5.1 已补记) |
3. 验证方法¶
- 逻辑冒烟:
--headless --import(注册 class_name)+--headless --quit-after <<N>>跑主场景 →EXIT=0零报错。 - 内容生成:
--headless --script res://tools/generate_content.gd→ 输出10 蘑菇 / 10 物品 / 7 能力。 - 视觉复盘:
<Godot>_console.exe --path <proj> --script res://tools/capture.gd -- --phase=day|night(窗口模式,§9.4 headless 渲染不到纹理),产出shots/{day,night}_{player,map}.png并Read检查。
4. 本次踩的坑(含修正)¶
| 坑 | 现象 | 修正 |
|---|---|---|
AbilityData 缺 desc 字段 |
生成时运行时赋值报错,且发生在 main loop 的 _init/_initialize 内 → 进程挂起不退出 |
补 @export var desc;改用 MainLoop 生命周期 _initialize() + quit() 才稳定退出 |
严格名推断(项目把 INFERENCE_ON_VARIANT 当 error) |
for x in <const 数组>、var y := dict.get(...)、var m := load(...).instantiate() 都编译失败 |
显式标注类型(for s: Dictionary in ... / var cat: ItemData = ... / var main: Node = ...) |
交互物 collision_mask |
填成 2,玩家在默认层 1 → body_entered 不触发,交互无效 |
改为 collision_mask = 1 |
| 内联副本 → 引用漂移 | 生成时 yield/grant 用的是内存对象,ResourceSaver 把它们序列化为内联 SubResource,改 items/*.tres 不会同步 |
生成时 load() 重载为 path 托管实例,再作为 ext_resource 引用 |
| 截屏脚本编译期见不到 autoload | GameClock 作为标识符在 --script 里 Identifier not found |
用 root.get_node("/root/GameClock") 运行时取用 |
| 截屏时间自洽 | 直接改 game_min 但 HUD 只听 minute_ticked → 标签残留旧时刻、场景读新时刻,昼夜错位 |
在 _boot(load 场景前)设一次目标时刻,HUD/作物/覆盖层一次性读到一致值 |
5. 遗留与下一步¶
| 优先级 | 项 | 说明 |
|---|---|---|
| 高 | M4 合成 + 开门 | RecipeData + 一条「银芒菇×N → 魔钥」→ 开魔法门;让采集到的蘑菇立刻有「变强/推进」落点(最贴合核心循环) |
| 高 | M5 战斗 | 自动瞄准普攻/施法 + 1 种机制怪;能力已经解锁,只差施放逻辑 + 敌怪 |
| 中 | 移动端动作按钮 + 手感 | 摇杆已可移动;攻击/施法/交互触控按钮、安全区(M8) |
| 低 | 美术换皮 | 占位色块 → Sprite2D/AnimatedSprite2D,只换纹理不碰玩法(§7.4) |
| 指标 | draw calls / script time | 暂未实测,M8 打磨时按 §8 预算(draw calls<100、script<4ms)核 |
6. 一句话结论¶
M3 已交付一个能玩的移动端最小闭环:采集 → 种植 → 睡觉推进 → 收获 → 解锁能力,且昼夜双环境、数据驱动单一真相、换皮层接口都已按三份手册落地并通过 headless + 截图验证。下一步价值最高的是 M4 合成+开门,把「蘑菇=材料=门钥匙」这个探索驱动真正闭环起来。



