Additional Animations

This commit is contained in:
Brian Fertig 2026-05-18 23:09:06 -06:00
parent 53db492c83
commit 9469440122
1 changed files with 145 additions and 20 deletions

View File

@ -601,39 +601,164 @@ export default class GoFishGame extends Phaser.Scene {
const after = applyAsk(before, targetSeat, rank);
if (after === before) { this.animating = false; return; }
const last = after.lastAsk;
this.showBanner(this.formatAskBanner(last));
playSound(this, last.result === 'catch' ? SFX.CARD_PLACE : SFX.CARD_DEAL);
this.gs = after;
this.selectedRank = null;
this.animateAsk(askerSeat, targetSeat, rank, last, before, () => {
this.showBanner(this.formatAskBanner(last));
playSound(this, last.result === 'catch' ? SFX.CARD_PLACE : SFX.CARD_DEAL);
for (let s = 0; s < this.gs.players.length; s++) {
observeLog(this.aiMemory[s], this.gs, s);
}
this.gs = after;
this.selectedRank = null;
if (last.newPairs > 0 && last.pairedCards?.length >= 2) {
this.time.delayedCall(600, () => {
this.hideBanner();
this.renderAll();
this.updateStatus();
this.animatePairedCards(askerSeat, last.pairedCards, () => {
for (let s = 0; s < this.gs.players.length; s++) {
observeLog(this.aiMemory[s], this.gs, s);
}
if (last.newPairs > 0 && last.pairedCards?.length >= 2) {
this.time.delayedCall(600, () => {
this.hideBanner();
this.renderAll();
this.updateStatus();
this.animatePairedCards(askerSeat, last.pairedCards, () => {
this.animating = false;
if (isGameOver(this.gs)) { this.endGame(); return; }
this.maybeStartAITurn();
});
});
} else {
this.time.delayedCall(900, () => {
this.renderAll();
this.updateStatus();
this.animating = false;
if (isGameOver(this.gs)) { this.endGame(); return; }
this.hideBanner();
this.maybeStartAITurn();
});
}
});
}
animateAsk(askerSeat, targetSeat, rank, last, beforeState, onComplete) {
const askerSlot = this.slotForSeat[askerSeat];
const askerLayout = slotLayout(askerSlot);
const askerShow = this.slotShowPos(askerSlot, askerLayout);
const askerCard = beforeState.players[askerSeat].hand.find(c => c.rank === rank);
if (!askerCard) { onComplete(); return; }
const askerSprite = this.makeCardSprite(askerCard, askerLayout.handCenter.x, askerLayout.handCenter.y, {
faceUp: false, rotation: 0,
});
askerSprite.setDepth(D.banner - 4);
this.transientObjs.push(askerSprite);
this.tweens.add({
targets: askerSprite,
x: askerShow.x, y: askerShow.y,
duration: 280,
ease: 'Cubic.easeOut',
onComplete: () => this.flipCardFaceUp(askerSprite, askerCard),
});
if (last.result === 'catch') {
const targetSlot = this.slotForSeat[targetSeat];
const targetLayout = slotLayout(targetSlot);
const targetShow = this.slotShowPos(targetSlot, targetLayout);
const n = last.cardsTransferred.length;
this.time.delayedCall(640, () => {
const isTargetVert = targetSlot === 'left' || targetSlot === 'right';
const targetSprites = last.cardsTransferred.map((card, i) => {
const tx = isTargetVert ? targetShow.x
: targetShow.x + (i - (n - 1) / 2) * (CARD_W + 8);
const ty = isTargetVert ? targetShow.y + (i - (n - 1) / 2) * (CARD_H + 8)
: targetShow.y;
const sprite = this.makeCardSprite(card, targetLayout.handCenter.x, targetLayout.handCenter.y, {
faceUp: false, rotation: 0,
});
sprite.setDepth(D.banner - 4);
this.transientObjs.push(sprite);
this.tweens.add({
targets: sprite,
x: tx, y: ty,
duration: 250,
delay: i * 80,
ease: 'Cubic.easeOut',
onComplete: () => this.flipCardFaceUp(sprite, card),
});
return { sprite, tx, ty };
});
const waitMs = 250 + (n - 1) * 80 + 380;
this.time.delayedCall(waitMs, () => {
if (askerSprite.active) {
this.tweens.add({
targets: askerSprite, alpha: 0, duration: 200,
onComplete: () => { if (askerSprite.active) askerSprite.destroy(); },
});
}
for (const { sprite } of targetSprites) {
if (!sprite.active) continue;
this.tweens.add({
targets: sprite,
x: askerLayout.handCenter.x, y: askerLayout.handCenter.y,
alpha: 0, duration: 380, ease: 'Cubic.easeIn',
onComplete: () => { if (sprite.active) sprite.destroy(); },
});
}
this.time.delayedCall(420, onComplete);
});
});
} else {
this.time.delayedCall(900, () => {
this.renderAll();
this.updateStatus();
this.animating = false;
if (isGameOver(this.gs)) { this.endGame(); return; }
this.hideBanner();
this.maybeStartAITurn();
this.time.delayedCall(880, () => {
this.flipCardFaceDown(askerSprite);
this.time.delayedCall(340, () => {
this.tweens.add({
targets: askerSprite,
x: askerLayout.handCenter.x, y: askerLayout.handCenter.y,
duration: 280, ease: 'Cubic.easeIn',
onComplete: () => { if (askerSprite.active) askerSprite.destroy(); },
});
this.time.delayedCall(320, onComplete);
});
});
}
}
slotShowPos(slot, layout) {
const GAP = 10;
switch (slot) {
case 'bottom': return { x: layout.handCenter.x, y: layout.handCenter.y - CARD_H / 2 - GAP - CARD_H / 2 };
case 'top': return { x: layout.handCenter.x, y: layout.handCenter.y + CARD_H / 2 + GAP + CARD_H / 2 };
case 'left': return { x: layout.handCenter.x + CARD_H / 2 + GAP + CARD_W / 2, y: layout.handCenter.y };
case 'right': return { x: layout.handCenter.x - CARD_H / 2 - GAP - CARD_W / 2, y: layout.handCenter.y };
default: return { x: CX, y: CY };
}
}
flipCardFaceUp(container, card) {
this.tweens.add({
targets: container, scaleX: 0, duration: 150, ease: 'Linear',
onComplete: () => {
container.setRotation(0);
this.renderCardFace(container, card, true);
this.tweens.add({ targets: container, scaleX: 1, duration: 150, ease: 'Linear' });
},
});
}
flipCardFaceDown(container) {
this.tweens.add({
targets: container, scaleX: 0, duration: 150, ease: 'Linear',
onComplete: () => {
this.renderCardFace(container, container.card, false);
this.tweens.add({ targets: container, scaleX: 1, duration: 150, ease: 'Linear' });
},
});
}
animatePairedCards(askerSeat, pairedCards, onComplete) {
const slot = this.slotForSeat[askerSeat];
const layout = slotLayout(slot);