#pragma once #include "character/CharacterDataLoader.h" #include "character/CharacterEquipmentManager.h" #include #include #include #include #include #include #include #include #include namespace frostbite2D { class CharacterObject; class CharacterAnimation : public Actor { public: using ActionAnimationList = std::map>>; using ActionFrameFlagCallback = std::function; using ActionEndCallback = std::function; struct CompositeFrameInfo { bool valid = false; Rect localBounds; Vec2 originInTexture = Vec2::Zero(); Vec2 groundAnchorInTexture = Vec2::Zero(); int width = 1; int height = 1; }; bool Init(CharacterObject* parent, const character::CharacterConfig& config, const CharacterEquipmentManager& equipmentManager); void Update(float deltaTime) override; void Render() override; bool SetAction(const std::string& actionName); void SetDirection(int direction); const std::string& GetCurrentAction() const { return currentActionTag_; } bool HasAction(const std::string& actionName) const { return actionAnimations_.count(actionName) > 0; } std::string DescribeAvailableActions() const; bool IsCurrentActionFinished() const; int GetCurrentFrameIndex() const; int GetCurrentFrameCount() const; float GetCurrentNormalizedProgress() const; animation::AniFrame GetCurrentFrameInfo() const; void SetActionFrameFlagCallback(ActionFrameFlagCallback callback); void SetActionEndCallback(ActionEndCallback callback); bool EnsureCompositeTextureReady(); bool HasCompositeTexture() const; Ptr GetCompositeTexture() const; Vec2 GetCompositeTextureSize() const; Vec2 GetCompositeOriginInTexture() const; Vec2 GetCompositeGroundAnchorInTexture() const; uint64 GetCompositeVersion() const { return compositeVersion_; } private: static std::string FormatImgPath(std::string path, Animation::ReplaceData data); Animation* GetPrimaryAnimation(const std::string& actionName) const; Animation* GetCurrentPrimaryAnimation() const; void RefreshRuntimeCallbacks(); bool shouldSkipMissingAnimation(const std::string& aniPath); void BuildCompositeActionFrames(); CompositeFrameInfo ComputeCompositeFrameInfo(const std::vector>& animations, int direction) const; CompositeFrameInfo GetCurrentCompositeFrameInfo() const; uint64 CaptureCurrentRenderSignature() const; void MarkCompositeDirty(); void UpdateCompositeCamera(); void RefreshCompositeTextureIfNeeded(); void RenderCurrentActionToCompositeCanvas(); void CreateAnimationBySlot(const std::string& actionName, const std::string& slotName, const std::string& actionPath, const character::CharacterConfig& config, const CharacterEquipmentManager& equipmentManager); CharacterObject* parent_ = nullptr; ActionAnimationList actionAnimations_; std::string currentActionTag_; int direction_ = 1; ActionFrameFlagCallback actionFrameFlagCallback_; ActionEndCallback actionEndCallback_; std::unordered_set missingAnimationPaths_; size_t skippedMissingAnimationCount_ = 0; RefPtr compositeCanvas_ = nullptr; std::map compositeFrameInfoByAction_; bool compositeDirty_ = true; uint64 compositeVersion_ = 0; uint64 lastCompositeSignature_ = 0; }; } // namespace frostbite2D