添加粒子效果

This commit is contained in:
2026-04-26 13:20:00 +08:00
parent 03bf93afaa
commit b537d3c193
4 changed files with 266 additions and 0 deletions
+137
View File
@@ -17,6 +17,9 @@ PlayerStats classicStats = { 0, 1, 0, 0, 0 };
PlayerStats rogueStats = { 0, 1, 0, 30, 0, 100, 100, 0 };
UpgradeUiState upgradeUiState = { 0, 0, 0, 0, {} };
FeedbackState feedbackState = { 0, _T(""), _T("") };
ClearEffectState clearEffectState = { 0, 0, 0, {} };
FloatingTextEffect floatingTextEffects[8] = {};
ParticleEffect particleEffects[24] = {};
int currentScreen = SCREEN_MENU;
int currentMode = MODE_CLASSIC;
int currentFallInterval = 500;
@@ -239,6 +242,129 @@ void SetFeedbackMessage(const TCHAR* title, const TCHAR* detail, int ticks)
lstrcpyn(feedbackState.detail, detail, sizeof(feedbackState.detail) / sizeof(TCHAR));
}
void ResetVisualEffects()
{
clearEffectState.ticks = 0;
clearEffectState.totalTicks = 0;
clearEffectState.rowCount = 0;
for (int i = 0; i < 8; i++)
{
floatingTextEffects[i].ticks = 0;
}
for (int i = 0; i < 24; i++)
{
particleEffects[i].ticks = 0;
}
}
bool TickVisualEffects()
{
bool active = false;
if (clearEffectState.ticks > 0)
{
clearEffectState.ticks--;
active = true;
}
for (int i = 0; i < 8; i++)
{
if (floatingTextEffects[i].ticks > 0)
{
floatingTextEffects[i].ticks--;
active = true;
}
}
for (int i = 0; i < 24; i++)
{
if (particleEffects[i].ticks > 0)
{
particleEffects[i].ticks--;
active = true;
}
}
return active;
}
static void AddFloatingText(int boardX, int boardY, const TCHAR* text, COLORREF color)
{
for (int i = 0; i < 8; i++)
{
if (floatingTextEffects[i].ticks <= 0)
{
floatingTextEffects[i].ticks = 22;
floatingTextEffects[i].totalTicks = 22;
floatingTextEffects[i].boardX = boardX;
floatingTextEffects[i].boardY = boardY;
floatingTextEffects[i].color = color;
lstrcpyn(floatingTextEffects[i].text, text, sizeof(floatingTextEffects[i].text) / sizeof(TCHAR));
return;
}
}
}
static void AddParticle(int boardX, int boardY, COLORREF color)
{
for (int i = 0; i < 24; i++)
{
if (particleEffects[i].ticks <= 0)
{
particleEffects[i].ticks = 10 + rand() % 5;
particleEffects[i].totalTicks = particleEffects[i].ticks;
particleEffects[i].boardX = boardX;
particleEffects[i].boardY = boardY;
particleEffects[i].velocityX = (rand() % 11) - 5;
particleEffects[i].velocityY = -8 + (rand() % 5);
particleEffects[i].color = color;
return;
}
}
}
void TriggerLineClearEffect(const int* rows, int rowCount, int linesCleared)
{
if (rows == nullptr || rowCount <= 0 || linesCleared <= 0)
{
return;
}
if (rowCount > 8)
{
rowCount = 8;
}
clearEffectState.ticks = 16;
clearEffectState.totalTicks = 16;
clearEffectState.rowCount = rowCount;
int rowSum = 0;
for (int i = 0; i < rowCount; i++)
{
clearEffectState.rows[i] = rows[i];
rowSum += rows[i];
for (int x = 0; x < nGameWidth; x += 3)
{
COLORREF particleColor = BrickColor[(x + rows[i]) % 7];
AddParticle(x * 100 + 50, rows[i] * 100 + 50, particleColor);
}
}
TCHAR text[64];
if (linesCleared >= 4)
{
_stprintf_s(text, _T("TETRIS"));
}
else
{
_stprintf_s(text, _T("%d LINE%s"), linesCleared, linesCleared > 1 ? _T("S") : _T(""));
}
AddFloatingText(nGameWidth * 50, (rowSum * 100 / rowCount) - 20, text, linesCleared >= 4 ? RGB(255, 232, 120) : RGB(255, 250, 252));
}
bool IsPiecePlacementValid(int pieceType, int pieceState, Point position)
{
for (int i = 0; i < 4; i++)
@@ -741,6 +867,8 @@ int DeleteLines()
{
int clearedLines = 0;
bool clearedWithRainbow = false;
int clearedRows[8] = {};
int clearedRowCount = 0;
int playableHeight = GetRoguePlayableHeight();
for (int i = playableHeight - 1; i >= 0; i--)
@@ -758,6 +886,12 @@ int DeleteLines()
if (fullLine)
{
if (clearedRowCount < 8)
{
clearedRows[clearedRowCount] = i;
clearedRowCount++;
}
for (int j = 0; j < nGameWidth; j++)
{
if (IsRainbowBoardCell(workRegion[i][j]))
@@ -773,6 +907,7 @@ int DeleteLines()
}
ApplyLineClearResult(clearedLines);
TriggerLineClearEffect(clearedRows, clearedRowCount, clearedLines);
if (pendingChainBombFollowup && clearedLines > 0)
{
@@ -898,6 +1033,7 @@ void Restart()
feedbackState.visibleTicks = 0;
feedbackState.title[0] = _T('\0');
feedbackState.detail[0] = _T('\0');
ResetVisualEffects();
holdType = -1;
holdUsedThisTurn = false;
RollCurrentPieceSpecialFlags(false);
@@ -929,6 +1065,7 @@ void ReturnToMainMenu()
currentScreen = SCREEN_MENU;
suspendFlag = false;
gameOverFlag = false;
ResetVisualEffects();
menuState.optionCount = 3;
upgradeUiState.pendingCount = 0;
upgradeUiState.picksRemaining = 0;