#include "Animation.h" #include "Asset/AssetManager.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) { this->AdditionalOptions = AdditionalOptions; Init(AniPath); } Animation::~Animation() { } void Animation::Init(std::string AniPath) { // 标记该组件需要渲染和更新 addTag(Tag::RENDER); addTag(Tag::UPDATE); addTag(Tag::TRANSFORM); 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); } SpriteObj = new Sprite(FrameObj.Img_Path, FrameObj.Img_Index); SpriteObj->SetPos(FrameObj.Img_Pos); } else SpriteObj = new Sprite(); SpriteArr.push_back(SpriteObj); } // 初始化完毕 如果是第一次初始化 而非重新构造 设置大小为第0帧大小否则天空 地板等依靠大小的初始化会有问题 if (CurrentIndexT == 0) SetSize(SpriteArr[0]->GetSize()); // 记录总帧数 TotalFrameIndex = FrameArr.size(); // TODO 染色 } void Animation::HandleEvents(SDL_Event *e) { } void Animation::Update(float deltaTime) { Component::Update(deltaTime); // 可用性检查 if (IsUsability) { int dt = (int)(deltaTime * 1000); // 累加当前帧时间 CurrentIndexT += dt; // 插值模式判断 InterpolationLogic(); // 当前帧时间 超过 当前帧延迟就需要切换帧了 if (CurrentIndexT >= NextFrameDelay) { CurrentIndexT = 0; // 如果当前帧小于总帧数就切换 if (CurrentFrameIndex < (TotalFrameIndex - 1)) { FlushFrame(CurrentFrameIndex + 1); } // 说明播放完毕了 else { // 如果有循环 if (AnimationFlag.count("LOOP")) { FlushFrame(0); } // 没有循环触发状态机回调 else { // 将不再可用 IsUsability = false; if (EndCallback) EndCallback(); } } } } } void Animation::Render(float deltaTime) { if (IsUsability) { if (CurrentFrame) { CurrentFrame->Render(deltaTime); } } } void Animation::OnAdded(Actor *actor) { Component::OnAdded(actor); FlushFrame(0); } void Animation::Clear() { } void Animation::SetIterationPos(VecPos pos) { Component::SetIterationPos(pos); if (CurrentFrame) CurrentFrame->SetIterationPos(this->Pos + this->IterationPos); } void Animation::FlushFrame(int Index) { // 同步当前帧 CurrentFrameIndex = Index; // 当前帧更换为本帧 CurrentFrame = SpriteArr[CurrentFrameIndex]; // 设置精灵帧的迭代坐标为自己的坐标和自己的迭代坐标 CurrentFrame->SetIterationPos(this->Pos + this->IterationPos); // 如果是整体染色 则直接使用染色帧 // 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"]); VecSize Size = CurrentFrame->GetSize(); CurrentFrame->SetSize(VecSize{int(Size.width * Rate.x), (int)(Size.width * Rate.y)}); } // 线性减淡 if (FlagBuf.count("GRAPHIC_EFFECT_LINEARDODGE")) { CurrentFrame->SetBlendMode(SDL_BLENDMODE_ADD); } // 旋转 if (FlagBuf.count("IMAGE_ROTATE")) { CurrentFrame->SetAnchor(VecFPos{0.5, 0.5}); CurrentFrame->SetAngle(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 染色 和 透明度还没弄 } // 坐标 { VecPos PosData = { (int)(OldData.Img_Pos.x + (NewData.Img_Pos.x - OldData.Img_Pos.x) * InterRate), (int)(OldData.Img_Pos.y + (NewData.Img_Pos.y - OldData.Img_Pos.y) * InterRate)}; SetPos(PosData); CurrentFrame->SetIterationPos(this->Pos + this->IterationPos); } // 缩放 { VecFPos OldRateData = {1.0, 1.0}; VecFPos NewRateData = {1.0, 1.0}; 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"]); } VecSize ScaleData = { (int)(CurrentFrame->GetSize().width * (OldRateData.x + (NewRateData.x - OldRateData.x) * InterRate)), (int)(CurrentFrame->GetSize().height * (OldRateData.y + (NewRateData.y - OldRateData.y) * InterRate))}; VecSize Size = CurrentFrame->GetSize(); CurrentFrame->SetSize(VecSize{int(Size.width * ScaleData.width), (int)(Size.height * ScaleData.height)}); } // 旋转 { 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->SetAngle(OldAngleData + (NewAngleData - OldAngleData) * InterRate); } } void Animation::SetSize(VecSize size) { this->Size = size; } void Animation::SetPos(VecPos pos) { this->Pos = pos; if (CurrentFrame) CurrentFrame->SetIterationPos(this->Pos + this->IterationPos); } VecPos Animation::GetPos() { return this->Pos; } VecSize Animation::GetSize() { return this->Size; }