Files
mario/IMPLEMENTATION_TODO.md
2025-12-14 11:15:50 +01:00

9.1 KiB

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 :

// 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 :

// 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

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

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

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

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

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

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 :

// 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 ! 🚀