318 lines
9.2 KiB
C++
318 lines
9.2 KiB
C++
#include "Animation.h"
|
|
#include "Asset/AssetManager.h"
|
|
#include "Asset/Asset_Script.h"
|
|
#include "Tool/Math.h"
|
|
#include "EngineFrame/Base/Actor.h"
|
|
#include "EngineCore/Game.h"
|
|
|
|
Animation::Animation()
|
|
{
|
|
}
|
|
|
|
Animation::Animation(std::string AniPath)
|
|
{
|
|
Init(AniPath);
|
|
}
|
|
|
|
Animation::Animation(std::string AniPath, std::function<std::string(std::string, Animation::ReplaceData)> 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<Sprite> 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(Vec2(0.5f, 0.5f));
|
|
SpriteObj->SetPos(Vec2(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<Animation> 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()
|
|
{
|
|
Actor::Render();
|
|
}
|
|
|
|
void Animation::OnAdded(BaseNode *node)
|
|
{
|
|
Actor::OnAdded(node);
|
|
FlushFrame(0);
|
|
}
|
|
|
|
void Animation::Clear()
|
|
{
|
|
}
|
|
|
|
void Animation::SetVisible(bool visible)
|
|
{
|
|
// 设置启用的时候要更新一下当前帧的渲染信息 避免因为延迟造成的坐标闪烁
|
|
if (visible)
|
|
{
|
|
CurrentFrame->CalcRenderInfoLogic();
|
|
CurrentFrame->CalcRenderInfo();
|
|
}
|
|
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<std::string, AniScriptParser::AniFlag> FlagBuf = FrameInfo.Flag;
|
|
// 关键帧
|
|
if (FlagBuf.count("SET_FLAG"))
|
|
{
|
|
if (ChangeFrameCallback)
|
|
ChangeFrameCallback(std::get<int>(FlagBuf["SET_FLAG"]));
|
|
}
|
|
// 播放音效
|
|
if (FlagBuf.count("PLAY_SOUND"))
|
|
{
|
|
// TODO 还没有做音效的播放
|
|
}
|
|
// 缩放
|
|
if (FlagBuf.count("IMAGE_RATE"))
|
|
{
|
|
Vec2 Rate = std::get<Vec2>(FlagBuf["IMAGE_RATE"]);
|
|
CurrentFrame->SetScale(Vec2{Rate.x, Rate.y});
|
|
}
|
|
// 线性减淡
|
|
if (FlagBuf.count("GRAPHIC_EFFECT_LINEARDODGE"))
|
|
{
|
|
CurrentFrame->SetBlendMode(LINEARDODGE);
|
|
}
|
|
// 旋转
|
|
if (FlagBuf.count("IMAGE_ROTATE"))
|
|
{
|
|
CurrentFrame->SetAnchor(Vec2{0.5f, 0.5f});
|
|
CurrentFrame->SetRotation(std::get<float>(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());
|
|
}
|
|
|
|
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<int> OldRgbaData = {255, 255, 255, 250};
|
|
std::vector<int> NewRgbaData = {255, 255, 255, 250};
|
|
if (OldData.Flag.count("RGBA"))
|
|
OldRgbaData = std::get<std::vector<int>>(OldData.Flag["RGBA"]);
|
|
if (NewData.Flag.count("RGBA"))
|
|
NewRgbaData = std::get<std::vector<int>>(NewData.Flag["RGBA"]);
|
|
std::vector<int> 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 染色 和 透明度还没弄
|
|
}
|
|
// 坐标
|
|
{
|
|
Vec2 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);
|
|
}
|
|
// 缩放
|
|
{
|
|
Vec2 OldRateData = {1.0f, 1.0f};
|
|
Vec2 NewRateData = {1.0f, 1.0f};
|
|
if (OldData.Flag.count("IMAGE_RATE"))
|
|
{
|
|
OldRateData = std::get<Vec2>(OldData.Flag["IMAGE_RATE"]);
|
|
}
|
|
if (NewData.Flag.count("IMAGE_RATE"))
|
|
{
|
|
NewRateData = std::get<Vec2>(NewData.Flag["IMAGE_RATE"]);
|
|
}
|
|
Vec2 RateData = {
|
|
OldRateData.x + (NewRateData.x - OldRateData.x) * InterRate,
|
|
OldRateData.y + (NewRateData.y - OldRateData.y) * InterRate};
|
|
CurrentFrame->SetAnchor(Vec2{0.5f, 0.5f});
|
|
CurrentFrame->SetScale(RateData);
|
|
}
|
|
// 旋转
|
|
{
|
|
float OldAngleData = 0.0;
|
|
float NewAngleData = 0.0;
|
|
if (OldData.Flag.count("IMAGE_ROTATE"))
|
|
{
|
|
OldAngleData = std::get<float>(OldData.Flag["IMAGE_ROTATE"]);
|
|
}
|
|
if (NewData.Flag.count("IMAGE_ROTATE"))
|
|
{
|
|
NewAngleData = std::get<float>(NewData.Flag["IMAGE_ROTATE"]);
|
|
}
|
|
CurrentFrame->SetRotation(OldAngleData + (NewAngleData - OldAngleData) * InterRate);
|
|
}
|
|
}
|