建档
This commit is contained in:
309
source/EngineFrame/Component/Animation.cpp
Normal file
309
source/EngineFrame/Component/Animation.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#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<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(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<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()
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
Actor::Render();
|
||||
}
|
||||
|
||||
void Animation::OnAdded(BaseNode *node)
|
||||
{
|
||||
Actor::OnAdded(node);
|
||||
FlushFrame(0);
|
||||
}
|
||||
|
||||
void Animation::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
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"))
|
||||
{
|
||||
VecFPos Rate = std::get<VecFPos>(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<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());
|
||||
// 裁切 //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<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 染色 和 透明度还没弄
|
||||
}
|
||||
// 坐标
|
||||
{
|
||||
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<VecFPos>(OldData.Flag["IMAGE_RATE"]);
|
||||
}
|
||||
if (NewData.Flag.count("IMAGE_RATE"))
|
||||
{
|
||||
NewRateData = std::get<VecFPos>(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<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);
|
||||
}
|
||||
}
|
||||
95
source/EngineFrame/Component/Animation.h
Normal file
95
source/EngineFrame/Component/Animation.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
#include "EngineFrame/Component/Sprite.h"
|
||||
#include "Asset/AnimationStruct.h"
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
class Animation : public Actor
|
||||
{
|
||||
|
||||
public:
|
||||
struct ReplaceData
|
||||
{
|
||||
int Param1;
|
||||
int Param2;
|
||||
ReplaceData() : Param1(0), Param2(0) {}
|
||||
ReplaceData(int _Param1, int _Param2) : Param1(_Param1), Param2(_Param2) {}
|
||||
};
|
||||
|
||||
public:
|
||||
Animation(/* args */);
|
||||
Animation(std::string AniPath);
|
||||
Animation(std::string AniPath, std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions, Animation::ReplaceData);
|
||||
~Animation();
|
||||
|
||||
void Init(std::string AniPath);
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
void Update(float deltaTime) override;
|
||||
void Render() override;
|
||||
void OnAdded(BaseNode *node) override;
|
||||
void Clear() override;
|
||||
|
||||
public:
|
||||
void FlushFrame(int Index);
|
||||
void Reset();
|
||||
AniScriptParser::AniFrame GetCurrentFrameInfo();
|
||||
void SetFrameIndex(int Index);
|
||||
void InterpolationLogic();
|
||||
// TODO SetOutline
|
||||
// TODO SetDye
|
||||
// TODO SetCrop
|
||||
|
||||
public:
|
||||
// Ani是否可用
|
||||
bool IsUsability = true;
|
||||
// 当前帧数
|
||||
int CurrentFrameIndex = 0;
|
||||
// 总帧数
|
||||
int TotalFrameIndex = 0;
|
||||
// 当前帧时间
|
||||
float CurrentIndexT = 0;
|
||||
// 当前帧
|
||||
RefPtr<Sprite> CurrentFrame = nullptr;
|
||||
// 下帧延迟
|
||||
float NextFrameDelay = 9999999;
|
||||
// 染色Flag
|
||||
bool DyeingFlag = false;
|
||||
// 插值模式
|
||||
std::vector<AniScriptParser::AniFrame> InterpolationFlag;
|
||||
// 关键帧回调
|
||||
std::function<void(int)> ChangeFrameCallback;
|
||||
// 结束回调
|
||||
std::function<void()> EndCallback;
|
||||
// Ani的标签
|
||||
std::unordered_map<std::string, AniScriptParser::AniFlag> AnimationFlag;
|
||||
// 帧对象数组
|
||||
std::vector<AniScriptParser::AniFrame> FrameArr;
|
||||
// 图片精灵帧对象
|
||||
std::vector<RefPtr<Sprite>> SpriteArr;
|
||||
// Ani类型
|
||||
std::string Type = "normal";
|
||||
// Ani路径
|
||||
std::string AniPath;
|
||||
// 是否描边
|
||||
bool IsOutline = false;
|
||||
// // 描边颜色
|
||||
// OutlineColor = null;
|
||||
// // 描边对象List
|
||||
// OutlineList = null;
|
||||
// // 当前描边对象
|
||||
// CurrentOutline = null;
|
||||
// // 染色颜色
|
||||
// DyeColor = null;
|
||||
// // 染色帧List
|
||||
// DyeFrameList = null;
|
||||
// // 整体染色
|
||||
// DyeAllFlag = false;
|
||||
// // 裁切数据
|
||||
// CropRect = null;
|
||||
|
||||
// 附加选项
|
||||
std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions;
|
||||
Animation::ReplaceData AdditionalOptionsData;
|
||||
};
|
||||
7
source/EngineFrame/Component/Component.cpp
Normal file
7
source/EngineFrame/Component/Component.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "Component.h"
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
|
||||
void Component::Init()
|
||||
{
|
||||
addTag(Tag::COMPONENT);
|
||||
}
|
||||
11
source/EngineFrame/Component/Component.h
Normal file
11
source/EngineFrame/Component/Component.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "EngineFrame/Base/BaseNode.h"
|
||||
|
||||
#include <SDL.h>
|
||||
class Actor;
|
||||
class Component : public BaseNode
|
||||
{
|
||||
|
||||
public:
|
||||
void Init() override;
|
||||
};
|
||||
86
source/EngineFrame/Component/RenderBase.cpp
Normal file
86
source/EngineFrame/Component/RenderBase.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
#include "RenderBase.h"
|
||||
#include "EngineFrame/Actor/Actor.h"
|
||||
|
||||
RenderBase::RenderBase()
|
||||
{
|
||||
}
|
||||
|
||||
RenderBase::~RenderBase()
|
||||
{
|
||||
}
|
||||
|
||||
void RenderBase::CalcRenderInfo()
|
||||
{
|
||||
this->CalcRenderInfoFlag = true;
|
||||
}
|
||||
|
||||
void RenderBase::Init()
|
||||
{
|
||||
Component::Init();
|
||||
// 标记该组件需要渲染和更新
|
||||
addTag(Tag::RENDER);
|
||||
addTag(Tag::UPDATE);
|
||||
addTag(Tag::TRANSFORM);
|
||||
// 计算渲染信息
|
||||
CalcRenderInfo();
|
||||
}
|
||||
|
||||
void RenderBase::Update(float deltaTime)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
Component::Update(deltaTime);
|
||||
|
||||
}
|
||||
|
||||
void RenderBase::Render()
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
Component::Render();
|
||||
}
|
||||
|
||||
void RenderBase::SetIterationPos(VecFPos pos)
|
||||
{
|
||||
Component::SetIterationPos(pos);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetIterationScale(VecFPos scale)
|
||||
{
|
||||
Component::SetIterationScale(scale);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetIterationRotation(float angle)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
Component::SetIterationRotation(angle);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetPos(VecFPos pos)
|
||||
{
|
||||
Component::SetPos(pos);
|
||||
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetScale(VecFPos scale)
|
||||
{
|
||||
Component::SetScale(scale);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetRotation(float angle)
|
||||
{
|
||||
Component::SetRotation(angle);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
|
||||
void RenderBase::SetAnchor(VecFPos anchor)
|
||||
{
|
||||
Component::SetAnchor(anchor);
|
||||
CalcRenderInfo(); // 更新渲染信息
|
||||
}
|
||||
50
source/EngineFrame/Component/RenderBase.h
Normal file
50
source/EngineFrame/Component/RenderBase.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
#include "Tool/TransformT.h"
|
||||
|
||||
class RenderBase : public Component
|
||||
{
|
||||
|
||||
public:
|
||||
struct RenderGuidanceInfo
|
||||
{
|
||||
SDL_Rect rect;
|
||||
float rotation;
|
||||
SDL_RendererFlip flip = SDL_FLIP_NONE;
|
||||
VecPos AnchorPos;
|
||||
bool Visible = true;
|
||||
bool IsInScreen;
|
||||
};
|
||||
|
||||
public:
|
||||
RenderBase(/* args */);
|
||||
~RenderBase();
|
||||
|
||||
public:
|
||||
void Init() override;
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void Render() override;
|
||||
|
||||
public:
|
||||
public:
|
||||
// 设置迭代的坐标
|
||||
void SetIterationPos(VecFPos pos) override;
|
||||
// 设置迭代的缩放
|
||||
void SetIterationScale(VecFPos scale) override;
|
||||
// 设置迭代的旋转角度
|
||||
void SetIterationRotation(float angle) override;
|
||||
|
||||
// 设置坐标
|
||||
void SetPos(VecFPos pos) override;
|
||||
// 设置缩放
|
||||
void SetScale(VecFPos scale) override;
|
||||
// 设置旋转角度
|
||||
void SetRotation(float angle) override;
|
||||
// 设置中心点
|
||||
void SetAnchor(VecFPos anchor) override;
|
||||
|
||||
// 计算渲染信息
|
||||
void CalcRenderInfo() override;
|
||||
};
|
||||
159
source/EngineFrame/Component/Sprite.cpp
Normal file
159
source/EngineFrame/Component/Sprite.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
#include "Sprite.h"
|
||||
#include "EngineCore/Game.h"
|
||||
#include "Text.h"
|
||||
Sprite::Sprite()
|
||||
{
|
||||
}
|
||||
|
||||
Sprite::Sprite(std::string imgPath, int Index)
|
||||
{
|
||||
this->imgPath = imgPath;
|
||||
this->Index = Index;
|
||||
m_texture = new Texture(imgPath, Index);
|
||||
Init();
|
||||
CalcRenderInfoLogic(); // 第一次计算
|
||||
}
|
||||
|
||||
Sprite::Sprite(std::string PngPath)
|
||||
{
|
||||
m_texture = new Texture(PngPath);
|
||||
Init();
|
||||
CalcRenderInfoLogic(); // 第一次计算
|
||||
}
|
||||
|
||||
Sprite::~Sprite()
|
||||
{
|
||||
}
|
||||
|
||||
RefPtr<Texture> Sprite::GetTexture()
|
||||
{
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
void Sprite::SetIterationPos(VecFPos pos)
|
||||
{
|
||||
RenderBase::SetIterationPos(pos);
|
||||
CalcRenderInfo();
|
||||
}
|
||||
|
||||
void Sprite::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Sprite::Update(float deltaTime)
|
||||
{
|
||||
if (CalcRenderInfoFlag && Visible)
|
||||
CalcRenderInfoLogic();
|
||||
}
|
||||
|
||||
void Sprite::CalcRenderInfoLogic()
|
||||
{
|
||||
// 计算缩放因子和翻转状态
|
||||
float scaleX = transformIter.scale.x * transform.scale.x;
|
||||
float scaleY = transformIter.scale.y * transform.scale.y;
|
||||
// X轴和Y轴上是否翻转的标志
|
||||
bool flipX = scaleX < 0;
|
||||
bool flipY = scaleY < 0;
|
||||
|
||||
_RenderGuidanceInfo.flip = SDL_FLIP_NONE;
|
||||
// 更新翻转状态
|
||||
if (flipX)
|
||||
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_HORIZONTAL | _RenderGuidanceInfo.flip);
|
||||
if (flipY)
|
||||
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_VERTICAL | _RenderGuidanceInfo.flip);
|
||||
|
||||
// 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上
|
||||
int texturePosX = flipX ? -(m_texture->TextureSize.width + m_texture->TexturePos.x) + SDL_abs(transform.position.x * 2) : m_texture->TexturePos.x;
|
||||
int texturePosY = flipY ? -(m_texture->TextureSize.height + m_texture->TexturePos.y) + SDL_abs(transform.position.y * 2) : m_texture->TexturePos.y;
|
||||
|
||||
// 先计算Img坐标与精灵坐标合成后的真实坐标
|
||||
int RealPosX = transform.position.x + texturePosX;
|
||||
int RealPosY = transform.position.y + texturePosY;
|
||||
|
||||
// 计算在世界中的位置
|
||||
int baseX = transformIter.position.x + RealPosX;
|
||||
int baseY = transformIter.position.y + RealPosY;
|
||||
|
||||
// 获取当前帧的原始尺寸
|
||||
int frameWidth = m_texture->TextureSize.width;
|
||||
int frameHeight = m_texture->TextureSize.height;
|
||||
|
||||
// 原始锚点偏移(基于帧尺寸)
|
||||
int origAnchorOffsetX = static_cast<int>(frameWidth * Anchor.x);
|
||||
int origAnchorOffsetY = static_cast<int>(frameHeight * Anchor.y);
|
||||
|
||||
// 缩放的绝对值
|
||||
float absScaleX = SDL_abs(scaleX);
|
||||
float absScaleY = SDL_abs(scaleY);
|
||||
// 缩放后的尺寸
|
||||
int scaledWidth = static_cast<int>(frameWidth * absScaleX);
|
||||
int scaledHeight = static_cast<int>(frameHeight * absScaleY);
|
||||
// 缩放后的锚点偏移
|
||||
int scaledAnchorOffsetX = static_cast<int>(origAnchorOffsetX * absScaleX);
|
||||
int scaledAnchorOffsetY = static_cast<int>(origAnchorOffsetY * absScaleY);
|
||||
|
||||
// 计算缩放后的锚点偏移与原锚点偏移的差值
|
||||
int scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
|
||||
int scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;
|
||||
|
||||
// 最终位置计算:世界位置 + 缩放锚点差值 - 缩放后的锚点偏移 + 纹理数据里带的偏移数据 (计算出绘制点的左上角)
|
||||
int Xpos = baseX + scaleOffsetX;
|
||||
int Ypos = baseY + scaleOffsetY;
|
||||
|
||||
// 更新渲染信息
|
||||
_RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
|
||||
_RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
|
||||
|
||||
// 屏幕内检测
|
||||
int screenWidth = Game::GetInstance().Screen_W;
|
||||
int screenHeight = Game::GetInstance().Screen_H;
|
||||
bool isInScreen = (Xpos + scaledWidth >= 0 && Xpos <= screenWidth && Ypos + scaledHeight >= 0 && Ypos <= screenHeight);
|
||||
_RenderGuidanceInfo.IsInScreen = isInScreen;
|
||||
|
||||
this->Size = {scaledWidth, scaledHeight};
|
||||
_RenderGuidanceInfo.rotation = transformIter.rotation + transform.rotation;
|
||||
|
||||
CalcRenderInfoFlag = false;
|
||||
}
|
||||
|
||||
void Sprite::Render()
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
if (!m_texture)
|
||||
return;
|
||||
|
||||
if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
|
||||
{
|
||||
if (_RenderGuidanceInfo.rotation != 0.f || _RenderGuidanceInfo.flip != SDL_FLIP_NONE)
|
||||
{
|
||||
SDL_Point AnchorPos = _RenderGuidanceInfo.AnchorPos;
|
||||
SDL_RenderCopyEx(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_RenderCopy(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect);
|
||||
// // 设置绘制颜色
|
||||
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, 128);
|
||||
// // 绘制填充矩形
|
||||
// SDL_RenderFillRect(renderer, &_RenderGuidanceInfo.rect);
|
||||
}
|
||||
Game::GetInstance().RenderCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Sprite::SetBlendMode(SDL_BlendMode blendMode)
|
||||
{
|
||||
if (GetBlendMode() != blendMode)
|
||||
m_texture->SetBlendMode(blendMode);
|
||||
}
|
||||
|
||||
SDL_BlendMode Sprite::GetBlendMode()
|
||||
{
|
||||
return m_texture->GetBlendMode();
|
||||
}
|
||||
77
source/EngineFrame/Component/Sprite.h
Normal file
77
source/EngineFrame/Component/Sprite.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "Asset/Asset_ImagePack.h"
|
||||
#include "EngineFrame/Component/RenderBase.h"
|
||||
#include "EngineFrame/Render/Texture.h"
|
||||
|
||||
class Game;
|
||||
/**
|
||||
* @brief Sprite类,继承自Component类,用于表示游戏中的精灵组件
|
||||
*/
|
||||
class Sprite : public RenderBase
|
||||
{
|
||||
protected:
|
||||
/* data */
|
||||
RefPtr<Texture> m_texture = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Sprite类的默认构造函数
|
||||
*/
|
||||
Sprite(/* args */);
|
||||
/**
|
||||
* @brief Sprite类的带参数构造函数
|
||||
* @param imgPath 纹理图片路径
|
||||
* @param Index 索引值
|
||||
*/
|
||||
Sprite(std::string imgPath, int Index);
|
||||
/**
|
||||
* @brief Sprite类的带参数构造函数
|
||||
* @param imgPath 纹理图片文件路径
|
||||
*/
|
||||
Sprite(std::string PngPath);
|
||||
/**
|
||||
* @brief Sprite类的析构函数
|
||||
*/
|
||||
~Sprite();
|
||||
/**
|
||||
* @brief 处理事件
|
||||
* @param e SDL事件指针
|
||||
*/
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
/**
|
||||
* @brief 更新组件状态
|
||||
* @param deltaTime 时间增量
|
||||
*/
|
||||
void Update(float deltaTime) override;
|
||||
/**
|
||||
* @brief 渲染组件
|
||||
* @param deltaTime 时间增量
|
||||
*/
|
||||
void Render() override;
|
||||
/**
|
||||
* @brief 清理组件资源
|
||||
*/
|
||||
void Clear() override;
|
||||
|
||||
/**
|
||||
* @brief 获取纹理
|
||||
* @return SDL_Texture* 纹理指针
|
||||
*/
|
||||
RefPtr<Texture> GetTexture();
|
||||
|
||||
void SetIterationPos(VecFPos pos) override;
|
||||
|
||||
public:
|
||||
RenderGuidanceInfo _RenderGuidanceInfo;
|
||||
std::string imgPath;
|
||||
int Index;
|
||||
|
||||
public:
|
||||
// 计算渲染信息
|
||||
void CalcRenderInfoLogic();
|
||||
// 设置混合模式
|
||||
void SetBlendMode(SDL_BlendMode blendMode);
|
||||
// 获取混合模式
|
||||
SDL_BlendMode GetBlendMode();
|
||||
};
|
||||
207
source/EngineFrame/Component/Text.cpp
Normal file
207
source/EngineFrame/Component/Text.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include "EngineFrame/Component/Text.h"
|
||||
#include "Text.h"
|
||||
#include "EngineCore/Game.h"
|
||||
Text::Text()
|
||||
{
|
||||
}
|
||||
|
||||
Text::Text(std::string Str, TTF_Font *font, SDL_Color color)
|
||||
{
|
||||
m_text = Str;
|
||||
m_font = font;
|
||||
m_text_color = color;
|
||||
Init(Str, font, color);
|
||||
}
|
||||
|
||||
Text::Text(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize)
|
||||
{
|
||||
m_text = Str;
|
||||
m_font = font;
|
||||
m_text_color = textColor;
|
||||
m_stroke_color = strokeColor;
|
||||
m_stroke_size = strokeSize;
|
||||
Init(Str, font, textColor, strokeColor, strokeSize);
|
||||
}
|
||||
|
||||
Text::~Text()
|
||||
{
|
||||
}
|
||||
|
||||
void Text::Init(std::string Str, TTF_Font *font, SDL_Color color)
|
||||
{
|
||||
// 标记该组件需要渲染和更新
|
||||
addTag(Tag::RENDER);
|
||||
addTag(Tag::UPDATE);
|
||||
|
||||
// TTF_SetFontOutline(font, 1);
|
||||
// 先渲染为表面
|
||||
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), color);
|
||||
if (!textSurface)
|
||||
{
|
||||
SDL_LogError(0, "文字渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||||
}
|
||||
// 再将表面转换为纹理
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
m_texture = SDL_CreateTextureFromSurface(renderer, textSurface);
|
||||
if (!m_texture)
|
||||
{
|
||||
SDL_LogError(0, "表面转换为纹理失败!SDL_Error:%s", SDL_GetError());
|
||||
}
|
||||
// 设置纹理过滤模式为最近邻,避免缩放模糊
|
||||
SDL_SetTextureScaleMode(m_texture, SDL_ScaleModeNearest);
|
||||
Size.x = textSurface->w;
|
||||
Size.y = textSurface->h;
|
||||
TextureSize.x = textSurface->w;
|
||||
TextureSize.y = textSurface->h;
|
||||
|
||||
// 释放表面
|
||||
SDL_FreeSurface(textSurface);
|
||||
}
|
||||
|
||||
void Text::Init(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize)
|
||||
{
|
||||
// 先保存原始字体的轮廓设置
|
||||
int originalOutline = TTF_GetFontOutline(font);
|
||||
|
||||
// 设置字体轮廓大小(描边宽度)
|
||||
TTF_SetFontOutline(font, strokeSize);
|
||||
|
||||
// 渲染描边(使用描边颜色)
|
||||
SDL_Surface *strokeSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), strokeColor);
|
||||
if (!strokeSurface)
|
||||
{
|
||||
SDL_LogError(0, "描边渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||||
TTF_SetFontOutline(font, originalOutline); // 恢复原始设置
|
||||
return;
|
||||
}
|
||||
|
||||
// 恢复字体轮廓设置,用于渲染文字本身
|
||||
TTF_SetFontOutline(font, 0);
|
||||
|
||||
// 渲染文字本身(使用文字颜色)
|
||||
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), textColor);
|
||||
if (!textSurface)
|
||||
{
|
||||
SDL_LogError(0, "文字渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||||
SDL_FreeSurface(strokeSurface);
|
||||
TTF_SetFontOutline(font, originalOutline); // 恢复原始设置
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建一个合并描边和文字的表面
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
|
||||
// 计算最终纹理大小(描边会增加额外尺寸)
|
||||
int finalWidth = strokeSurface->w;
|
||||
int finalHeight = strokeSurface->h;
|
||||
|
||||
// 创建一个临时表面用于合并描边和文字
|
||||
SDL_Surface *finalSurface = SDL_CreateRGBSurfaceWithFormat(
|
||||
0, finalWidth, finalHeight, 32, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!finalSurface)
|
||||
{
|
||||
SDL_LogError(0, "创建最终表面失败!SDL_Error:%s", SDL_GetError());
|
||||
SDL_FreeSurface(textSurface);
|
||||
SDL_FreeSurface(strokeSurface);
|
||||
TTF_SetFontOutline(font, originalOutline);
|
||||
return;
|
||||
}
|
||||
|
||||
// 将描边绘制到最终表面
|
||||
SDL_Rect strokeRect = {0, 0, strokeSurface->w, strokeSurface->h};
|
||||
SDL_BlitSurface(strokeSurface, nullptr, finalSurface, &strokeRect);
|
||||
|
||||
// 计算文字在描边中间的位置
|
||||
SDL_Rect textRect = {
|
||||
strokeSize, // X偏移(描边宽度)
|
||||
strokeSize, // Y偏移(描边宽度)
|
||||
textSurface->w,
|
||||
textSurface->h};
|
||||
SDL_BlitSurface(textSurface, nullptr, finalSurface, &textRect);
|
||||
|
||||
// 将合并后的表面转换为纹理
|
||||
m_texture = SDL_CreateTextureFromSurface(renderer, finalSurface);
|
||||
if (!m_texture)
|
||||
{
|
||||
SDL_LogError(0, "表面转换为纹理失败!SDL_Error:%s", SDL_GetError());
|
||||
}
|
||||
|
||||
// 设置尺寸信息
|
||||
Size.x = finalSurface->w;
|
||||
Size.y = finalSurface->h;
|
||||
TextureSize.x = finalSurface->w;
|
||||
TextureSize.y = finalSurface->h;
|
||||
|
||||
// 释放所有临时表面
|
||||
SDL_FreeSurface(textSurface);
|
||||
SDL_FreeSurface(strokeSurface);
|
||||
SDL_FreeSurface(finalSurface);
|
||||
|
||||
// 恢复字体原始轮廓设置
|
||||
TTF_SetFontOutline(font, originalOutline);
|
||||
}
|
||||
|
||||
void Text::HandleEvents(SDL_Event *e)
|
||||
{
|
||||
}
|
||||
|
||||
void Text::Update(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void Text::Render()
|
||||
{
|
||||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||||
if (!renderer || !m_texture)
|
||||
return;
|
||||
SDL_Rect dstrect = {Pos.x, Pos.y, Size.x, Size.y};
|
||||
|
||||
SDL_RenderCopy(renderer, m_texture, NULL, &dstrect);
|
||||
}
|
||||
|
||||
void Text::Clear()
|
||||
{
|
||||
}
|
||||
|
||||
void Text::SetPos(SDL_Point pos)
|
||||
{
|
||||
Pos = pos;
|
||||
}
|
||||
|
||||
SDL_Point Text::GetPos()
|
||||
{
|
||||
return Pos;
|
||||
}
|
||||
|
||||
void Text::SetText(std::string Str)
|
||||
{
|
||||
if (Str == m_text)
|
||||
return;
|
||||
if (!m_font)
|
||||
{
|
||||
SDL_LogError(0, "SetText失败:字体指针为空!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有原纹理先删除原纹理
|
||||
if (m_texture)
|
||||
{
|
||||
SDL_DestroyTexture(m_texture);
|
||||
m_texture = nullptr; // 置空指针
|
||||
}
|
||||
m_text = Str;
|
||||
// 根据是否有描边选择对应的Init方法
|
||||
if (m_stroke_size > 0)
|
||||
{
|
||||
Init(Str, m_font, m_text_color, m_stroke_color, m_stroke_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Init(Str, m_font, m_text_color);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Text::GetText()
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
59
source/EngineFrame/Component/Text.h
Normal file
59
source/EngineFrame/Component/Text.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include "EngineFrame/Component/Component.h"
|
||||
class Game;
|
||||
|
||||
class Text : public Component
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
SDL_Texture *m_texture = nullptr;
|
||||
|
||||
public:
|
||||
Text(/* args */);
|
||||
Text(std::string Str, TTF_Font *font, SDL_Color color);
|
||||
Text(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize);
|
||||
~Text();
|
||||
|
||||
// 显式引入基类的Init方法,避免隐藏
|
||||
using Component::Init;
|
||||
void Init(std::string Str, TTF_Font *font, SDL_Color color);
|
||||
void Init(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize);
|
||||
void HandleEvents(SDL_Event *e) override;
|
||||
void Update(float deltaTime) override;
|
||||
void Render() override;
|
||||
void Clear() override;
|
||||
|
||||
SDL_Texture *GetTexture();
|
||||
|
||||
public:
|
||||
// 组件标签
|
||||
Tag m_tag = Tag::RENDER | Tag::UPDATE; // 标记该组件需要渲染和更新
|
||||
|
||||
std::string m_text;
|
||||
TTF_Font *m_font;
|
||||
SDL_Color m_text_color;
|
||||
SDL_Color m_stroke_color;
|
||||
int m_stroke_size = 0;
|
||||
|
||||
SDL_Point Pos = {0, 0}; // 位置坐标
|
||||
SDL_Point TextureSize = {0, 0}; // 纹理大小
|
||||
SDL_Point Size = {0, 0}; // 大小
|
||||
SDL_Point Anchor = {0, 0}; // 中心点
|
||||
float Angle = 0.0f; // 旋转角度
|
||||
SDL_RendererFlip flip = SDL_FLIP_NONE; // 翻转
|
||||
|
||||
public:
|
||||
// 设置坐标
|
||||
void SetPos(SDL_Point pos);
|
||||
// 设置文本
|
||||
void SetText(std::string Str);
|
||||
|
||||
// 获取坐标
|
||||
SDL_Point GetPos();
|
||||
// 获取文本
|
||||
std::string GetText();
|
||||
};
|
||||
Reference in New Issue
Block a user