feat: improve action animations

This commit is contained in:
2026-02-05 20:23:37 +08:00
parent 9e2d885949
commit e66e997a16
5 changed files with 105 additions and 18 deletions

View File

@@ -110,7 +110,9 @@ bool GameSession::executeAction(int toRow, int toCol) {
m_board->changeHP(toRow, toCol, -fromPiece->getATK());
m_board->changeHP(fromRow, fromCol, -toPiece->getATK() * 0.5);
if (fromPiece->getHP() > 0 && toPiece->getHP() > 0) {
m_gamePieceEventCallback(GamePieceEvent::FIGHT_PIECE, fromRow, fromCol, toRow, toCol);
}
if (fromPiece->getHP() <= 0) {
m_gamePieceEventCallback(GamePieceEvent::REMOVE_PIECE, fromRow, fromCol, -1, -1);
m_board->removePieceAt(fromRow, fromCol);
@@ -121,6 +123,7 @@ bool GameSession::executeAction(int toRow, int toCol) {
if (fromPiece->getHP() > 0) {
m_gamePieceEventCallback(GamePieceEvent::MOVE_PIECE, fromRow, fromCol, toRow, toCol);
auto fromInfo = fromPiece->getPieceInfo();
m_board->removePieceAt(fromRow, fromCol);

View File

@@ -34,7 +34,8 @@ enum class GamePieceEvent {
PLACE_PIECE,
MOVE_PIECE,
GROW_PIECE,
SPORE_PIECE
SPORE_PIECE,
FIGHT_PIECE
};
struct PieceInfo {

View File

@@ -1,6 +1,7 @@
#include "BoardRenderer.h"
#include "game/Board.h"
#include "core/Time.h"
#include "utils/Tools.h"
#include <iostream>
BoardRenderer::BoardRenderer(int WIDTH, int HEIGHT, SDL_Renderer* renderer, TextureManager* textureManager) :
m_Width(WIDTH),
@@ -114,7 +115,8 @@ void BoardRenderer::drawPiece(std::optional<std::pair<int, int>> selectedPiece)
float progess = m_pieceGrowStatus.currentTime / m_pieceGrowStatus.animationDuration;
m_textureManager->destoryTexture(rect, color);
auto renderColor = color;
renderColor.a = 255 * progess;
renderColor.a = Tools::smoothMove(progess, 0, 255);
auto texture = m_textureManager->createTextureFromRect(rect, renderColor);
SDL_RenderTexture(m_renderer, texture, nullptr, &rect);
continue;
@@ -167,21 +169,42 @@ void BoardRenderer::drawPiece(std::optional<std::pair<int, int>> selectedPiece)
continue;
}
if (m_pieceMoveStatus.isAnimating && col == m_pieceMoveStatus.toCol && row == m_pieceMoveStatus.toRow) {
//SDL_Log("rendering..\n");
m_pieceMoveStatus.currentTime += Time::deltaTime();
if (m_pieceMoveStatus.currentTime > m_pieceMoveStatus.animationDuration) {
m_pieceMoveStatus.currentTime = m_pieceMoveStatus.animationDuration;
m_pieceMoveStatus.isAnimating = false;
}
float progess = m_pieceMoveStatus.currentTime / m_pieceMoveStatus.animationDuration;
auto renderRect = m_pieceMoveStatus.fromPieceRect;
renderRect.x += m_pieceMoveStatus.distanceCol * progess;
renderRect.y += m_pieceMoveStatus.distanceRow * progess;
SDL_RenderTexture(m_renderer, texture, nullptr, &renderRect);
} else {
SDL_RenderTexture(m_renderer, texture, nullptr, &rect);
if (m_pieceMoveStatus.isAnimating && col == m_pieceMoveStatus.toCol && row == m_pieceMoveStatus.toRow) {
//SDL_Log("rendering..\n");
m_pieceMoveStatus.currentTime += Time::deltaTime();
if (m_pieceMoveStatus.currentTime > m_pieceMoveStatus.animationDuration) {
m_pieceMoveStatus.currentTime = m_pieceMoveStatus.animationDuration;
m_pieceMoveStatus.isAnimating = false;
}
float progess = m_pieceMoveStatus.currentTime / m_pieceMoveStatus.animationDuration;
auto renderRect = m_pieceMoveStatus.fromPieceRect;
renderRect.x += Tools::smoothMove(progess, 0, m_pieceMoveStatus.distanceCol);
renderRect.y += Tools::smoothMove(progess, 0, m_pieceMoveStatus.distanceRow);
SDL_RenderTexture(m_renderer, texture, nullptr, &renderRect);
continue;
}
if (m_pieceFightStatus.isAnimating && col == m_pieceFightStatus.fromCol && row == m_pieceFightStatus.fromRow) {
m_pieceFightStatus.currentTime += Time::deltaTime();
if (m_pieceFightStatus.currentTime > m_pieceFightStatus.animationDuration) {
m_pieceFightStatus.currentTime = m_pieceFightStatus.animationDuration;
m_pieceFightStatus.isAnimating = false;
}
float progess = m_pieceFightStatus.currentTime / m_pieceFightStatus.animationDuration;
auto renderRect = m_pieceFightStatus.fromPieceRect;
float cX = m_pieceFightStatus.distanceCol * 0.5f;
float cY = m_pieceFightStatus.distanceRow * 0.5f;
renderRect.x = Tools::pingPongSpring(progess, renderRect.x, cX);
renderRect.y = Tools::pingPongSpring(progess, renderRect.y, cY);
SDL_RenderTexture(m_renderer, texture, nullptr, &renderRect);
continue;
}
SDL_RenderTexture(m_renderer, texture, nullptr, &rect);
@@ -378,6 +401,18 @@ void BoardRenderer::handleGamePieceEvent(GamePieceEvent event, int fromRow, int
1.0f
};
break;
case (GamePieceEvent::FIGHT_PIECE):
m_pieceFightStatus = {
fromRow, fromCol,
toRow, toCol,
toY - fromY,
toX - fromX,
0.0f,
true,
rect,
1.0f
};
break;
default:
break;
}

View File

@@ -35,6 +35,19 @@ struct PieceGrowStatue {
};
struct PieceFightStatue {
int fromRow = -1;
int fromCol = -1;
int toRow = -1;
int toCol = -1;
float distanceRow;
float distanceCol;
float currentTime = 0.0f; // 当前已进行时间
bool isAnimating = false;
SDL_FRect fromPieceRect;
float animationDuration = 1.0f; // 动画总时长(秒)
};
class Board;
class BoardRenderer
@@ -64,6 +77,8 @@ private:
PieceGrowStatue m_pieceGrowStatus;
PieceFightStatue m_pieceFightStatus;
public:
BoardRenderer(int WIDTH, int HEIGHT, SDL_Renderer* renderer, TextureManager* textureManager);

View File

@@ -1,7 +1,10 @@
#pragma once
#include <utility>
#include "Config.h"
#include <cmath>
static inline float easeInOutSine(float t) {
return -(cos(M_PI * t) - 1) / 2.0f;
}
namespace Tools {
inline std::pair<int, int> physicalToLogical(float physicalX, float physicalY, const Viewport& viewport) {
std::pair<int, int> logicalPoint = {0 , 0};
@@ -16,4 +19,34 @@ namespace Tools {
return logicalPoint;
}
// t ∈ [0, 1]0=开始0.5=最远点1=回到原点(带震荡)
// b = 起始值(原位置)
// c = 偏移量(最大偏移距离)
inline float pingPongSpring(float t, float b, float c) {
if (t <= 0.0f) return b;
if (t >= 1.0f) return b; // 最终回到原点!
float overshoot = 1.70158f;
if (t < 0.5f) {
// 前半段:从 0 → 1冲到最远点
t *= 2.0f; // 映射到 [0,1]
float val = t * t * ((overshoot + 1) * t - overshoot);
return b + c * val;
} else {
// 后半段:从 1 → 0从最远点弹回原点带过冲
t = (t - 0.5f) * 2.0f; // 映射到 [0,1]
t -= 1;
float val = t * t * ((overshoot + 1) * t + overshoot) + 1;
return b + c * (1.0f - val); // 从 c 往回减到 0
}
}
// 通用插值函数
inline float smoothMove(float t, float start, float end) {
float progress = easeInOutSine(t); // t ∈ [0,1]
return start + (end - start) * progress;
}
}