Files
NS_unknown_game/game/docs/engine_capability_audit.md
T

345 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Engine Capability Audit
目标:后续游戏层尽量复用 Frostbite2D 已有能力,避免在游戏项目里重复造资源、动画、地图、渲染、输入和存档轮子。本文基于当前引擎代码和游戏层现状整理。
## 结论
当前游戏层已经用了引擎核心框架,并且已把地图、动画、UI、音频、存档和 NPK/SoundPack 资源入口接到真实调用路径。
最重要的调整已经完成:场景地图不再以 C++ 硬编码为主,`stage_01.map` 通过 `Asset` / `PvfArchive` / `ScriptParser` 读取入口进入 `LevelDefinition`
当前骨架接入状态:游戏启动时通过 `GameServices` 探测/初始化 `AudioSystem``FontManager``PvfArchive``NpkArchive``SoundPackArchive``AudioDatabase``SaveSystem` 状态;`PlayerActor` 已接入 `Animation`/NPK/PNG 优先级;`WhiteboxScene` 已接入 `UIScene`、音频 cue 和 debug 存档。详细状态见 `game_skeleton.md`
推荐方向:
```text
.map 文件
-> Asset 普通资源读取,或 PvfArchive 从 Script.pvf 内读取
-> ScriptParser / map parser 解析
-> 转成 LevelDefinition
-> StageRenderer / DebugOverlay / WhiteboxScene 继续复用
```
这样地图可以外部维护,素材、图层、碰撞、出生点、camera bounds 和 battle zone 都能从数据文件进入游戏,而不是继续写死在 `whitebox_level.cpp`
## 已经用上的引擎能力
### Core / Scene / Actor
已使用:
- `Application`
- `SceneManager`
- `Scene`
- `Actor`
- `RefPtr` / `MakePtr`
当前状态:
- `WhiteboxScene` 继承 `frostbite2D::Scene`
- `PlayerActor` 继承 `frostbite2D::Actor`
- 场景生命周期、Actor 子节点、Render/Update 流程已接入引擎。
保留原则:
- 后续敌人、道具、特效仍应优先做成 `Actor` 子类或 Actor 子节点。
- 不在游戏层另写对象树、生命周期系统或场景管理器。
### Graphics / Camera / Render
已使用:
- `Renderer::drawQuad`
- `Renderer::drawSprite`
- `Texture::loadFromFile`
- `Camera`
- `RenderStyleProfileId::PixelArt2D`
- `ResolutionScaleMode::Fit`
当前状态:
- `StageRenderer` 已复用引擎 Renderer 和 Texture。
- `CameraController` 使用引擎 `Camera` 做位置控制。
- `GameUiOverlay` 通过 `UIScene` 进入 UI scene stack。
- 游戏入口已设置像素风渲染风格。
需要调整:
- `StageRenderer` 当前自己维护贴图缓存。后续如果引擎已有统一资源缓存或纹理缓存,应迁移过去。
- 地图层和 tile 层不应该额外造渲染管线,继续输出到引擎 Renderer 即可。
### Resource / Asset
已部分使用:
- `Asset` 被引擎纹理加载间接使用。
- Windows / Switch 的资源根目录、RomFS 路径已经由引擎 `Asset` 解析。
当前状态:
- `StageMapResource` 已直接使用 `Asset::readFileToString` 读取 `map/stage_01.map``assets/map/stage_01.map`
- Windows 和 Switch 构建会把 `game/assets/*` 复制到产物 `assets/`,保证 `assets/map/stage_01.map` 路径可用。
- `stage_01` 主地图已迁移到外部 `.map` 文件。
- `GameAudio``GameServices``PlayerAnimationAssets` 都通过 `Asset` 检查可选资源。
下一步:
- 继续把输入配置、角色动画配置等文本/脚本配置接入 `Asset` 或 PVF。
### PVF / ScriptParser
引擎已有:
- `PvfArchive::open`
- `PvfArchive::getFileContent`
- `PvfArchive::getFileBytes`
- `PvfArchive::getFileRawData`
- `PvfArchive::resolvePath`
- `ScriptParser`
- `ScriptValue`
当前状态:
- `StageMapResource` 已能在 `PvfArchive` 打开后尝试读取 `map/stage_01.map`
- 若资源像 PVF 二进制脚本,会先用 `ScriptParser` 解析出 script values。
- 若资源是 PVF 文本,会作为普通 `.map` 文本交给 `StageMapLoader`
- `ScriptParser` 支持 PVF 脚本二进制格式,不是普通文本 parser。
地图结论:
- 如果我们的 `.map` 是 PVF 内的二进制脚本格式,就应使用 `PvfArchive + ScriptParser`
- 如果我们的 `.map` 是普通文本/JSON/自定义文本格式,就应先用 `Asset` 读取,再由游戏层做最小 parser。
- 无论哪种格式,最终都应该落到 `LevelDefinition`,不要让 `WhiteboxScene` 直接理解文件格式。
### NPK / Sprite / Animation
引擎已有:
- `NpkArchive`
- `Sprite::createFromNpk`
- `Sprite::createFromFile`
- `Animation`
- `parseAniFromPvf`
- `parseAlsFromPvf`
当前状态:
- 玩家动画加载顺序为 PVF `.ani` -> NPK IMG -> PNG fallback。
- 如果 PVF 中存在 `character/male/*.ani``PlayerActor` 会使用引擎 `Animation`
- 如果 NPK 中存在 `sprite/character/male/*.img`,会使用 `Sprite::createFromNpk`
- 当前仓库没有正式 PVF/NPK 动画资源,因此运行时仍会回退到 PNG spritesheet。
风险:
- 只要正式动画资源未进入 PVF/NPK,临时 PNG fallback 仍需要少量手写帧切换。
下一步建议:
- 为玩家和敌人补齐 PVF `.ani` 或 NPK IMG 后,逐步移除 PNG fallback 的手写帧切换。
- 将 attack/damage box 从 `Animation::GetCurrentFrameInfo()` 接入战斗 hitbox。
### Audio / Save
引擎已有:
- `AudioSystem`
- `Sound`
- `Music`
- `SoundPackArchive`
- `AudioDatabase`
- `SaveSystem`
当前状态:
- `GameAudio` 已接入 `Sound``Music``AudioDatabase` 查询。
- `WhiteboxScene` 会尝试播放 `stage_01` BGM 和 battle zone 进入音效。
- `PlayerActor` 会尝试播放跳跃、攻击音效。
- `GameSave` 已用 `SaveSystem` 保存 debug overlay 开关。
后续原则:
- 正式音效、BGM、环境音直接放入资源槽位或 `audio.xml`
- 设置、进度继续用 `SaveSystem`,不要在游戏层重新写文件存档服务。
### UI / Text
引擎已有:
- `UIScene`
- `TextSprite`
- `FontManager`
当前状态:
- `GameUiOverlay` 已作为 `UIScene` 接入。
-`assets/fonts/debug.ttf``assets/fonts/ui.ttf` 时,状态 UI 使用 `TextSprite`
- 缺字体时使用 `Renderer::drawQuad` 色条 fallback,避免 Switch/PC 因字体缺失黑屏。
### Event / Input
已使用:
- `KeyEvent`
- `EventType::KeyDown`
游戏层自定义:
- `InputState`
- `InputStateProvider`
判断:
- `InputState` 作为游戏语义输入是合理的,能隔离 PC/Switch 差异。
- 但底层输入事件和生命周期应继续使用引擎事件系统。
下一步:
- `InputConfig` 可以作为游戏层配置,但读取配置应走 `Asset` 或 PVF。
- Debug 输入和 gameplay 输入要分离,避免正式版本保留开发快捷键。
## 当前游戏层自造/硬编码点
### 1. 地图硬编码
文件:
- `game/src/data/whitebox_level.cpp`
当前状态:
- 已新增 `game/assets/map/stage_01.map`
- 已新增 `StageMapLoader`,把 `.map` 文本解析成 `LevelDefinition`
- `CreateWhiteboxLevel()` 已改为优先加载 `.map`,失败时才回退 C++ 白盒数据。
- C++ 中保留的世界尺寸、平台、视觉层、props、battle zone、spawn point 现在只作为 fallback。
后续建议:
- 继续扩展 `.map` 的 tileset/tile entry 表达。
- 逐步把 `level_visual` 的长色块替换成 tile 数据。
### 2. PNG fallback 手写动画帧切换
文件:
- `game/src/actor/player_actor.cpp`
当前状态:
- 已接入 `Animation` 和 NPK 优先路径。
- 临时 PNG fallback 仍在 C++ 里硬编码帧数、帧时间和 source rect。
建议:
- 等正式 `.ani` / `.img` 资源补齐后,删除 PNG fallback 的手写帧切换。
### 3. 游戏层贴图缓存
文件:
- `game/src/stage/stage_renderer.*`
问题:
- `StageRenderer` 自己维护 `textureCache_`
建议:
- 短期可接受,避免每帧重复加载。
- 如果引擎后续提供统一 Texture cache,迁移到引擎资源缓存。
### 4. 调试绘制工具
文件:
- `game/src/debug/debug_overlay.*`
判断:
- 这是游戏特定调试可视化,保留合理。
- 但底层绘制继续用 `Renderer::drawQuad`,不要另造 debug render backend。
## `.map` 框架建议
### 加载优先级
第一阶段已支持普通资源文件:
```text
Asset::readTextFile("map/stage_01.map")
```
第二阶段已预留 PVF
```text
PvfArchive::getFileContent("map/stage_01.map")
```
如果 `.map` 是 PVF 二进制脚本,则改用:
```text
PvfArchive::getFileRawData("map/stage_01.map")
ScriptParser parser(rawData, "map/stage_01.map")
```
### 数据流
```text
StageMapLoader
-> 读取 .map
-> 解析 world / camera / spawn / layers / collision / zones
-> 输出 LevelDefinition
-> WhiteboxScene 使用 LevelDefinition
```
### `.map` 应表达的字段
- `world`
- width
- height
- `camera`
- bounds
- `player`
- spawn
- `layers`
- id
- role
- parallax
- rect / tile / sprite source
- `collision`
- platforms
- walls
- bounds
- `battle_zones`
- id
- trigger
- camera_bounds
- enemy_spawns
- `assets`
- background
- tileset
- props
- effects
### 不建议做的事
- 不要在 `WhiteboxScene` 里解析 `.map`
- 不要绕开 `Asset` 直接用 `std::ifstream` 读资源。
- 不要继续把地图扩展写死在 `whitebox_level.cpp`
- 不要为了地图单独造一套渲染系统。
## 推荐执行顺序
1. 已完成:`StageMapResource` 定义地图文件路径、普通资源读取和 PVF 读取优先级。
2. 已完成:`StageMapLoader``.map` 转成 `LevelDefinition`
3. 已完成:`stage_01.map` 把当前 `whitebox_level.cpp` 数据迁移成外部地图文件。
4. 已完成:`CreateWhiteboxLevel()` 改为加载 `stage_01.map`,失败时回退旧白盒数据。
5. `StageRenderer`:继续消费 `LevelDefinition`,不直接关心 `.map`
6. 文档:把地图编辑流程写入 `scene_acceptance.md` 和场景计划。
## 总体原则
- 引擎已有的资源、归档、动画、音频、事件、Actor 和 Scene 能力优先使用。
- 游戏层只做“游戏语义转换”:地图语义、战斗语义、角色状态、关卡流程。
- 外部资源文件优先通过 `Asset` / `PvfArchive` 进入。
- C++ 硬编码只作为 fallback,不作为长期地图生产方式。