refactor: overhaul 2048 merge animation and swap sound effects
- Replace PIECE_CLICK with alternating MASTERMIND_GLITCH sounds - Refactor merge animation: redraw all tiles before merge phase instead of skipping merged positions - Hide spawn tile early to prevent flash before spawn animation - Simplify merge destination setup by removing redundant alpha reset - Extract runMergePhase callback for cleaner merge/no-merge flow
This commit is contained in:
parent
4b78bf047f
commit
a8e21a3bc6
|
|
@ -35,11 +35,12 @@ export default class Game2048 extends Phaser.Scene {
|
||||||
this.tileGraphics = [];
|
this.tileGraphics = [];
|
||||||
this.tileTexts = [];
|
this.tileTexts = [];
|
||||||
|
|
||||||
this.busy = false;
|
this.busy = false;
|
||||||
this.gameOver = false;
|
this.gameOver = false;
|
||||||
this.wonAlready = false;
|
this.wonAlready = false;
|
||||||
this.score = 0;
|
this.score = 0;
|
||||||
this.best = 0;
|
this.best = 0;
|
||||||
|
this._sfxToggle = 0;
|
||||||
|
|
||||||
this.scoreValueText = null;
|
this.scoreValueText = null;
|
||||||
this.bestValueText = null;
|
this.bestValueText = null;
|
||||||
|
|
@ -416,7 +417,8 @@ export default class Game2048 extends Phaser.Scene {
|
||||||
if (!newState) return;
|
if (!newState) return;
|
||||||
|
|
||||||
this.busy = true;
|
this.busy = true;
|
||||||
playSound(this, SFX.PIECE_CLICK);
|
playSound(this, this._sfxToggle ? SFX.MASTERMIND_GLITCH_2 : SFX.MASTERMIND_GLITCH_1);
|
||||||
|
this._sfxToggle ^= 1;
|
||||||
|
|
||||||
this._animateMove(this.state, newState, () => {
|
this._animateMove(this.state, newState, () => {
|
||||||
this.state = newState;
|
this.state = newState;
|
||||||
|
|
@ -500,7 +502,7 @@ export default class Game2048 extends Phaser.Scene {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build map: merge destination index → moving source containers currently at that position
|
// Build map: merge destination → moving source containers sitting at that position
|
||||||
const mergeSources = new Map();
|
const mergeSources = new Map();
|
||||||
for (const mv of movingEntries) {
|
for (const mv of movingEntries) {
|
||||||
if (!mergeSet.has(mv.toIdx)) continue;
|
if (!mergeSet.has(mv.toIdx)) continue;
|
||||||
|
|
@ -509,33 +511,35 @@ export default class Game2048 extends Phaser.Scene {
|
||||||
mergeSources.get(mv.toIdx).push({ cont: this.tileContainers[fr][fc], fromIdx: mv.fromIdx });
|
mergeSources.get(mv.toIdx).push({ cont: this.tileContainers[fr][fc], fromIdx: mv.fromIdx });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Immediately update all tiles that aren't part of a merge transition
|
|
||||||
const skipIndices = new Set(newState.mergedAt);
|
|
||||||
for (const srcs of mergeSources.values()) {
|
|
||||||
for (const { fromIdx } of srcs) skipIndices.add(fromIdx);
|
|
||||||
}
|
|
||||||
this._redrawTilesExcept(newState, skipIndices);
|
|
||||||
|
|
||||||
// Count total source containers across all merges
|
|
||||||
let totalSrcs = 0;
|
let totalSrcs = 0;
|
||||||
for (const srcs of mergeSources.values()) totalSrcs += srcs.length;
|
for (const srcs of mergeSources.values()) totalSrcs += srcs.length;
|
||||||
|
|
||||||
if (totalSrcs === 0) {
|
// Restore every tile to its canonical position/value, then hand off to
|
||||||
|
// _showMergedTiles which overrides scale=0 on the merge destinations so
|
||||||
|
// the grow animation runs from nothing. Hiding the spawn tile here
|
||||||
|
// prevents it flashing visible before spawnPhase animates it in.
|
||||||
|
const runMergePhase = () => {
|
||||||
|
this._redrawAllTiles(newState);
|
||||||
|
if (newState.spawned !== null) {
|
||||||
|
const sr = Math.floor(newState.spawned / 4), sc = newState.spawned % 4;
|
||||||
|
this.tileContainers[sr][sc].setAlpha(0);
|
||||||
|
}
|
||||||
this._showMergedTiles(newState, spawnPhase);
|
this._showMergedTiles(newState, spawnPhase);
|
||||||
return;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// Scale down all source containers simultaneously (they're at the merge position)
|
if (totalSrcs === 0) { runMergePhase(); return; }
|
||||||
|
|
||||||
|
// Scale down all merge-source containers simultaneously (they're at the merge position)
|
||||||
let scaledDown = 0;
|
let scaledDown = 0;
|
||||||
const onAllScaledDown = () => {
|
const onAllScaledDown = () => {
|
||||||
// Reset every source to its home cell (invisible) before growing merged tiles
|
// Reset source containers to their home cells before the full redraw
|
||||||
for (const [, srcs] of mergeSources) {
|
for (const [, srcs] of mergeSources) {
|
||||||
for (const { cont, fromIdx } of srcs) {
|
for (const { cont, fromIdx } of srcs) {
|
||||||
const { cx, cy } = this._cellCenter(Math.floor(fromIdx / 4), fromIdx % 4);
|
const { cx, cy } = this._cellCenter(Math.floor(fromIdx / 4), fromIdx % 4);
|
||||||
cont.setAlpha(0).setScale(1).setPosition(cx, cy);
|
cont.setAlpha(0).setScale(1).setPosition(cx, cy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._showMergedTiles(newState, spawnPhase);
|
runMergePhase();
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const [, srcs] of mergeSources) {
|
for (const [, srcs] of mergeSources) {
|
||||||
|
|
@ -577,9 +581,10 @@ export default class Game2048 extends Phaser.Scene {
|
||||||
for (const idx of newState.mergedAt) {
|
for (const idx of newState.mergedAt) {
|
||||||
const tr = Math.floor(idx / 4), tc = idx % 4;
|
const tr = Math.floor(idx / 4), tc = idx % 4;
|
||||||
const destCont = this.tileContainers[tr][tc];
|
const destCont = this.tileContainers[tr][tc];
|
||||||
this._paintTile(tr, tc, newState.grid[idx]);
|
// _redrawAllTiles already painted this tile at alpha=1 scale=1;
|
||||||
|
// collapse scale to 0 so the grow tween starts from nothing.
|
||||||
this._scorePopup(destCont.x, destCont.y - 40, newState.grid[idx]);
|
this._scorePopup(destCont.x, destCont.y - 40, newState.grid[idx]);
|
||||||
destCont.setAlpha(1).setScale(0);
|
destCont.setScale(0);
|
||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: destCont, scaleX: 1.2, scaleY: 1.2,
|
targets: destCont, scaleX: 1.2, scaleY: 1.2,
|
||||||
duration: 200, ease: 'Back.easeOut',
|
duration: 200, ease: 'Back.easeOut',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue