Files
Frostbite2D/Game/src/common/debug/GameDebugActor.cpp
Lenheart e570fec599 feat(角色): 添加角色阴影渲染功能
新增 CharacterShadowActor 类用于处理角色阴影的渲染
在 CharacterObject 中实现阴影的同步和渲染逻辑
移除 GameDebugActor 中不再使用的合成纹理预览代码
添加 EnsureCompositeTextureReady 方法确保纹理准备就绪
2026-04-07 07:08:53 +08:00

226 lines
6.1 KiB
C++

#include "common/debug/GameDebugActor.h"
#include "character/CharacterObject.h"
#include "map/GameMap.h"
#include "ui/NineSliceActor.h"
#include <SDL2/SDL.h>
#include <algorithm>
#include <frostbite2D/2d/text_sprite.h>
#include <frostbite2D/scene/scene.h>
#include <limits>
namespace frostbite2D {
namespace {
constexpr float kDebugHudMarginX = 12.0f;
constexpr float kDebugHudMarginY = 12.0f;
constexpr float kDebugHudPaddingX = 8.0f;
constexpr float kDebugHudPaddingY = 6.0f;
constexpr float kDebugHudLineGap = 4.0f;
constexpr char kDebugHudPopupImg[] = "sprite/interface/newstyle/windows/popup/popup.img";
void ConfigureTextLine(RefPtr<TextSprite> textSprite, const char* name,
int zOrder) {
if (!textSprite) {
return;
}
textSprite->SetName(name);
textSprite->SetFont("default");
textSprite->SetTextColor(1.0f, 1.0f, 1.0f, 1.0f);
textSprite->SetZOrder(zOrder);
}
} // namespace
GameDebugActor::GameDebugActor() {
SetName("GameDebugActor");
SetZOrder(std::numeric_limits<int>::max());
initOverlay();
}
GameDebugActor& GameDebugActor::get() {
return *getPtr();
}
Ptr<GameDebugActor> GameDebugActor::getPtr() {
static Ptr<GameDebugActor> instance(new GameDebugActor());
return instance;
}
bool GameDebugActor::AttachToScene(Scene* scene) {
return AttachToParent(scene);
}
bool GameDebugActor::AttachToParent(Actor* parent) {
if (!parent || parent == this) {
return false;
}
Ptr<GameDebugActor> self = getPtr();
if (GetParent() == parent) {
return true;
}
if (GetParent()) {
GetParent()->RemoveChild(self);
}
parent->AddChild(self);
return GetParent() == parent;
}
void GameDebugActor::DetachFromParent() {
Ptr<GameDebugActor> self = getPtr();
if (GetParent()) {
GetParent()->RemoveChild(self);
}
}
void GameDebugActor::SetDebugMap(GameMap* map) {
if (debugMap_ && debugMap_ != map) {
debugMap_->SetDebugHighlightedMoveAreaIndex(GameMap::kInvalidMoveAreaIndex);
}
debugMap_ = map;
updateOverlay();
}
void GameDebugActor::SetTrackedCharacter(CharacterObject* character) {
trackedCharacter_ = character;
updateOverlay();
}
void GameDebugActor::ClearDebugContext() {
if (debugMap_) {
debugMap_->SetDebugHighlightedMoveAreaIndex(GameMap::kInvalidMoveAreaIndex);
}
debugMap_ = nullptr;
trackedCharacter_ = nullptr;
setOverlayVisible(false);
}
void GameDebugActor::OnUpdate(float deltaTime) {
(void)deltaTime;
updateOverlay();
}
void GameDebugActor::initOverlay() {
if (background_ || coordText_ || actionText_) {
return;
}
background_ = NineSliceActor::createFromNpk(kDebugHudPopupImg, 0);
if (background_) {
background_->SetName("debugHudBackground");
AddChild(background_);
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"GameDebugActor: failed to load HUD background from %s",
kDebugHudPopupImg);
}
coordText_ = TextSprite::create();
ConfigureTextLine(coordText_, "debugCoordText", 1);
AddChild(coordText_);
actionText_ = TextSprite::create();
ConfigureTextLine(actionText_, "debugActionText", 1);
AddChild(actionText_);
setOverlayVisible(false);
}
void GameDebugActor::updateOverlay() {
if (!coordText_ || !actionText_) {
setOverlayVisible(false);
return;
}
updateMapDebugHighlight();
if (!trackedCharacter_) {
setOverlayVisible(false);
return;
}
const CharacterWorldPosition& worldPosition = trackedCharacter_->GetWorldPosition();
char coordTextBuffer[96];
SDL_snprintf(coordTextBuffer, sizeof(coordTextBuffer), "角色坐标: (%d, %d, %d)",
worldPosition.x, worldPosition.y, worldPosition.z);
coordText_->SetText(coordTextBuffer);
int frameCount = std::max(trackedCharacter_->GetCurrentAnimationFrameCount(), 1);
int frameIndex = std::clamp(trackedCharacter_->GetCurrentAnimationFrameIndex(), 0,
frameCount - 1);
char actionTextBuffer[128];
SDL_snprintf(actionTextBuffer, sizeof(actionTextBuffer),
"Action: %s dir:%c frame:%d/%d",
trackedCharacter_->GetCurrentAction().empty()
? "<none>"
: trackedCharacter_->GetCurrentAction().c_str(),
trackedCharacter_->GetDirection() >= 0 ? 'R' : 'L', frameIndex + 1,
frameCount);
actionText_->SetText(actionTextBuffer);
Vec2 coordTextSize = coordText_->GetTextSize();
Vec2 actionTextSize = actionText_->GetTextSize();
float panelWidth = std::max(coordTextSize.x, actionTextSize.x) + kDebugHudPaddingX * 2.0f;
float contentHeight = coordTextSize.y;
if (actionText_->IsVisible()) {
contentHeight += kDebugHudLineGap + actionTextSize.y;
}
float panelHeight = contentHeight + kDebugHudPaddingY * 2.0f;
Vec2 panelSize(panelWidth, panelHeight);
if (background_) {
background_->SetSize(panelSize);
}
SetPosition(kDebugHudMarginX, kDebugHudMarginY);
SetScale(1.0f);
float currentY = kDebugHudPaddingY;
coordText_->SetPosition(kDebugHudPaddingX, currentY);
currentY += coordTextSize.y;
if (actionText_->IsVisible()) {
currentY += kDebugHudLineGap;
actionText_->SetPosition(kDebugHudPaddingX, currentY);
currentY += actionTextSize.y;
}
setOverlayVisible(true);
}
void GameDebugActor::updateMapDebugHighlight() {
if (!debugMap_) {
return;
}
if (!trackedCharacter_ || !debugMap_->IsDebugModeEnabled()) {
debugMap_->SetDebugHighlightedMoveAreaIndex(GameMap::kInvalidMoveAreaIndex);
return;
}
const CharacterWorldPosition& worldPosition = trackedCharacter_->GetWorldPosition();
Vec3 currentWorldPos(static_cast<float>(worldPosition.x),
static_cast<float>(worldPosition.y),
static_cast<float>(worldPosition.z));
size_t moveAreaIndex = debugMap_->FindMoveAreaIndex(currentWorldPos);
debugMap_->SetDebugHighlightedMoveAreaIndex(moveAreaIndex);
}
void GameDebugActor::setOverlayVisible(bool visible) {
if (background_) {
background_->SetVisible(visible);
}
if (coordText_) {
coordText_->SetVisible(visible);
}
if (actionText_) {
actionText_->SetVisible(visible);
}
}
} // namespace frostbite2D