diff --git a/client/public/cards/apoticaire.png b/client/public/cards/apoticaire.png new file mode 100644 index 0000000..e950340 Binary files /dev/null and b/client/public/cards/apoticaire.png differ diff --git a/client/public/cards/assassin.png b/client/public/cards/assassin.png new file mode 100644 index 0000000..2896fac Binary files /dev/null and b/client/public/cards/assassin.png differ diff --git a/client/public/cards/boucher.png b/client/public/cards/boucher.png new file mode 100644 index 0000000..d4c0743 Binary files /dev/null and b/client/public/cards/boucher.png differ diff --git a/client/public/cards/bourreau.png b/client/public/cards/bourreau.png new file mode 100644 index 0000000..b98e1c3 Binary files /dev/null and b/client/public/cards/bourreau.png differ diff --git a/client/public/cards/chevalier.png b/client/public/cards/chevalier.png new file mode 100644 index 0000000..9425f60 Binary files /dev/null and b/client/public/cards/chevalier.png differ diff --git a/client/public/cards/eveque.png b/client/public/cards/eveque.png new file mode 100644 index 0000000..ddc0cbd Binary files /dev/null and b/client/public/cards/eveque.png differ diff --git a/client/public/cards/fou_du_roi.png b/client/public/cards/fou_du_roi.png new file mode 100644 index 0000000..f3ae3ca Binary files /dev/null and b/client/public/cards/fou_du_roi.png differ diff --git a/client/public/cards/marchand.png b/client/public/cards/marchand.png new file mode 100644 index 0000000..ebd8814 Binary files /dev/null and b/client/public/cards/marchand.png differ diff --git a/client/public/cards/medecin.png b/client/public/cards/medecin.png new file mode 100644 index 0000000..446acbe Binary files /dev/null and b/client/public/cards/medecin.png differ diff --git a/client/public/cards/paysan.png b/client/public/cards/paysan.png new file mode 100644 index 0000000..d454a17 Binary files /dev/null and b/client/public/cards/paysan.png differ diff --git a/client/public/cards/prince.png b/client/public/cards/prince.png new file mode 100644 index 0000000..9201402 Binary files /dev/null and b/client/public/cards/prince.png differ diff --git a/client/public/cards/reine.png b/client/public/cards/reine.png new file mode 100644 index 0000000..c77f4df Binary files /dev/null and b/client/public/cards/reine.png differ diff --git a/client/src/game/objects/CardObject.js b/client/src/game/objects/CardObject.js index b7a027f..5eb52fa 100644 --- a/client/src/game/objects/CardObject.js +++ b/client/src/game/objects/CardObject.js @@ -31,55 +31,70 @@ export class CardObject extends Phaser.GameObjects.Container { } _build() { - const teamHex = this.cardData.teamColor?.hex ?? 0x888888 + const teamHex = this.cardData.teamColor?.hex ?? 0x888888 + const textureKey = `card-${this.cardData.id}` + const hasTexture = this.scene.textures.exists(textureKey) - // --- Fond de carte avec couleur d'équipe --- + // --- Ombre portée --- + const shadow = this.scene.add.graphics() + shadow.fillStyle(0x000000, 0.45) + shadow.fillRoundedRect(-CARD_W / 2 + 4, -CARD_H / 2 + 4, CARD_W, CARD_H, RADIUS) + this.add(shadow) + + // --- Fond coloré équipe --- const bg = this.scene.add.graphics() - // Ombre portée - bg.fillStyle(0x000000, 0.4) - bg.fillRoundedRect(4, 4, CARD_W, CARD_H, RADIUS) - // Corps principal (couleur équipe assombrie) - bg.fillStyle(this._darken(teamHex, 0.3)) - bg.fillRoundedRect(0, 0, CARD_W, CARD_H, RADIUS) - // Bordure couleur équipe - bg.lineStyle(2, teamHex, 1) - bg.strokeRoundedRect(0, 0, CARD_W, CARD_H, RADIUS) - // Zone portrait (rectangle foncé central) - bg.fillStyle(0x000000, 0.35) - bg.fillRoundedRect(8, 28, CARD_W - 16, CARD_H - 80, 6) - bg.x = -CARD_W / 2 - bg.y = -CARD_H / 2 + bg.fillStyle(this._darken(teamHex, 0.25)) + bg.fillRoundedRect(-CARD_W / 2, -CARD_H / 2, CARD_W, CARD_H, RADIUS) this.add(bg) - // --- Nom du personnage (haut, centré) --- - const nameText = this.scene.add.text(0, -CARD_H / 2 + 9, this.cardData.name, { - fontSize: '13px', + // --- Image du personnage (zone portrait) --- + if (hasTexture) { + const img = this.scene.add.image(0, -10, textureKey) + // Ajuster pour remplir la zone portrait en conservant le ratio + const portraitH = CARD_H - 50 // laisser place au nom (haut) et badges (coins) + const portraitW = CARD_W - 4 + img.setDisplaySize(portraitW, portraitH) + img.setAlpha(0.92) + // Masque arrondi via crop + clip (simulé via alpha sur les bords) + this.add(img) + + // Overlay dégradé en bas pour lisibilité du texte + const overlay = this.scene.add.graphics() + overlay.fillGradientStyle(0x000000, 0x000000, 0x000000, 0x000000, 0, 0, 0.7, 0.7) + overlay.fillRect(-CARD_W / 2, CARD_H / 2 - 55, CARD_W, 55) + this.add(overlay) + } else { + // Fallback : initiale si l'image n'est pas chargée + const initial = this.scene.add.text(0, -10, this.cardData.name[0], { + fontSize: '60px', + fontFamily: 'Georgia, serif', + color: '#ffffff', + alpha: 0.12 + }).setOrigin(0.5, 0.5) + this.add(initial) + } + + // --- Bordure couleur équipe --- + const border = this.scene.add.graphics() + border.lineStyle(2, teamHex, 1) + border.strokeRoundedRect(-CARD_W / 2, -CARD_H / 2, CARD_W, CARD_H, RADIUS) + this.add(border) + + // --- Bandeau nom (haut) --- + const nameBg = this.scene.add.graphics() + nameBg.fillStyle(0x000000, 0.65) + nameBg.fillRoundedRect(-CARD_W / 2, -CARD_H / 2, CARD_W, 24, { tl: RADIUS, tr: RADIUS, bl: 0, br: 0 }) + this.add(nameBg) + + const nameText = this.scene.add.text(0, -CARD_H / 2 + 12, this.cardData.name, { + fontSize: '12px', fontFamily: 'Georgia, serif', - color: '#ffffff', + color: '#f5e6c8', stroke: '#000000', - strokeThickness: 3, + strokeThickness: 2, fontStyle: 'bold' - }).setOrigin(0.5, 0) - this.add(nameText) - - // --- Initiale du personnage (zone portrait) --- - const initial = this.scene.add.text(0, -CARD_H / 2 + 75, this.cardData.name[0], { - fontSize: '52px', - fontFamily: 'Georgia, serif', - color: '#ffffff', - alpha: 0.15 }).setOrigin(0.5, 0.5) - this.add(initial) - - // --- Description courte (bas de carte) --- - const desc = this.scene.add.text(0, CARD_H / 2 - 22, this._shortDesc(), { - fontSize: '8px', - fontFamily: 'Georgia, serif', - color: '#cccccc', - wordWrap: { width: CARD_W - 16 }, - align: 'center' - }).setOrigin(0.5, 1) - this.add(desc) + this.add(nameText) // --- 4 badges d'attributs dans les coins --- this._addCornerBadge('food', -CARD_W / 2 + 2, -CARD_H / 2 + 2, 'topLeft') @@ -97,36 +112,31 @@ export class CardObject extends Phaser.GameObjects.Container { /** * Badge carré coloré dans un coin, avec la valeur de l'attribut - * @param {'food'|'war'|'health'|'diplo'} attr - * @param {number} bx position x relative au centre du container (coin du badge) - * @param {number} by position y relative au centre du container (coin du badge) - * @param {'topLeft'|'topRight'|'bottomLeft'|'bottomRight'} corner */ _addCornerBadge(attr, bx, by, corner) { const { color, label } = ATTR[attr] const value = this.cardData[attr] const S = CORNER - // Calculer l'origine du rectangle selon le coin let rx = bx, ry = by - if (corner === 'topRight' || corner === 'bottomRight') rx = bx - S - if (corner === 'bottomLeft' || corner === 'bottomRight') ry = by - S + if (corner === 'topRight' || corner === 'bottomRight') rx = bx - S + if (corner === 'bottomLeft' || corner === 'bottomRight') ry = by - S - const g = this.scene.add.graphics() - g.fillStyle(color, 0.9) - // Coins arrondis uniquement vers l'intérieur de la carte const cornerRadii = { topLeft: { tl: RADIUS, tr: 2, bl: 2, br: 4 }, topRight: { tl: 2, tr: RADIUS, bl: 4, br: 2 }, bottomLeft: { tl: 2, tr: 4, bl: RADIUS, br: 2 }, bottomRight: { tl: 4, tr: 2, bl: 2, br: RADIUS } } + + const g = this.scene.add.graphics() + g.fillStyle(color, 0.92) g.fillRoundedRect(rx, ry, S, S, cornerRadii[corner]) this.add(g) - // Valeur (grand, centré dans le badge) const cx = rx + S / 2 const cy = ry + S / 2 - 3 + const valText = this.scene.add.text(cx, cy, String(value), { fontSize: '14px', fontFamily: 'Georgia, serif', @@ -137,12 +147,11 @@ export class CardObject extends Phaser.GameObjects.Container { }).setOrigin(0.5, 0.5) this.add(valText) - // Label abrégé (petit, en bas du badge) const lblText = this.scene.add.text(cx, cy + 8, label, { fontSize: '6px', fontFamily: 'Arial, sans-serif', color: '#ffffff', - alpha: 0.85 + alpha: 0.9 }).setOrigin(0.5, 0.5) this.add(lblText) } @@ -190,9 +199,4 @@ export class CardObject extends Phaser.GameObjects.Container { const b = Math.floor(( hex & 0xff) * factor) return (r << 16) | (g << 8) | b } - - _shortDesc() { - const d = this.cardData.description || '' - return d.length > 60 ? d.substring(0, 57) + '…' : d - } } diff --git a/client/src/game/scenes/BootScene.js b/client/src/game/scenes/BootScene.js index 8509bdd..7734b09 100644 --- a/client/src/game/scenes/BootScene.js +++ b/client/src/game/scenes/BootScene.js @@ -1,29 +1,45 @@ import Phaser from 'phaser' +// Correspondance id personnage → fichier image +const CARD_IMAGES = [ + { id: 'queen', file: 'reine.png' }, + { id: 'prince', file: 'prince.png' }, + { id: 'butcher', file: 'boucher.png' }, + { id: 'doctor', file: 'medecin.png' }, + { id: 'apothecary', file: 'apoticaire.png'}, + { id: 'jester', file: 'fou_du_roi.png'}, + { id: 'assassin', file: 'assassin.png' }, + { id: 'peasant', file: 'paysan.png' }, + { id: 'executioner', file: 'bourreau.png' }, + { id: 'knight', file: 'chevalier.png' }, + { id: 'merchant', file: 'marchand.png' }, + { id: 'bishop', file: 'eveque.png' } +] + export class BootScene extends Phaser.Scene { constructor() { super('BootScene') } preload() { - // Créer des textures procédurales pour les cartes - const graphics = this.add.graphics() + // Charger les images des 12 personnages + CARD_IMAGES.forEach(({ id, file }) => { + this.load.image(`card-${id}`, `/cards/${file}`) + }) - // Fond de carte - graphics.fillStyle(0x2a1500) - graphics.fillRoundedRect(0, 0, 120, 180, 10) - graphics.lineStyle(2, 0xd4a732) - graphics.strokeRoundedRect(0, 0, 120, 180, 10) - graphics.generateTexture('card-back', 120, 180) - graphics.clear() + // Barre de chargement simple + const { width, height } = this.scale + const bar = this.add.graphics() - // Carte face - graphics.fillStyle(0x3a2010) - graphics.fillRoundedRect(0, 0, 120, 180, 10) - graphics.lineStyle(2, 0xd4a732) - graphics.strokeRoundedRect(0, 0, 120, 180, 10) - graphics.generateTexture('card-front', 120, 180) - graphics.destroy() + this.load.on('progress', (v) => { + bar.clear() + bar.fillStyle(0x1a0a00) + bar.fillRect(width / 2 - 150, height / 2 - 10, 300, 20) + bar.fillStyle(0xd4a732) + bar.fillRect(width / 2 - 150, height / 2 - 10, 300 * v, 20) + }) + + this.load.on('complete', () => bar.destroy()) } create() {