Split stage rendering and debug overlay
This commit is contained in:
@@ -17,8 +17,10 @@ game/
|
|||||||
├─ combat/ 碰撞箱、伤害判定和战斗解算类型
|
├─ combat/ 碰撞箱、伤害判定和战斗解算类型
|
||||||
├─ core/ 共享配置、输入快照和资源路径
|
├─ core/ 共享配置、输入快照和资源路径
|
||||||
├─ data/ 关卡和游戏数据定义
|
├─ data/ 关卡和游戏数据定义
|
||||||
|
├─ debug/ 调试可视化叠层
|
||||||
├─ movement/ 可复用的移动和碰撞辅助工具
|
├─ movement/ 可复用的移动和碰撞辅助工具
|
||||||
├─ scene/ 游戏场景和关卡编排
|
├─ scene/ 游戏场景和关卡编排
|
||||||
|
├─ stage/ 关卡视觉层渲染
|
||||||
└─ main.cpp 游戏可执行文件入口点
|
└─ main.cpp 游戏可执行文件入口点
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -37,7 +39,9 @@ main.cpp
|
|||||||
-> PlayerActor 通过 PlatformMover 移动
|
-> PlayerActor 通过 PlatformMover 移动
|
||||||
-> PlayerActor 更新动画
|
-> PlayerActor 更新动画
|
||||||
-> WhiteboxScene 更新摄像机
|
-> WhiteboxScene 更新摄像机
|
||||||
-> WhiteboxScene 绘制白盒关卡
|
-> StageRenderer 绘制关卡视觉层
|
||||||
|
-> Actor 渲染
|
||||||
|
-> DebugOverlay 绘制调试叠层
|
||||||
```
|
```
|
||||||
|
|
||||||
## 模块职责
|
## 模块职责
|
||||||
@@ -47,6 +51,7 @@ main.cpp
|
|||||||
- `game_config.h` 存储共享的调整常数,如虚拟分辨率、
|
- `game_config.h` 存储共享的调整常数,如虚拟分辨率、
|
||||||
重力、玩家速度和攻击持续时间
|
重力、玩家速度和攻击持续时间
|
||||||
- `asset_paths.h` 存储稳定的运行时资源路径
|
- `asset_paths.h` 存储稳定的运行时资源路径
|
||||||
|
- `debug_flags.h` 集中控制开发期调试显示开关
|
||||||
- `input_state.*` 将原始 SDL 键盘状态转换为与引擎无关的
|
- `input_state.*` 将原始 SDL 键盘状态转换为与引擎无关的
|
||||||
`InputState` 快照。玩家逻辑使用此快照而不是直接读取
|
`InputState` 快照。玩家逻辑使用此快照而不是直接读取
|
||||||
SDL
|
SDL
|
||||||
@@ -74,7 +79,17 @@ main.cpp
|
|||||||
`scene`
|
`scene`
|
||||||
|
|
||||||
- `WhiteboxScene` 编排当前关卡:加载关卡数据、创建
|
- `WhiteboxScene` 编排当前关卡:加载关卡数据、创建
|
||||||
角色、绘制白盒几何和控制摄像机
|
角色、委托关卡渲染、委托调试叠层并控制摄像机
|
||||||
|
|
||||||
|
`stage`
|
||||||
|
|
||||||
|
- `StageRenderer` 绘制当前关卡视觉层,包括背景、网格、白盒道具和平台
|
||||||
|
- 后续 tileset、视差背景和 props 渲染都应该优先接入该模块
|
||||||
|
|
||||||
|
`debug`
|
||||||
|
|
||||||
|
- `DebugOverlay` 绘制碰撞矩形和玩家包围盒
|
||||||
|
- `DebugFlags` 决定哪些调试层启用
|
||||||
|
|
||||||
`combat`
|
`combat`
|
||||||
|
|
||||||
|
|||||||
@@ -121,11 +121,11 @@ mindmap
|
|||||||
- `core/game_config.h`
|
- `core/game_config.h`
|
||||||
- `core/asset_paths.h`
|
- `core/asset_paths.h`
|
||||||
- `core/input_state.*`
|
- `core/input_state.*`
|
||||||
|
- `core/debug_flags.h`
|
||||||
|
|
||||||
下一步:
|
下一步:
|
||||||
|
|
||||||
- 增加 `GameContext`,统一传递全局服务。
|
- 增加 `GameContext`,统一传递全局服务。
|
||||||
- 增加 `DebugFlags`,集中管理调试开关。
|
|
||||||
- 输入层支持键盘和手柄统一映射。
|
- 输入层支持键盘和手柄统一映射。
|
||||||
|
|
||||||
### 2. Scene
|
### 2. Scene
|
||||||
@@ -159,10 +159,10 @@ mindmap
|
|||||||
- `data/level_definition.h`
|
- `data/level_definition.h`
|
||||||
- `data/whitebox_level.cpp`
|
- `data/whitebox_level.cpp`
|
||||||
- `movement/platform_world.*`
|
- `movement/platform_world.*`
|
||||||
|
- `stage/stage_renderer.*`
|
||||||
|
|
||||||
下一步:
|
下一步:
|
||||||
|
|
||||||
- 增加 `StageRenderer`。
|
|
||||||
- 增加 `StageLayer` 数据结构。
|
- 增加 `StageLayer` 数据结构。
|
||||||
- 关卡宽度扩展到 2400 到 3200 像素。
|
- 关卡宽度扩展到 2400 到 3200 像素。
|
||||||
- 引入远景/中景/地面三层绘制。
|
- 引入远景/中景/地面三层绘制。
|
||||||
@@ -287,6 +287,7 @@ mindmap
|
|||||||
|
|
||||||
下一步:
|
下一步:
|
||||||
|
|
||||||
|
- `debug/debug_overlay.*` 已经提供碰撞和玩家包围盒绘制。
|
||||||
- `F1` 切换 debug overlay。
|
- `F1` 切换 debug overlay。
|
||||||
- 绘制平台碰撞。
|
- 绘制平台碰撞。
|
||||||
- 绘制 battle zone。
|
- 绘制 battle zone。
|
||||||
@@ -378,12 +379,11 @@ mindmap
|
|||||||
|
|
||||||
下一步建议按这个顺序做:
|
下一步建议按这个顺序做:
|
||||||
|
|
||||||
1. `StageRenderer`:让关卡视觉层从 Scene 中独立出来。
|
1. `BattleZone`:做清版推进的核心框架。
|
||||||
2. `DebugOverlay`:显示碰撞、战斗区域和出生点。
|
2. `EnemyActor`:做第一个敌人占位。
|
||||||
3. `BattleZone`:做清版推进的核心框架。
|
3. `CombatSystem`:把 hitbox/hurtbox 真正跑起来。
|
||||||
4. `EnemyActor`:做第一个敌人占位。
|
4. `SpriteAnimator`:把玩家动画从硬编码改成组件。
|
||||||
5. `CombatSystem`:把 hitbox/hurtbox 真正跑起来。
|
5. `StageLayer`:把白盒视觉层扩展为背景、tiles 和 props。
|
||||||
6. `SpriteAnimator`:把玩家动画从硬编码改成组件。
|
|
||||||
|
|
||||||
## 素材协作提示
|
## 素材协作提示
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ns_game {
|
||||||
|
|
||||||
|
struct DebugFlags {
|
||||||
|
bool showStageGrid = true;
|
||||||
|
bool showCollision = true;
|
||||||
|
bool showActorBounds = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ns_game
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#include "debug_overlay.h"
|
||||||
|
|
||||||
|
#include <frostbite2D/graphics/renderer.h>
|
||||||
|
|
||||||
|
namespace ns_game {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void drawRect(const frostbite2D::Rect& rect, const frostbite2D::Color& color) {
|
||||||
|
frostbite2D::Renderer::get().drawQuad(rect, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawOutline(const frostbite2D::Rect& rect, const frostbite2D::Color& color,
|
||||||
|
float thickness = 2.0f) {
|
||||||
|
drawRect(frostbite2D::Rect(rect.left(), rect.top(), rect.width(), thickness),
|
||||||
|
color);
|
||||||
|
drawRect(frostbite2D::Rect(rect.left(), rect.bottom() - thickness,
|
||||||
|
rect.width(), thickness),
|
||||||
|
color);
|
||||||
|
drawRect(frostbite2D::Rect(rect.left(), rect.top(), thickness, rect.height()),
|
||||||
|
color);
|
||||||
|
drawRect(frostbite2D::Rect(rect.right() - thickness, rect.top(), thickness,
|
||||||
|
rect.height()),
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void DebugOverlay::Render(const LevelDefinition& level, const DebugFlags& flags,
|
||||||
|
const frostbite2D::Rect* playerBounds) const {
|
||||||
|
if (flags.showCollision) {
|
||||||
|
drawCollision(level);
|
||||||
|
}
|
||||||
|
if (flags.showActorBounds && playerBounds) {
|
||||||
|
drawActorBounds(*playerBounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::drawCollision(const LevelDefinition& level) const {
|
||||||
|
for (const auto& platform : level.collision.platforms) {
|
||||||
|
drawOutline(platform, frostbite2D::Color(0.1f, 0.95f, 0.45f, 0.85f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::drawActorBounds(const frostbite2D::Rect& bounds) const {
|
||||||
|
drawOutline(bounds, frostbite2D::Color(1.0f, 0.78f, 0.1f, 0.9f));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ns_game
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../core/debug_flags.h"
|
||||||
|
#include "../data/level_definition.h"
|
||||||
|
|
||||||
|
#include <frostbite2D/types/type_math.h>
|
||||||
|
|
||||||
|
namespace ns_game {
|
||||||
|
|
||||||
|
class DebugOverlay {
|
||||||
|
public:
|
||||||
|
void Render(const LevelDefinition& level, const DebugFlags& flags,
|
||||||
|
const frostbite2D::Rect* playerBounds) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawCollision(const LevelDefinition& level) const;
|
||||||
|
void drawActorBounds(const frostbite2D::Rect& bounds) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ns_game
|
||||||
@@ -9,14 +9,6 @@
|
|||||||
|
|
||||||
namespace ns_game {
|
namespace ns_game {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void drawRect(const frostbite2D::Rect& rect, const frostbite2D::Color& color) {
|
|
||||||
frostbite2D::Renderer::get().drawQuad(rect, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void WhiteboxScene::onEnter() {
|
void WhiteboxScene::onEnter() {
|
||||||
frostbite2D::Scene::onEnter();
|
frostbite2D::Scene::onEnter();
|
||||||
level_ = CreateWhiteboxLevel();
|
level_ = CreateWhiteboxLevel();
|
||||||
@@ -32,35 +24,11 @@ void WhiteboxScene::OnUpdate(float deltaTime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WhiteboxScene::Render() {
|
void WhiteboxScene::Render() {
|
||||||
drawWhitebox();
|
stageRenderer_.Render(level_, debugFlags_);
|
||||||
frostbite2D::Scene::Render();
|
frostbite2D::Scene::Render();
|
||||||
}
|
const frostbite2D::Rect playerBounds =
|
||||||
|
player_ ? player_->GetWorldBounds() : frostbite2D::Rect::Zero();
|
||||||
void WhiteboxScene::drawWhitebox() const {
|
debugOverlay_.Render(level_, debugFlags_, player_ ? &playerBounds : nullptr);
|
||||||
const float worldWidth = level_.collision.levelRight - level_.collision.levelLeft;
|
|
||||||
drawRect(frostbite2D::Rect(level_.collision.levelLeft, 0.0f, worldWidth,
|
|
||||||
config::kVirtualHeight),
|
|
||||||
frostbite2D::Color(0.10f, 0.12f, 0.14f, 1.0f));
|
|
||||||
|
|
||||||
for (float x = level_.collision.levelLeft; x <= level_.collision.levelRight;
|
|
||||||
x += 80.0f) {
|
|
||||||
drawRect(frostbite2D::Rect(x, 0.0f, 1.0f, config::kVirtualHeight),
|
|
||||||
frostbite2D::Color(0.20f, 0.22f, 0.25f, 1.0f));
|
|
||||||
}
|
|
||||||
for (float y = 0.0f; y <= config::kVirtualHeight; y += 80.0f) {
|
|
||||||
drawRect(frostbite2D::Rect(level_.collision.levelLeft, y, worldWidth, 1.0f),
|
|
||||||
frostbite2D::Color(0.20f, 0.22f, 0.25f, 1.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& prop : level_.props) {
|
|
||||||
drawRect(prop.bounds, prop.color);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& platform : level_.collision.platforms) {
|
|
||||||
drawRect(platform, frostbite2D::Color(0.62f, 0.68f, 0.73f, 1.0f));
|
|
||||||
drawRect(frostbite2D::Rect(platform.left(), platform.top(), platform.width(), 4.0f),
|
|
||||||
frostbite2D::Color(0.91f, 0.95f, 0.98f, 1.0f));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WhiteboxScene::updateCamera() {
|
void WhiteboxScene::updateCamera() {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../actor/player_actor.h"
|
#include "../actor/player_actor.h"
|
||||||
|
#include "../core/debug_flags.h"
|
||||||
#include "../data/level_definition.h"
|
#include "../data/level_definition.h"
|
||||||
|
#include "../debug/debug_overlay.h"
|
||||||
|
#include "../stage/stage_renderer.h"
|
||||||
|
|
||||||
#include <frostbite2D/scene/scene.h>
|
#include <frostbite2D/scene/scene.h>
|
||||||
#include <frostbite2D/types/type_math.h>
|
#include <frostbite2D/types/type_math.h>
|
||||||
@@ -15,10 +18,12 @@ public:
|
|||||||
void Render() override;
|
void Render() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void drawWhitebox() const;
|
|
||||||
void updateCamera();
|
void updateCamera();
|
||||||
|
|
||||||
LevelDefinition level_;
|
LevelDefinition level_;
|
||||||
|
DebugFlags debugFlags_;
|
||||||
|
StageRenderer stageRenderer_;
|
||||||
|
DebugOverlay debugOverlay_;
|
||||||
frostbite2D::Ptr<PlayerActor> player_;
|
frostbite2D::Ptr<PlayerActor> player_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#include "stage_renderer.h"
|
||||||
|
|
||||||
|
#include "../core/game_config.h"
|
||||||
|
|
||||||
|
#include <frostbite2D/graphics/renderer.h>
|
||||||
|
|
||||||
|
namespace ns_game {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void drawRect(const frostbite2D::Rect& rect, const frostbite2D::Color& color) {
|
||||||
|
frostbite2D::Renderer::get().drawQuad(rect, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
float worldWidthOf(const LevelDefinition& level) {
|
||||||
|
return level.collision.levelRight - level.collision.levelLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void StageRenderer::Render(const LevelDefinition& level,
|
||||||
|
const DebugFlags& debugFlags) const {
|
||||||
|
drawBackground(level);
|
||||||
|
if (debugFlags.showStageGrid) {
|
||||||
|
drawGrid(level);
|
||||||
|
}
|
||||||
|
drawProps(level);
|
||||||
|
drawPlatforms(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StageRenderer::drawBackground(const LevelDefinition& level) const {
|
||||||
|
drawRect(frostbite2D::Rect(level.collision.levelLeft, 0.0f,
|
||||||
|
worldWidthOf(level), config::kVirtualHeight),
|
||||||
|
frostbite2D::Color(0.10f, 0.12f, 0.14f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StageRenderer::drawGrid(const LevelDefinition& level) const {
|
||||||
|
const float worldWidth = worldWidthOf(level);
|
||||||
|
for (float x = level.collision.levelLeft; x <= level.collision.levelRight;
|
||||||
|
x += 80.0f) {
|
||||||
|
drawRect(frostbite2D::Rect(x, 0.0f, 1.0f, config::kVirtualHeight),
|
||||||
|
frostbite2D::Color(0.20f, 0.22f, 0.25f, 1.0f));
|
||||||
|
}
|
||||||
|
for (float y = 0.0f; y <= config::kVirtualHeight; y += 80.0f) {
|
||||||
|
drawRect(frostbite2D::Rect(level.collision.levelLeft, y, worldWidth, 1.0f),
|
||||||
|
frostbite2D::Color(0.20f, 0.22f, 0.25f, 1.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StageRenderer::drawProps(const LevelDefinition& level) const {
|
||||||
|
for (const auto& prop : level.props) {
|
||||||
|
drawRect(prop.bounds, prop.color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StageRenderer::drawPlatforms(const LevelDefinition& level) const {
|
||||||
|
for (const auto& platform : level.collision.platforms) {
|
||||||
|
drawRect(platform, frostbite2D::Color(0.62f, 0.68f, 0.73f, 1.0f));
|
||||||
|
drawRect(frostbite2D::Rect(platform.left(), platform.top(),
|
||||||
|
platform.width(), 4.0f),
|
||||||
|
frostbite2D::Color(0.91f, 0.95f, 0.98f, 1.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ns_game
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../data/level_definition.h"
|
||||||
|
#include "../core/debug_flags.h"
|
||||||
|
|
||||||
|
namespace ns_game {
|
||||||
|
|
||||||
|
class StageRenderer {
|
||||||
|
public:
|
||||||
|
void Render(const LevelDefinition& level, const DebugFlags& debugFlags) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawBackground(const LevelDefinition& level) const;
|
||||||
|
void drawGrid(const LevelDefinition& level) const;
|
||||||
|
void drawProps(const LevelDefinition& level) const;
|
||||||
|
void drawPlatforms(const LevelDefinition& level) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ns_game
|
||||||
Reference in New Issue
Block a user