first
This commit is contained in:
337
IMPLEMENTATION_TODO.md
Normal file
337
IMPLEMENTATION_TODO.md
Normal file
@@ -0,0 +1,337 @@
|
||||
# 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 ! 🚀
|
||||
Reference in New Issue
Block a user