# Implémentation Système de Vies, Obstacles et Coffre - TODO ## ✅ Ce qui est fait ### 1. Classes Créées - ✅ **TreasureChest** (`src/entities/TreasureChest.ts`) - Coffre qui s'ouvre avec 15 cadeaux collectés - Donne +1000 points - Effets visuels spectaculaires - ✅ **Player** modifié avec invincibilité - Méthode `makeInvincible()` - Effet clignotant - Timer d'invincibilité 2 secondes ### 2. Constantes Ajoutées - `PLAYER_STARTING_LIVES = 3` - `RESPAWN_INVINCIBILITY_TIME = 2000` - `CHEST_REQUIRED_GIFTS = 15` ### 3. Variables GameScene - `lives: number` - `giftsCollected: number` - `lastCheckpointX: number` - `treasureChest: TreasureChest` - UI texts pour vies et cadeaux ## 🚧 Ce qu'il reste à implémenter dans GameScene ### 1. Ajouter le coffre au niveau Dans `spawnTestObjects()`, ajouter à la fin : ```typescript // Coffre final au bout du niveau this.treasureChest = new TreasureChest(this, 7700, height - 300, CHEST_REQUIRED_GIFTS); this.physics.add.overlap(this.player!, this.treasureChest, this.openChest, undefined, this); ``` ### 2. Modifier `createUI()` - Ajouter affichage vies Ajouter après le score : ```typescript // Vies this.livesText = this.add.text(20, 60, `❤️ Vies: ${this.lives}`, { fontSize: '28px', color: '#ff0000', stroke: '#000000', strokeThickness: 4, }); this.livesText.setScrollFactor(0); this.livesText.setDepth(100); // Cadeaux collectés this.giftsCollectedText = this.add.text(20, 100, `🎁 Cadeaux: ${this.giftsCollected}/${CHEST_REQUIRED_GIFTS}`, { fontSize: '24px', color: '#FFD700', stroke: '#000000', strokeThickness: 3, }); this.giftsCollectedText.setScrollFactor(0); this.giftsCollectedText.setDepth(100); ``` ### 3. Modifier `collectGift()` - Compter les cadeaux ```typescript private collectGift(_player: any, gift: any): void { gift.destroy(); this.giftsCollected++; this.addScore(100); // Mettre à jour l'UI this.giftsCollectedText?.setText(`🎁 Cadeaux: ${this.giftsCollected}/${CHEST_REQUIRED_GIFTS}`); // Feedback si on a assez pour le coffre if (this.giftsCollected >= CHEST_REQUIRED_GIFTS && !this.treasureChest?.getIsOpen()) { // Flash doré this.cameras.main.flash(100, 255, 215, 0, true); const hint = this.add.text( this.cameras.main.scrollX + this.cameras.main.width / 2, this.cameras.main.height / 2, '🏆 Assez de cadeaux! Trouvez le coffre! 🏆', { fontSize: '32px', color: '#FFD700', stroke: '#000000', strokeThickness: 4, } ); hint.setOrigin(0.5); hint.setScrollFactor(0); hint.setDepth(1000); this.tweens.add({ targets: hint, alpha: 0, duration: 3000, onComplete: () => hint.destroy(), }); } } ``` ### 4. Créer `openChest()` - Interaction avec le coffre ```typescript private openChest(_player: any, chest: any): void { if (chest.canOpen(this.giftsCollected)) { const bonus = chest.open(this); this.addScore(bonus); } else if (!chest.getIsOpen()) { // Pas assez de cadeaux const remaining = chest.getRequiredGifts() - this.giftsCollected; const warning = this.add.text( this.cameras.main.scrollX + this.cameras.main.width / 2, this.cameras.main.height / 2, `❌ Encore ${remaining} cadeaux nécessaires! ❌`, { fontSize: '28px', color: '#FF0000', stroke: '#000000', strokeThickness: 4, } ); warning.setOrigin(0.5); warning.setScrollFactor(0); warning.setDepth(1000); this.tweens.add({ targets: warning, alpha: 0, duration: 2000, onComplete: () => warning.destroy(), }); } } ``` ### 5. Modifier `hitObstacle()` - Système de vies ```typescript private hitObstacle(player: any, obstacle: any): void { // Vérifier si on saute dessus (player au-dessus de l'obstacle) const playerBody = player.body as Phaser.Physics.Arcade.Body; const obstacleBody = obstacle.body as Phaser.Physics.Arcade.Body; const isJumpingOn = playerBody.velocity.y > 0 && playerBody.bottom <= obstacleBody.top + 10; if (isJumpingOn) { // Sauter dessus = détruit l'obstacle obstacle.destroy(); this.addScore(50); // Bonus pour avoir sauté dessus player.jump(); // Petit rebond // Effet visuel this.add.circle(obstacleBody.x, obstacleBody.y, 20, 0x00FF00, 0.5) .setDepth(100); console.log('💚 Obstacle détruit en sautant dessus !'); } else { // Collision frontale = perd une vie if (player.getIsInvincible()) { console.log('🛡️ Invincible - pas de dégâts'); return; } this.loseLife(); } } ``` ### 6. Créer `loseLife()` - Gestion perte de vie ```typescript private loseLife(): void { this.lives--; this.livesText?.setText(`❤️ Vies: ${this.lives}`); // Flash rouge this.cameras.main.flash(200, 255, 0, 0, true); this.cameras.main.shake(200, 0.01); console.log(`💔 Vie perdue! Vies restantes: ${this.lives}`); if (this.lives <= 0) { this.gameOver(); } else { this.respawnPlayer(); } } ``` ### 7. Créer `respawnPlayer()` - Respawn au checkpoint ```typescript private respawnPlayer(): void { if (!this.player) return; // Téléporter au dernier checkpoint this.player.setPosition(this.lastCheckpointX, this.cameras.main.height - 200); this.player.setVelocity(0, 0); // Activer invincibilité this.player.makeInvincible(this); // Message const respawnText = this.add.text( this.cameras.main.scrollX + this.cameras.main.width / 2, this.cameras.main.height / 2, `💫 RESPAWN! ${this.lives} ❤️ restantes`, { fontSize: '36px', color: '#00FF00', stroke: '#000000', strokeThickness: 6, } ); respawnText.setOrigin(0.5); respawnText.setScrollFactor(0); respawnText.setDepth(1000); this.tweens.add({ targets: respawnText, alpha: 0, duration: 2000, onComplete: () => respawnText.destroy(), }); } ``` ### 8. Créer `gameOver()` - Game Over ```typescript private gameOver(): void { console.log('💀 GAME OVER'); // Arrêter le jeu this.physics.pause(); // Écran de game over const gameOverText = this.add.text( this.cameras.main.scrollX + this.cameras.main.width / 2, this.cameras.main.height / 2 - 50, 'GAME OVER', { fontSize: '72px', color: '#FF0000', stroke: '#000000', strokeThickness: 8, fontStyle: 'bold', } ); gameOverText.setOrigin(0.5); gameOverText.setScrollFactor(0); gameOverText.setDepth(2000); const scoreText = this.add.text( this.cameras.main.scrollX + this.cameras.main.width / 2, this.cameras.main.height / 2 + 50, `Score Final: ${this.score}`, { fontSize: '36px', color: '#FFFFFF', stroke: '#000000', strokeThickness: 4, } ); scoreText.setOrigin(0.5); scoreText.setScrollFactor(0); scoreText.setDepth(2000); // Retour au menu après 3 secondes this.time.delayedCall(3000, () => { this.cleanup(); this.scene.start('MenuScene'); }); } ``` ### 9. Système de Checkpoints (optionnel mais recommandé) Dans `update()`, détecter quand le joueur passe un checkpoint : ```typescript // Mettre à jour le checkpoint tous les 1000px if (this.player && this.player.x > this.lastCheckpointX + 1000) { this.lastCheckpointX = this.player.x; console.log(`🚩 Checkpoint! Position: ${this.lastCheckpointX}`); } ``` ## 🎮 Résumé des Mécaniques ### Obstacles - **Sauter dessus** : Détruit + 50 pts + rebond - **Collision frontale** : Perd 1 vie (sauf si invincible) ### Vies - **Départ** : 3 vies - **Respawn** : Position checkpoint + 2s invincibilité - **Game Over** : 0 vies → retour menu ### Coffre Final - **Requis** : 15 cadeaux collectés - **Position** : Fin du niveau (7700px) - **Récompense** : +1000 points - **Feedback** : Message si pas assez de cadeaux ### UI ``` ❤️ Vies: 3 🎁 Cadeaux: 12/15 Score: 2500 Timer: 2:15 ``` ## 📝 Fichiers à Modifier 1. ✅ `src/entities/TreasureChest.ts` - Créé 2. ✅ `src/entities/Player.ts` - Modifié (invincibilité) 3. ✅ `src/utils/constants.ts` - Constantes ajoutées 4. 🚧 `src/scenes/GameScene.ts` - À compléter avec les fonctions ci-dessus ## 🔧 Test 1. Lance le jeu 2. Fonce dans un obstacle → perd 1 vie → respawn avec clignotement 3. Saute sur un obstacle → détruit + bonus 4. Collecte 15 cadeaux → message "Trouvez le coffre!" 5. Va au bout du niveau et saute sur le coffre → MEGA BONUS! Tout le code est prêt, il suffit de copier-coller les fonctions dans GameScene ! 🚀