Files
DNF_DEV/source/EngineFrame/Component/Sprite.cpp

240 lines
7.8 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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→11→0
if (flipHorizontal)
{
v.tex_coord.x = 1.0f - v.tex_coord.x;
}
// 垂直翻转反转v坐标0→11→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;
}
}