#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 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_FLIP_HORIZONTAL | _RenderGuidanceInfo.flip); if (flipY) _RenderGuidanceInfo.flip = static_cast(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 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; } }