240 lines
7.8 KiB
C++
240 lines
7.8 KiB
C++
#include "Sprite.h"
|
||
#include "EngineCore/Game.h"
|
||
#include "Text.h"
|
||
|
||
void Sprite::Init()
|
||
{
|
||
this->Size = m_texture->TextureSize;
|
||
RenderBase::Init();
|
||
}
|
||
|
||
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::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);
|
||
|
||
// 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上
|
||
float texturePosX = flipX ? -(m_texture->TextureSize.width + m_texture->TexturePos.x) + SDL_abs(transform.position.x * 2) : m_texture->TexturePos.x;
|
||
float texturePosY = flipY ? -(m_texture->TextureSize.height + m_texture->TexturePos.y) + SDL_abs(transform.position.y * 2) : m_texture->TexturePos.y;
|
||
|
||
// 先计算Img坐标与精灵坐标合成后的真实坐标
|
||
float RealPosX = transform.position.x + texturePosX;
|
||
float RealPosY = transform.position.y + texturePosY;
|
||
|
||
// 计算在世界中的位置
|
||
float baseX = transformIter.position.x + RealPosX;
|
||
float baseY = transformIter.position.y + RealPosY;
|
||
|
||
// 获取当前帧的原始尺寸
|
||
int frameWidth = Size.width;
|
||
int frameHeight = Size.height;
|
||
|
||
// 原始锚点偏移(基于帧尺寸)
|
||
float origAnchorOffsetX = int(frameWidth * Anchor.x);
|
||
float origAnchorOffsetY = int(frameHeight * Anchor.y);
|
||
|
||
// 缩放的绝对值
|
||
float absScaleX = SDL_fabs(scaleX);
|
||
float absScaleY = SDL_fabs(scaleY);
|
||
// 缩放后的尺寸
|
||
float scaledWidth = frameWidth * absScaleX;
|
||
float scaledHeight = frameHeight * absScaleY;
|
||
// 缩放后的锚点偏移
|
||
float scaledAnchorOffsetX = int(origAnchorOffsetX * absScaleX);
|
||
float scaledAnchorOffsetY = int(origAnchorOffsetY * absScaleY);
|
||
|
||
// 计算缩放后的锚点偏移与原锚点偏移的差值
|
||
float scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
|
||
float scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;
|
||
|
||
// 最终位置计算:世界位置 + 缩放锚点差值 - 缩放后的锚点偏移 + 纹理数据里带的偏移数据 (计算出绘制点的左上角)
|
||
float Xpos = baseX - scaleOffsetX;
|
||
float Ypos = baseY - scaleOffsetY;
|
||
|
||
Xpos = (int)Xpos; // 强制转换为整数
|
||
Ypos = (int)Ypos; // 强制转换为整数
|
||
|
||
// 更新渲染信息
|
||
_RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
|
||
|
||
// 如果有阴影 计算阴影的渲染信息
|
||
if (ShadowFlag)
|
||
CalculateShadowData();
|
||
_RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
|
||
// 设置纹理透明度
|
||
SDL_SetTextureAlphaMod(m_texture->GetTexture(), this->Alpha * 255);
|
||
|
||
// 屏幕内检测
|
||
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::SetClipRect(SDL_Rect clipRect)
|
||
{
|
||
CropFlag = true;
|
||
CropRect = clipRect;
|
||
}
|
||
|
||
void Sprite::UnsetClipRect()
|
||
{
|
||
CropFlag = false;
|
||
}
|
||
|
||
void Sprite::PreRender()
|
||
{
|
||
if (CalcRenderInfoFlag && Visible)
|
||
CalcRenderInfoLogic();
|
||
}
|
||
|
||
void Sprite::Render()
|
||
{
|
||
if (!Visible)
|
||
return;
|
||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||
if (!m_texture)
|
||
return;
|
||
|
||
if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
|
||
{
|
||
// 如果有阴影绘制阴影
|
||
if (ShadowFlag)
|
||
{
|
||
std::array<int, 6> indices = {0, 1, 2, 1, 3, 2};
|
||
SDL_RenderGeometry(renderer, m_texture->GetTexture(), vertices.data(), vertices.size(), indices.data(), indices.size());
|
||
}
|
||
|
||
if (_RenderGuidanceInfo.rotation != 0.f || _RenderGuidanceInfo.flip != SDL_FLIP_NONE)
|
||
{
|
||
SDL_FPoint AnchorPos = _RenderGuidanceInfo.AnchorPos;
|
||
SDL_RenderCopyExF(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);
|
||
}
|
||
else
|
||
{
|
||
SDL_RenderCopyF(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect);
|
||
// // 设置绘制颜色
|
||
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, 128);
|
||
// // 绘制填充矩形
|
||
// SDL_RenderFillRectF(renderer, &_RenderGuidanceInfo.rect);
|
||
}
|
||
Game::GetInstance().m_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();
|
||
}
|
||
|
||
void Sprite::SetShadow()
|
||
{
|
||
ShadowFlag = true;
|
||
CalcRenderInfo();
|
||
}
|
||
|
||
void Sprite::CalculateShadowData()
|
||
{
|
||
const float shearX = 1.3f;
|
||
SDL_FRect guidance = _RenderGuidanceInfo.rect;
|
||
float shadowW = guidance.w; // 影子宽度(建议与角色宽度一致)
|
||
float shadowH = guidance.h * 0.33; // 影子高度(可根据需求调整,比如角色高度的1/4)
|
||
|
||
// 计算角色脚部中点坐标(底部中心,即需要重叠的锚点)
|
||
float roleFootX = guidance.x + guidance.w / 2.0f + 3; // 角色X中心 + 位置偏移
|
||
float roleFootY = guidance.y + guidance.h - 5; // 角色底部Y坐标(脚的位置)
|
||
|
||
// 计算错切后的顶点(局部坐标)
|
||
vertices = {
|
||
// 左上角(局部坐标)
|
||
SDL_Vertex{{0.0f, 0.0f}, {0, 0, 0, 110}, {0.0f, 0.0f}},
|
||
// 右上角(局部坐标)
|
||
SDL_Vertex{{shadowW, 0.0f}, {0, 0, 0, 110}, {1.0f, 0.0f}},
|
||
// 左下角(局部坐标)
|
||
SDL_Vertex{{0.0f + shearX * shadowH, shadowH}, {0, 0, 0, 110}, {0.0f, 1.0f}},
|
||
// 右下角(局部坐标)
|
||
SDL_Vertex{{shadowW + shearX * shadowH, shadowH}, {0, 0, 0, 110}, {1.0f, 1.0f}}};
|
||
|
||
bool flipHorizontal = (_RenderGuidanceInfo.flip & SDL_FLIP_HORIZONTAL) != 0; // 检查水平翻转标志
|
||
bool flipVertical = (_RenderGuidanceInfo.flip & SDL_FLIP_VERTICAL) != 0; // 检查垂直翻转标志
|
||
// 应用纹理坐标翻转(核心逻辑)
|
||
for (auto &v : vertices)
|
||
{
|
||
// 水平翻转:反转u坐标(0→1,1→0)
|
||
if (flipHorizontal)
|
||
{
|
||
v.tex_coord.x = 1.0f - v.tex_coord.x;
|
||
}
|
||
// 垂直翻转:反转v坐标(0→1,1→0)
|
||
if (flipVertical)
|
||
{
|
||
v.tex_coord.y = 1.0f - v.tex_coord.y;
|
||
}
|
||
}
|
||
|
||
// 计算影子底部中点并对齐角色脚部(与之前逻辑一致)
|
||
float shadowFootX = (vertices[2].position.x + vertices[3].position.x) / 2.0f;
|
||
float shadowFootY = shadowH;
|
||
float offsetX = roleFootX - shadowFootX;
|
||
float offsetY = roleFootY - shadowFootY;
|
||
|
||
// 应用位置偏移
|
||
for (auto &v : vertices)
|
||
{
|
||
v.position.x += offsetX;
|
||
v.position.y += offsetY;
|
||
}
|
||
}
|