完成动画组件与动画载入

This commit is contained in:
Ziyu
2025-06-16 14:44:47 +08:00
parent fc8a8cec5c
commit a31890fc20
20 changed files with 477 additions and 5 deletions
@@ -0,0 +1,95 @@
#include "animation_component.h"
#include "sprite_component.h"
#include "../object/game_object.h"
#include "../render/animation.h"
#include <spdlog/spdlog.h>
namespace engine::component {
AnimationComponent::~AnimationComponent() = default;
void AnimationComponent::init() {
if (!owner_) {
spdlog::error("AnimationComponent 没有所有者 GameObject!");
return;
}
sprite_component_ = owner_->getComponent<SpriteComponent>();
if (!sprite_component_) {
spdlog::error("GameObject '{}' 的 AnimationComponent 需要 SpriteComponent,但未找到。", owner_->getName());
return;
}
}
void AnimationComponent::update(float delta_time, engine::core::Context&) {
// 如果没有正在播放的动画,或者没有当前动画,或者没有精灵组件,或者当前动画没有帧,则直接返回
if (!is_playing_ || !current_animation_ || !sprite_component_ || current_animation_->isEmpty()) {
spdlog::trace("AnimationComponent 更新时没有正在播放的动画或精灵组件为空。");
return;
}
// 推进计时器
animation_timer_ += delta_time;
// 根据时间获取当前帧
const auto& current_frame = current_animation_->getFrame(animation_timer_);
// 更新精灵组件的源矩形 (使用 SpriteComponent 的新方法)
sprite_component_->setSourceRect(current_frame.source_rect);
// 检查非循环动画是否已结束
if (!current_animation_->isLooping() && animation_timer_ >= current_animation_->getTotalDuration()) {
is_playing_ = false;
animation_timer_ = current_animation_->getTotalDuration(); // 将时间限制在结束点
if (is_one_shot_removal_) { // 如果 is_one_shot_removal_ 为 true,则删除整个 GameObject
owner_->setNeedRemove(true);
}
}
}
void AnimationComponent::addAnimation(std::unique_ptr<engine::render::Animation> animation) {
if (!animation) return;
std::string name = animation->getName(); // 获取名称
animations_[name] = std::move(animation);
spdlog::debug("已将动画 '{}' 添加到 GameObject '{}'", name, owner_ ? owner_->getName() : "未知");
}
void AnimationComponent::playAnimation(const std::string& name) {
auto it = animations_.find(name);
if (it == animations_.end() || !it->second) {
spdlog::warn("未找到 GameObject '{}' 的动画 '{}'", name, owner_ ? owner_->getName() : "未知");
return;
}
// 如果已经在播放相同的动画,不重新开始(注释这一段则重新开始播放)
if (current_animation_ == it->second.get() && is_playing_) {
return;
}
current_animation_ = it->second.get();
animation_timer_ = 0.0f;
is_playing_ = true;
// 立即将精灵更新到第一帧
if (sprite_component_ && !current_animation_->isEmpty()) {
const auto& first_frame = current_animation_->getFrame(0.0f);
sprite_component_->setSourceRect(first_frame.source_rect);
spdlog::debug("GameObject '{}' 播放动画 '{}'", owner_ ? owner_->getName() : "未知", name);
}
}
std::string AnimationComponent::getCurrentAnimationName() const {
if (current_animation_) {
return current_animation_->getName();
}
return "";
}
bool AnimationComponent::isAnimationFinished() const {
// 如果没有当前动画(说明从未调用过playAnimation),或者当前动画是循环的,则返回 false
if (!current_animation_ || current_animation_->isLooping()) {
return false;
}
return animation_timer_ >= current_animation_->getTotalDuration();
}
} // namespace engine::component
@@ -0,0 +1,61 @@
#pragma once
#include "./component.h"
#include <string>
#include <unordered_map>
#include <memory>
namespace engine::render {
class Animation;
}
namespace engine::component {
class SpriteComponent;
}
namespace engine::component {
/**
* @brief GameObject的动画组件。
*
* 持有一组Animation对象并控制其播放,
* 根据当前帧更新关联的SpriteComponent。
*/
class AnimationComponent : public Component {
friend class engine::object::GameObject;
private:
/// @brief 动画名称到Animation对象的映射。
std::unordered_map<std::string, std::unique_ptr<engine::render::Animation>> animations_;
SpriteComponent* sprite_component_ = nullptr; ///< @brief 指向必需的SpriteComponent的指针
engine::render::Animation* current_animation_ = nullptr; ///< @brief 指向当前播放动画的原始指针
float animation_timer_ = 0.0f; ///< @brief 动画播放中的计时器
bool is_playing_ = false; ///< @brief 当前是否有动画正在播放
bool is_one_shot_removal_ = false; ///< @brief 是否在动画结束后删除整个GameObject
public:
AnimationComponent() = default;
~AnimationComponent() override;
// 删除复制/移动操作
AnimationComponent(const AnimationComponent&) = delete;
AnimationComponent& operator=(const AnimationComponent&) = delete;
AnimationComponent(AnimationComponent&&) = delete;
AnimationComponent& operator=(AnimationComponent&&) = delete;
void addAnimation(std::unique_ptr<engine::render::Animation> animation); ///< @brief 向 animations_ map容器中添加一个动画。
void playAnimation(const std::string& name); ///< @brief 播放指定名称的动画。
void stopAnimation() { is_playing_ = false; } ///< @brief 停止当前动画播放。
// --- Getters and Setters ---
std::string getCurrentAnimationName() const;
bool isPlaying() const { return is_playing_; }
bool isAnimationFinished() const;
bool isOneShotRemoval() const { return is_one_shot_removal_; }
void setOneShotRemoval(bool is_one_shot_removal) { is_one_shot_removal_ = is_one_shot_removal; }
protected:
// 核心循环方法
void init() override;
void update(float, engine::core::Context&) override;
};
} // namespace engine::component