feat(场景管理): 添加UIScene支持并重构场景管理器
refactor(渲染器): 优化相机切换时的渲染批处理 feat(调试工具): 新增游戏调试UI场景和九宫格面板组件 fix(动画系统): 跳过缺失的动画资源加载并记录日志 perf(资源加载): 使用BinaryFileStreamReader优化NPK文件解析 feat(地图系统): 支持多边形可行走区域调试显示 style(代码格式): 清理多余空格和统一文件编码 docs(注释): 补充关键类和方法的文档说明 test(启动跟踪): 添加启动过程性能跟踪工具 chore(依赖): 添加SDL2_ttf库支持
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "character/CharacterAnimation.h"
|
||||
#include "character/CharacterObject.h"
|
||||
#include <frostbite2D/resource/pvf_archive.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -38,6 +39,8 @@ bool CharacterAnimation::Init(CharacterObject* parent,
|
||||
const CharacterEquipmentManager& equipmentManager) {
|
||||
parent_ = parent;
|
||||
actionAnimations_.clear();
|
||||
missingAnimationPaths_.clear();
|
||||
skippedMissingAnimationCount_ = 0;
|
||||
currentActionTag_.clear();
|
||||
direction_ = 1;
|
||||
actionFrameFlagCallback_ = nullptr;
|
||||
@@ -56,6 +59,12 @@ bool CharacterAnimation::Init(CharacterObject* parent,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (skippedMissingAnimationCount_ > 0) {
|
||||
SDL_Log("CharacterAnimation: skipped %zu missing animation loads across %zu unique paths for job %d",
|
||||
skippedMissingAnimationCount_, missingAnimationPaths_.size(),
|
||||
config.jobId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,6 +86,10 @@ void CharacterAnimation::CreateAnimationBySlot(
|
||||
const character::CharacterConfig& config,
|
||||
const CharacterEquipmentManager& equipmentManager) {
|
||||
if (slotName == std::string("skin_avatar")) {
|
||||
if (shouldSkipMissingAnimation(actionPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Animation::ReplaceData replaceData(0, 0);
|
||||
if (const auto* equip = equipmentManager.GetEquip(slotName)) {
|
||||
auto it = equip->jobAnimations.find(config.jobId);
|
||||
@@ -114,6 +127,10 @@ void CharacterAnimation::CreateAnimationBySlot(
|
||||
}
|
||||
|
||||
std::string aniPath = equipDir + "/" + variation.animationGroup + actionPathTail;
|
||||
if (shouldSkipMissingAnimation(aniPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto animation = MakePtr<Animation>(
|
||||
aniPath, FormatImgPath,
|
||||
Animation::ReplaceData(variation.imgFormat[0], variation.imgFormat[1]));
|
||||
@@ -128,6 +145,23 @@ void CharacterAnimation::CreateAnimationBySlot(
|
||||
}
|
||||
}
|
||||
|
||||
bool CharacterAnimation::shouldSkipMissingAnimation(const std::string& aniPath) {
|
||||
PvfArchive& pvf = PvfArchive::get();
|
||||
std::string normalizedPath = pvf.normalizePath(aniPath);
|
||||
if (missingAnimationPaths_.find(normalizedPath) != missingAnimationPaths_.end()) {
|
||||
++skippedMissingAnimationCount_;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pvf.hasFile(normalizedPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
missingAnimationPaths_.insert(std::move(normalizedPath));
|
||||
++skippedMissingAnimationCount_;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CharacterAnimation::DescribeAvailableActions() const {
|
||||
if (actionAnimations_.empty()) {
|
||||
return "<none>";
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <cmath>
|
||||
#include <frostbite2D/core/application.h>
|
||||
#include <frostbite2D/utils/startup_trace.h>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
@@ -49,6 +50,7 @@ int32 RoundWorldCoordinate(float value) {
|
||||
} // namespace
|
||||
|
||||
bool CharacterObject::Construction(int jobId) {
|
||||
ScopedStartupTrace startupTrace("CharacterObject::Construction");
|
||||
// Reset all runtime state before rebuilding the character from config.
|
||||
EnableEventReceive();
|
||||
RemoveAllChildren();
|
||||
@@ -67,7 +69,10 @@ bool CharacterObject::Construction(int jobId) {
|
||||
lastDeltaTime_ = 0.0f;
|
||||
inputEnabled_ = true;
|
||||
|
||||
auto config = character::loadCharacterConfig(jobId);
|
||||
auto config = [&]() {
|
||||
ScopedStartupTrace stageTrace("character::loadCharacterConfig");
|
||||
return character::loadCharacterConfig(jobId);
|
||||
}();
|
||||
if (!config) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"CharacterObject: failed to load job %d config", jobId);
|
||||
@@ -79,24 +84,36 @@ bool CharacterObject::Construction(int jobId) {
|
||||
direction_ = 1;
|
||||
config_ = *config;
|
||||
stateMachine_.Configure(*config_);
|
||||
equipmentManager_.Init(config_->baseJobConfig);
|
||||
if (auto actionLibrary = loadCharacterActionLibrary(*config_)) {
|
||||
{
|
||||
ScopedStartupTrace stageTrace("CharacterEquipmentManager::Init");
|
||||
equipmentManager_.Init(config_->baseJobConfig);
|
||||
}
|
||||
if (auto actionLibrary = [&]() {
|
||||
ScopedStartupTrace stageTrace("loadCharacterActionLibrary");
|
||||
return loadCharacterActionLibrary(*config_);
|
||||
}()) {
|
||||
actionLibrary_ = *actionLibrary;
|
||||
}
|
||||
|
||||
animationManager_ = MakePtr<CharacterAnimation>();
|
||||
if (!animationManager_->Init(this, *config_, equipmentManager_)) {
|
||||
ReportFatalCharacterError("CharacterObject::Construction",
|
||||
"no usable animation tags were loaded");
|
||||
return false;
|
||||
{
|
||||
ScopedStartupTrace stageTrace("CharacterAnimation::Init");
|
||||
if (!animationManager_->Init(this, *config_, equipmentManager_)) {
|
||||
ReportFatalCharacterError("CharacterObject::Construction",
|
||||
"no usable animation tags were loaded");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
AddChild(animationManager_);
|
||||
|
||||
if (!RequireAction("idle", "CharacterObject::Construction")) {
|
||||
return false;
|
||||
}
|
||||
if (!SetActionStrict("rest", "CharacterObject::Construction", "idle")) {
|
||||
return false;
|
||||
{
|
||||
ScopedStartupTrace stageTrace("CharacterObject initial action setup");
|
||||
if (!RequireAction("idle", "CharacterObject::Construction")) {
|
||||
return false;
|
||||
}
|
||||
if (!SetActionStrict("rest", "CharacterObject::Construction", "idle")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SetWorldPosition({});
|
||||
|
||||
Reference in New Issue
Block a user