feat: confirm button with pulse animation + ready counter (X/N players)

This commit is contained in:
kevin.lhereec committed 2026-08-17 11:57:55 +02:00
1 parent 91a1a9f4f0
commit 3125823f42
2 files changed
+84 -9

No files matched your search

+78 -9
View File
@@ -111,18 +111,75 @@ export class GameScene extends Phaser.Scene {
_buildPlayButton() {
const { width, height } = this.scale
const btnY = height - 28
this.playBtn = this.add.text(width / 2, height - 18, '[ JOUER LA CARTE ]', {
fontSize: '15px',
// Fond du bouton (rectangle arrondi via Graphics)
this.playBtnBg = this.add.graphics()
this._drawBtnBg(false)
// Texte du bouton
this.playBtn = this.add.text(width / 2, btnY, '✔ CONFIRMER MA CARTE', {
fontSize: '17px',
fontFamily: 'Georgia',
fontStyle: 'bold',
color: '#1a0a00',
backgroundColor: '#d4a732',
padding: { x: 20, y: 8 }
padding: { x: 28, y: 10 }
})
.setOrigin(0.5)
.setAlpha(0.35)
.setAlpha(0.3)
.setDepth(10)
.setInteractive({ cursor: 'pointer' })
.on('pointerdown', this._playSelectedCard, this)
.on('pointerover', () => { if (this._canPlay && this.selectedCard) this.playBtn.setScale(1.05) })
.on('pointerout', () => { this.playBtn.setScale(1) })
// Compteur de joueurs prêts (ex: "1 / 2 prêts")
this.readyText = this.add.text(width / 2, btnY + 22, '', {
fontSize: '12px',
fontFamily: 'Georgia',
color: '#a08060'
}).setOrigin(0.5).setDepth(10)
}
_drawBtnBg(active) {
const { width, height } = this.scale
const btnY = height - 28
const btnW = 280
const btnH = 42
this.playBtnBg.clear()
if (active) {
this.playBtnBg.fillStyle(0xd4a732, 1)
} else {
this.playBtnBg.fillStyle(0x4a3010, 0.5)
}
this.playBtnBg.fillRoundedRect(width / 2 - btnW / 2, btnY - btnH / 2, btnW, btnH, 8)
if (active) {
this.playBtnBg.lineStyle(2, 0xffd700)
this.playBtnBg.strokeRoundedRect(width / 2 - btnW / 2, btnY - btnH / 2, btnW, btnH, 8)
}
this.playBtnBg.setDepth(9)
}
_activateBtn() {
this._drawBtnBg(true)
this.playBtn.setAlpha(1).setColor('#1a0a00')
// Animation pulse
if (this._pulseTween) this._pulseTween.stop()
this._pulseTween = this.tweens.add({
targets: this.playBtn,
scaleX: 1.04,
scaleY: 1.04,
duration: 600,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut'
})
}
_deactivateBtn() {
this._drawBtnBg(false)
this.playBtn.setAlpha(0.3).setColor('#a08060').setScale(1)
if (this._pulseTween) { this._pulseTween.stop(); this._pulseTween = null }
}
// ─── Main du joueur ──────────────────────────────────────────────────────────
@@ -149,13 +206,14 @@ export class GameScene extends Phaser.Scene {
}
_onCardSelected(card) {
if (!this._canPlay) return
// Désélectionner l'ancienne
if (this.selectedCard && this.selectedCard !== card) {
this.selectedCard.deselect()
}
this.selectedCard = card
this.store.selectCard(card.cardData)
this.playBtn.setAlpha(1)
this._activateBtn()
}
_playSelectedCard() {
@@ -163,6 +221,7 @@ export class GameScene extends Phaser.Scene {
// Bloquer immédiatement pour éviter le double clic
this._canPlay = false
this._deactivateBtn()
this.socket.emit('play-card', {
roomId: this.roomId,
@@ -172,7 +231,6 @@ export class GameScene extends Phaser.Scene {
this.selectedCard.setAlpha(0.4)
this.selectedCard = null
this.store.clearSelection()
this.playBtn.setAlpha(0.35)
this.phaseText.setText('En attente des autres joueurs...')
}
@@ -279,22 +337,33 @@ export class GameScene extends Phaser.Scene {
this._canPlay = true
this.resolveObjects.forEach(o => o.destroy())
this.resolveObjects = []
this.phaseText.setText('Sélectionnez une carte')
this.phaseText.setText('Choisissez une carte puis confirmez')
this.readyText.setText('')
this._deactivateBtn()
this._buildHand(state.hand)
}
if (state.phase === 'waiting') {
this._canPlay = false
this.phaseText.setText('En attente des autres joueurs...')
this._deactivateBtn()
this.phaseText.setText('Carte confirmée — en attente des autres...')
}
if (state.phase === 'resolve' || state.phase === 'end') {
this._canPlay = false
this._deactivateBtn()
}
})
this.socket.on('players-ready', ({ ready, total }) => {
if (this.readyText) {
this.readyText.setText(`${ready} / ${total} joueurs prêts`)
}
})
this.socket.on('round-result', ({ playedCards, gains }) => {
this.phaseText.setText('Résolution du tour...')
this.readyText.setText('')
this._showPlayedCards(playedCards, gains)
})
}
+6
View File
@@ -69,6 +69,12 @@ io.on('connection', (socket) => {
return
}
// Broadcaster le compteur de joueurs prêts à tous
io.to(roomId).emit('players-ready', {
ready: room.pendingPlays.size,
total: room.playerCount
})
// Envoyer à chaque joueur son état personnalisé :
// - celui qui vient de jouer reçoit phase='waiting'
// - les autres restent en phase='selecting'