#include "Animation.h" #include "Asset/AssetManager.h" #include "Asset/Asset_Script.h" #include "Tool/Math.h" #include "EngineFrame/Actor/Actor.h" Animation::Animation() { } Animation::Animation(std::string AniPath) { Init(AniPath); } Animation::Animation(std::string AniPath, std::function AdditionalOptions, Animation::ReplaceData data) { this->AdditionalOptions = AdditionalOptions; this->AdditionalOptionsData = data; Init(AniPath); } Animation::~Animation() { } void Animation::Init(std::string AniPath) { Actor::Init(); AniScriptParser::AniInfo Info = AssetManager::GetInstance().StructAniInfo(AniPath); this->AniPath = AniPath; this->AnimationFlag = Info.Flag; this->FrameArr = Info.Frame; for (size_t i = 0; i < this->FrameArr.size(); i++) { AniScriptParser::AniFrame FrameObj = this->FrameArr[i]; RefPtr SpriteObj = nullptr; if (!FrameObj.Img_Path.empty()) { if (AdditionalOptions) { FrameObj.Img_Path = AdditionalOptions(FrameObj.Img_Path, this->AdditionalOptionsData); } SpriteObj = new Sprite(FrameObj.Img_Path, FrameObj.Img_Index); SpriteObj->SetAnchor(VecFPos(0.5f, 0.5f)); SpriteObj->SetPos(VecFPos(FrameObj.Img_Pos.x, FrameObj.Img_Pos.y)); SpriteObj->SetVisible(false); } else { SpriteObj = new Sprite(); SpriteObj->SetVisible(false); SDL_Log("Animation::Init() SpriteObj is nullptr"); } SpriteArr.push_back(SpriteObj); AddChild(SpriteObj); } // 初始化完毕 如果是第一次初始化 而非重新构造 设置大小为第0帧大小否则天空 地板等依靠大小的初始化会有问题 if (CurrentIndexT == 0) SetSize(SpriteArr[0]->GetSize()); // 记录总帧数 TotalFrameIndex = FrameArr.size(); // TODO 染色 // 判断是否有Als if (Asset_Script::GetInstance().GetFileInfo(AniPath + ".als")) { AniScriptParser::AlsInfo Info = AssetManager::GetInstance().StructAlsInfo(AniPath + ".als"); if (Info.AniList.size() > 0) { std::string Dir = AniPath.substr(0, AniPath.find_last_of("/") + 1); for (auto &Ani : Info.AniList) { RefPtr AlsAniObj = new Animation(Dir + Ani.second.path); AlsAniObj->SetRenderZOrder(Ani.second.layer[1]); AddChild(AlsAniObj); } } } FlushFrame(0); } void Animation::HandleEvents(SDL_Event *e) { } void Animation::Update(float deltaTime) { // 可用性检查 if (IsUsability && Visible) { float dt_ms = deltaTime * 1000.0f; // 累加当前帧时间 CurrentIndexT += dt_ms; // 插值模式判断 InterpolationLogic(); // 循环处理:只要当前时间超过帧延迟,就切换帧(支持一次跳过多帧) while (CurrentIndexT >= NextFrameDelay) { CurrentIndexT -= NextFrameDelay; // 如果当前帧小于总帧数就切换 if (CurrentFrameIndex < (TotalFrameIndex - 1)) { FlushFrame(CurrentFrameIndex + 1); } // 说明播放完毕了 else { // 如果有循环 if (AnimationFlag.count("LOOP")) { FlushFrame(0); } // 没有循环触发状态机回调 else { // 将不再可用 IsUsability = false; if (EndCallback) EndCallback(); break; } } } Actor::Update(deltaTime); } } void Animation::Render() { if (!Visible) return; Actor::Render(); } void Animation::OnAdded(BaseNode *node) { Actor::OnAdded(node); FlushFrame(0); } void Animation::Clear() { } void Animation::SetVisible(bool visible) { // 设置启用的时候要更新一下当前帧的渲染信息 避免因为延迟造成的坐标闪烁 if (visible) { CurrentFrame->CalcRenderInfoLogic(); } Actor::SetVisible(visible); } void Animation::FlushFrame(int Index) { // 关闭旧帧显示 if (CurrentFrame) CurrentFrame->SetVisible(false); // 同步当前帧编号 CurrentFrameIndex = Index; // 当前帧更换为本帧 CurrentFrame = SpriteArr[CurrentFrameIndex]; // 开启新帧显示 CurrentFrame->SetVisible(true); // 如果是整体染色 则直接使用染色帧 // if (DyeAllFlag) CurrentFrame = DyeFrameList[CurrentFrameIndex]; AniScriptParser::AniFrame FrameInfo = FrameArr[CurrentFrameIndex]; // 设置下帧延迟 NextFrameDelay = FrameInfo.Delay; std::unordered_map FlagBuf = FrameInfo.Flag; // 关键帧 if (FlagBuf.count("SET_FLAG")) { if (ChangeFrameCallback) ChangeFrameCallback(std::get(FlagBuf["SET_FLAG"])); } // 播放音效 if (FlagBuf.count("PLAY_SOUND")) { // TODO 还没有做音效的播放 } // 缩放 if (FlagBuf.count("IMAGE_RATE")) { VecFPos Rate = std::get(FlagBuf["IMAGE_RATE"]); CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f}); CurrentFrame->SetScale(VecFPos{Rate.x, Rate.y}); } // 线性减淡 if (FlagBuf.count("GRAPHIC_EFFECT_LINEARDODGE")) { CurrentFrame->SetBlendMode(SDL_BLENDMODE_ADD); } // 旋转 if (FlagBuf.count("IMAGE_ROTATE")) { CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f}); CurrentFrame->SetRotation(std::get(FlagBuf["IMAGE_ROTATE"])); } // 染色 // if (!DyeAllFlag) // 插值模式 if (FlagBuf.count("INTERPOLATION")) { // 初始化插值数据 if (InterpolationFlag.size() == 0) { // 旧插值数据 InterpolationFlag.push_back(FrameArr[CurrentFrameIndex]); // 新插值数据 InterpolationFlag.push_back(FrameArr[CurrentFrameIndex + 1]); } } else { if (InterpolationFlag.size() > 0) { InterpolationFlag.clear(); } } // 如果有描边 if (IsOutline) { } // Ani的大小同步为精灵帧对象的大小 SetSize(CurrentFrame->GetSize()); // 裁切 //TODO } void Animation::Reset() { IsUsability = true; CurrentIndexT = 0; FlushFrame(0); } AniScriptParser::AniFrame Animation::GetCurrentFrameInfo() { return FrameArr[CurrentFrameIndex]; } void Animation::SetFrameIndex(int Index) { FlushFrame(Index); CurrentIndexT = 0; } void Animation::InterpolationLogic() { if (InterpolationFlag.size() == 0) return; // 插值倍率 float InterRate = Math::getUniformVelocity(0, 100, CurrentIndexT, NextFrameDelay) / 100.0f; AniScriptParser::AniFrame OldData = InterpolationFlag[0]; AniScriptParser::AniFrame NewData = InterpolationFlag[1]; // RGBA插值 { std::vector OldRgbaData = {255, 255, 255, 250}; std::vector NewRgbaData = {255, 255, 255, 250}; if (OldData.Flag.count("RGBA")) OldRgbaData = std::get>(OldData.Flag["RGBA"]); if (NewData.Flag.count("RGBA")) NewRgbaData = std::get>(NewData.Flag["RGBA"]); std::vector RgbaData = { (int)(OldRgbaData[0] + (NewRgbaData[0] - OldRgbaData[0]) * InterRate), (int)(OldRgbaData[1] + (NewRgbaData[1] - OldRgbaData[1]) * InterRate), (int)(OldRgbaData[2] + (NewRgbaData[2] - OldRgbaData[2]) * InterRate), (int)(OldRgbaData[3] + (NewRgbaData[3] - OldRgbaData[3]) * InterRate)}; // TODO 染色 和 透明度还没弄 } // 坐标 { VecFPos PosData = { (OldData.Img_Pos.x + (NewData.Img_Pos.x - OldData.Img_Pos.x) * InterRate), (OldData.Img_Pos.y + (NewData.Img_Pos.y - OldData.Img_Pos.y) * InterRate)}; CurrentFrame->SetPos(PosData); } // 缩放 { VecFPos OldRateData = {1.0f, 1.0f}; VecFPos NewRateData = {1.0f, 1.0f}; if (OldData.Flag.count("IMAGE_RATE")) { OldRateData = std::get(OldData.Flag["IMAGE_RATE"]); } if (NewData.Flag.count("IMAGE_RATE")) { NewRateData = std::get(NewData.Flag["IMAGE_RATE"]); } VecFPos RateData = { OldRateData.x + (NewRateData.x - OldRateData.x) * InterRate, OldRateData.y + (NewRateData.y - OldRateData.y) * InterRate}; CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f}); CurrentFrame->SetScale(RateData); } // 旋转 { float OldAngleData = 0.0; float NewAngleData = 0.0; if (OldData.Flag.count("IMAGE_ROTATE")) { OldAngleData = std::get(OldData.Flag["IMAGE_ROTATE"]); } if (NewData.Flag.count("IMAGE_ROTATE")) { NewAngleData = std::get(NewData.Flag["IMAGE_ROTATE"]); } CurrentFrame->SetRotation(OldAngleData + (NewAngleData - OldAngleData) * InterRate); } }