Files
NS_unknown_game/game/docs/engine_capability_audit.md
T

326 lines
8.3 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 已有能力,避免在游戏项目里重复造资源、动画、地图、渲染、输入和存档轮子。本文基于当前引擎代码和游戏层现状整理。
## 结论
当前游戏层已经用了引擎的核心框架,但地图和角色动画仍有明显“游戏层自造/硬编码”倾向。
最重要的调整是:**场景地图不要继续在 C++ 里手写 `Rect`,下一步应接入 `.map` 文件加载,并优先通过引擎 `Asset` / `PvfArchive` / `ScriptParser` 读取和解析。**
推荐方向:
```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` 做位置控制。
- 游戏入口已设置像素风渲染风格。
需要调整:
- `StageRenderer` 当前自己维护贴图缓存。后续如果引擎已有统一资源缓存或纹理缓存,应迁移过去。
- 地图层和 tile 层不应该额外造渲染管线,继续输出到引擎 Renderer 即可。
### Resource / Asset
已部分使用:
- `Asset` 被引擎纹理加载间接使用。
- Windows / Switch 的资源根目录、RomFS 路径已经由引擎 `Asset` 解析。
未充分使用:
- 游戏层目前没有直接用 `Asset::readTextFile` / `readBinaryFile` 读取地图和配置。
- `stage_01` 地图仍写死在 C++。
下一步:
- `.map` 普通文件先用 `Asset` 读取。
- 同一套 loader 后续支持从 PVF 中读取。
### PVF / ScriptParser
引擎已有:
- `PvfArchive::open`
- `PvfArchive::getFileContent`
- `PvfArchive::getFileBytes`
- `PvfArchive::getFileRawData`
- `PvfArchive::resolvePath`
- `ScriptParser`
- `ScriptValue`
当前状态:
- 游戏层还没使用。
- 引擎已经具备从 `Script.pvf` 按逻辑路径取脚本文件的能力。
- `ScriptParser` 支持 PVF 脚本二进制格式,不是普通文本 parser。
地图结论:
- 如果我们的 `.map` 是 PVF 内的二进制脚本格式,就应使用 `PvfArchive + ScriptParser`
- 如果我们的 `.map` 是普通文本/JSON/自定义文本格式,就应先用 `Asset` 读取,再由游戏层做最小 parser。
- 无论哪种格式,最终都应该落到 `LevelDefinition`,不要让 `WhiteboxScene` 直接理解文件格式。
### NPK / Sprite / Animation
引擎已有:
- `NpkArchive`
- `Sprite::createFromNpk`
- `Sprite::createFromFile`
- `Animation`
- `parseAniFromPvf`
- `parseAlsFromPvf`
当前状态:
- 玩家现在使用 `Sprite::createFromFile` 加载 PNG spritesheet。
- 玩家动画帧切换在 `PlayerActor` 内手写。
- 还没有使用 `Animation``.ani``.als`、PVF 动画数据或 NPK 图包。
风险:
- 如果继续手写动画,后续敌人、玩家连招、受击、死亡都会重复造动画系统。
下一步建议:
- 在地图框架后,角色动画应迁移到引擎 `Animation`
- 若素材来自 NPK/PVF 体系,优先用 `Animation + NpkArchive + parseAniFromPvf`
- 若当前临时素材仍是 PNG spritesheet,可以短期保留,但不要扩展成复杂自研动画状态系统。
### Audio / Save
引擎已有:
- `AudioSystem`
- `Sound`
- `Music`
- `SoundPackArchive`
- `AudioDatabase`
- `SaveSystem`
当前状态:
- 游戏层尚未使用音频和存档。
后续原则:
- 音效、BGM、环境音直接接引擎音频系统。
- 设置、进度、调试存档优先用 `SaveSystem`,不要在游戏层重新写文件存档服务。
### Event / Input
已使用:
- `KeyEvent`
- `EventType::KeyDown`
游戏层自定义:
- `InputState`
- `InputStateProvider`
判断:
- `InputState` 作为游戏语义输入是合理的,能隔离 PC/Switch 差异。
- 但底层输入事件和生命周期应继续使用引擎事件系统。
下一步:
- `InputConfig` 可以作为游戏层配置,但读取配置应走 `Asset` 或 PVF。
- Debug 输入和 gameplay 输入要分离,避免正式版本保留开发快捷键。
## 当前游戏层自造/硬编码点
### 1. 地图硬编码
文件:
- `game/src/data/whitebox_level.cpp`
问题:
- 世界尺寸、平台、视觉层、props、battle zone、spawn point 全部写在 C++。
- 这不适合后续反复调地图,也不适合你要的 `.map` 工作流。
建议:
- 新增 `StageMapLoader`
- 创建 `game/assets/stage/stage_01/stage_01.map``game/assets/map/stage_01.map`
-`CreateWhiteboxLevel()` 临时变成:
```cpp
return LoadStageMap("map/stage_01.map").value_or(CreateFallbackWhiteboxLevel());
```
### 2. 手写动画帧切换
文件:
- `game/src/actor/player_actor.cpp`
问题:
- idle/run/punch 都在 C++ 里硬编码帧数、帧时间和 source rect。
建议:
- 先记录为短期可接受。
- 后续迁移到引擎 `Animation`,尤其当角色素材进入 PVF/NPK/ANI 体系后。
### 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,不作为长期地图生产方式。