feat: draw one card after each turn with slide-in animation
This commit is contained in:
1 parent
ec5a7ec2c3
commit
b46cb707cd
3 files changed
+102
-10
No files matched your search
@@ -363,7 +363,12 @@ export class GameScene extends Phaser.Scene {
|
|||||||
if (this.playSlots.length !== state.players.length) {
|
if (this.playSlots.length !== state.players.length) {
|
||||||
this._buildSlots(state.players.length)
|
this._buildSlots(state.players.length)
|
||||||
}
|
}
|
||||||
this._buildHand(state.hand)
|
// Si ce n'est pas le premier tour, animer la pioche avant d'afficher la main
|
||||||
|
if (state.currentTurn > 1) {
|
||||||
|
this._animateDraw(state.hand)
|
||||||
|
} else {
|
||||||
|
this._buildHand(state.hand)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.phase === 'waiting') {
|
if (state.phase === 'waiting') {
|
||||||
@@ -391,6 +396,76 @@ export class GameScene extends Phaser.Scene {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Animation pioche ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Affiche d'abord les cartes déjà en main, puis fait tomber la nouvelle
|
||||||
|
* (toujours la dernière du tableau, ajoutée par nextTurn côté serveur)
|
||||||
|
*/
|
||||||
|
_animateDraw(cards) {
|
||||||
|
const { width, height } = this.scale
|
||||||
|
|
||||||
|
// Afficher immédiatement les cartes déjà en main (toutes sauf la dernière)
|
||||||
|
const existing = cards.slice(0, -1)
|
||||||
|
const newCard = cards[cards.length - 1]
|
||||||
|
|
||||||
|
this._buildHand(existing)
|
||||||
|
|
||||||
|
if (!newCard) return
|
||||||
|
|
||||||
|
// Calculer la position finale de la nouvelle carte dans la main complète
|
||||||
|
const handY = height - BOTTOM_MARGIN - 110
|
||||||
|
const spacing = Math.min(150, (width * 0.85) / cards.length)
|
||||||
|
const totalW = spacing * (cards.length - 1)
|
||||||
|
const startX = width / 2 - totalW / 2
|
||||||
|
const finalX = startX + (cards.length - 1) * spacing
|
||||||
|
|
||||||
|
// Créer la carte hors écran (au-dessus)
|
||||||
|
const card = new CardObject(this, finalX, -200, newCard)
|
||||||
|
card.setDepth(50)
|
||||||
|
card.on('select', this._onCardSelected, this)
|
||||||
|
card.setAlpha(0)
|
||||||
|
|
||||||
|
// Animation : fade + slide vers la position finale
|
||||||
|
this.tweens.add({
|
||||||
|
targets: card,
|
||||||
|
y: handY,
|
||||||
|
alpha: 1,
|
||||||
|
duration: 400,
|
||||||
|
ease: 'Back.Out',
|
||||||
|
delay: 100,
|
||||||
|
onComplete: () => {
|
||||||
|
card._baseY = handY
|
||||||
|
card.setDepth(0)
|
||||||
|
this.handCards.push(card)
|
||||||
|
// Recalculer le spacing de toutes les cartes maintenant qu'on en a une de plus
|
||||||
|
this._repositionHand()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Repositionne toutes les cartes en main avec le bon espacement */
|
||||||
|
_repositionHand() {
|
||||||
|
const { width, height } = this.scale
|
||||||
|
const handY = height - BOTTOM_MARGIN - 110
|
||||||
|
const n = this.handCards.length
|
||||||
|
const spacing = Math.min(150, (width * 0.85) / n)
|
||||||
|
const totalW = spacing * (n - 1)
|
||||||
|
const startX = width / 2 - totalW / 2
|
||||||
|
|
||||||
|
this.handCards.forEach((card, i) => {
|
||||||
|
const targetX = startX + i * spacing
|
||||||
|
card._baseY = handY
|
||||||
|
this.tweens.add({
|
||||||
|
targets: card,
|
||||||
|
x: targetX,
|
||||||
|
y: handY,
|
||||||
|
duration: 250,
|
||||||
|
ease: 'Power2'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Utilitaires ─────────────────────────────────────────────────────────────
|
// ─── Utilitaires ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
_darken(hex, factor) {
|
_darken(hex, factor) {
|
||||||
|
|||||||
+17
-6
@@ -37,7 +37,8 @@ class Room {
|
|||||||
name,
|
name,
|
||||||
teamIndex: this.players.length,
|
teamIndex: this.players.length,
|
||||||
gauges: { food: 0, war: 0, health: 0, diplo: 0 },
|
gauges: { food: 0, war: 0, health: 0, diplo: 0 },
|
||||||
hand: []
|
hand: [],
|
||||||
|
deck: [] // cartes restantes à piocher
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -49,9 +50,10 @@ class Room {
|
|||||||
// ─── Démarrage ──────────────────────────────────────────────────────────────
|
// ─── Démarrage ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
startGame() {
|
startGame() {
|
||||||
const hands = dealHands(this.players.length, HAND_SIZE)
|
const dealt = dealHands(this.players.length, HAND_SIZE)
|
||||||
this.players.forEach((p, i) => {
|
this.players.forEach((p, i) => {
|
||||||
p.hand = hands[i]
|
p.hand = dealt[i].hand
|
||||||
|
p.deck = dealt[i].deck
|
||||||
p.gauges = { food: 0, war: 0, health: 0, diplo: 0 }
|
p.gauges = { food: 0, war: 0, health: 0, diplo: 0 }
|
||||||
})
|
})
|
||||||
this.currentTurn = 1
|
this.currentTurn = 1
|
||||||
@@ -144,6 +146,13 @@ class Room {
|
|||||||
// ─── Tour suivant ────────────────────────────────────────────────────────────
|
// ─── Tour suivant ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
nextTurn() {
|
nextTurn() {
|
||||||
|
// Chaque joueur pioche une carte depuis son deck personnel
|
||||||
|
this.players.forEach(p => {
|
||||||
|
if (p.deck.length > 0) {
|
||||||
|
p.hand.push(p.deck.shift())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
this.currentTurn++
|
this.currentTurn++
|
||||||
if (this.isGameOver()) {
|
if (this.isGameOver()) {
|
||||||
this.phase = 'end'
|
this.phase = 'end'
|
||||||
@@ -153,8 +162,9 @@ class Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isGameOver() {
|
isGameOver() {
|
||||||
const allEmpty = this.players.every(p => p.hand.length === 0)
|
// Partie terminée quand plus personne n'a de carte en main ET plus de deck
|
||||||
return allEmpty || this.currentTurn >= this.maxTurns
|
const allEmpty = this.players.every(p => p.hand.length === 0 && p.deck.length === 0)
|
||||||
|
return allEmpty || this.currentTurn > this.maxTurns
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Données publiques ───────────────────────────────────────────────────────
|
// ─── Données publiques ───────────────────────────────────────────────────────
|
||||||
@@ -165,7 +175,8 @@ class Room {
|
|||||||
teamIndex: p.teamIndex,
|
teamIndex: p.teamIndex,
|
||||||
gauges: { ...p.gauges },
|
gauges: { ...p.gauges },
|
||||||
score: ATTRS.reduce((sum, a) => sum + p.gauges[a], 0),
|
score: ATTRS.reduce((sum, a) => sum + p.gauges[a], 0),
|
||||||
handSize: p.hand.length
|
handSize: p.hand.length,
|
||||||
|
deckSize: p.deck.length
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,13 +165,19 @@ function shuffle(arr) {
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pour chaque joueur : retourne { hand, deck } (hand = les N premières cartes, deck = le reste)
|
||||||
|
*/
|
||||||
function dealHands(playerCount, handSize = 4) {
|
function dealHands(playerCount, handSize = 4) {
|
||||||
const hands = []
|
const result = []
|
||||||
for (let i = 0; i < playerCount; i++) {
|
for (let i = 0; i < playerCount; i++) {
|
||||||
const deck = shuffle(getDeckForTeam(i))
|
const deck = shuffle(getDeckForTeam(i))
|
||||||
hands.push(deck.slice(0, handSize))
|
result.push({
|
||||||
|
hand: deck.slice(0, handSize),
|
||||||
|
deck: deck.slice(handSize) // cartes restantes à piocher
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return hands
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { CHARACTERS, TEAM_COLORS, ATTR_COLORS, getDeckForTeam, dealHands }
|
module.exports = { CHARACTERS, TEAM_COLORS, ATTR_COLORS, getDeckForTeam, dealHands }
|
||||||
Reference in new issue
Block a user