feat(animation): 添加动画状态回调支持

refactor(character): 重构角色动作处理逻辑

feat(swordman): 实现剑士基础攻击和技能1处理

refactor(state): 优化状态机与动作上下文管理

feat(input): 改进输入系统支持动作请求队列

refactor(movement): 重构移动系统支持行走/奔跑模式
This commit is contained in:
2026-04-04 14:45:41 +08:00
parent 1200cf0181
commit 5e80df040b
29 changed files with 1251 additions and 513 deletions

View File

@@ -1,9 +1,11 @@
#include "character/CharacterAnimation.h"
#include "character/CharacterObject.h"
#include <SDL2/SDL.h>
#include <algorithm>
#include <array>
#include <cstdio>
#include <sstream>
#include <utility>
namespace frostbite2D {
namespace {
@@ -38,6 +40,8 @@ bool CharacterAnimation::Init(CharacterObject* parent,
actionAnimations_.clear();
currentActionTag_.clear();
direction_ = 1;
actionFrameFlagCallback_ = nullptr;
actionEndCallback_ = nullptr;
for (const auto& [actionName, actionPath] : config.animationPath) {
for (const char* slotName : kAvatarParts) {
@@ -142,6 +146,56 @@ std::string CharacterAnimation::DescribeAvailableActions() const {
return stream.str();
}
Animation* CharacterAnimation::GetPrimaryAnimation(const std::string& actionName) const {
auto it = actionAnimations_.find(actionName);
if (it == actionAnimations_.end()) {
return nullptr;
}
for (const auto& animation : it->second) {
if (animation && animation->IsUsable()) {
return animation.Get();
}
}
for (const auto& animation : it->second) {
if (animation) {
return animation.Get();
}
}
return nullptr;
}
Animation* CharacterAnimation::GetCurrentPrimaryAnimation() const {
if (currentActionTag_.empty()) {
return nullptr;
}
return GetPrimaryAnimation(currentActionTag_);
}
void CharacterAnimation::RefreshRuntimeCallbacks() {
auto currentIt = actionAnimations_.find(currentActionTag_);
if (currentIt == actionAnimations_.end()) {
return;
}
Animation* primaryAnimation = GetPrimaryAnimation(currentActionTag_);
for (auto& animation : currentIt->second) {
if (!animation) {
continue;
}
if (animation.Get() == primaryAnimation) {
animation->changeFrameCallback_ = actionFrameFlagCallback_;
animation->endCallback_ = actionEndCallback_;
} else {
animation->changeFrameCallback_ = nullptr;
animation->endCallback_ = nullptr;
}
}
}
bool CharacterAnimation::SetAction(const std::string& actionName) {
auto nextIt = actionAnimations_.find(actionName);
if (nextIt == actionAnimations_.end()) {
@@ -172,6 +226,7 @@ bool CharacterAnimation::SetAction(const std::string& actionName) {
animation->SetVisible(true);
}
currentActionTag_ = actionName;
RefreshRuntimeCallbacks();
SetDirection(direction_);
return true;
}
@@ -191,4 +246,51 @@ void CharacterAnimation::SetDirection(int direction) {
}
}
bool CharacterAnimation::IsCurrentActionFinished() const {
const Animation* primaryAnimation = GetCurrentPrimaryAnimation();
if (!primaryAnimation) {
return false;
}
return !primaryAnimation->IsUsable();
}
int CharacterAnimation::GetCurrentFrameIndex() const {
const Animation* primaryAnimation = GetCurrentPrimaryAnimation();
return primaryAnimation ? primaryAnimation->GetCurrentFrameIndex() : 0;
}
int CharacterAnimation::GetCurrentFrameCount() const {
const Animation* primaryAnimation = GetCurrentPrimaryAnimation();
return primaryAnimation ? primaryAnimation->GetTotalFrameCount() : 0;
}
float CharacterAnimation::GetCurrentNormalizedProgress() const {
int totalFrames = GetCurrentFrameCount();
if (totalFrames <= 1) {
return IsCurrentActionFinished() ? 1.0f : 0.0f;
}
float progress = static_cast<float>(GetCurrentFrameIndex())
/ static_cast<float>(totalFrames - 1);
return std::clamp(progress, 0.0f, 1.0f);
}
animation::AniFrame CharacterAnimation::GetCurrentFrameInfo() const {
const Animation* primaryAnimation = GetCurrentPrimaryAnimation();
if (!primaryAnimation) {
return animation::AniFrame();
}
return primaryAnimation->GetCurrentFrameInfo();
}
void CharacterAnimation::SetActionFrameFlagCallback(ActionFrameFlagCallback callback) {
actionFrameFlagCallback_ = std::move(callback);
RefreshRuntimeCallbacks();
}
void CharacterAnimation::SetActionEndCallback(ActionEndCallback callback) {
actionEndCallback_ = std::move(callback);
RefreshRuntimeCallbacks();
}
} // namespace frostbite2D