|
|
|
import pyxel
|
|
|
|
import random
|
|
|
|
|
|
|
|
# Paramètres du jeu
|
|
|
|
SCREEN_WIDTH = 128
|
|
|
|
SCREEN_HEIGHT = 128
|
|
|
|
BIRD_SIZE = 8
|
|
|
|
PIPE_WIDTH = 16
|
|
|
|
BIRD_GRAVITY = 0.4 # Modifié de 0.5 à 0.4
|
|
|
|
BIRD_LIFT = -4 # Modifié de -6 à -4
|
|
|
|
PIPE_SPEED = 1
|
|
|
|
PIPE_FREQ = 60
|
|
|
|
PIPE_GAP = 50 # Valeur par défaut (sera modifiée selon la difficulté)
|
|
|
|
|
|
|
|
class FlappyBirdGame:
|
|
|
|
def __init__(self):
|
|
|
|
pyxel.init(SCREEN_WIDTH, SCREEN_HEIGHT)
|
|
|
|
pyxel.load("flappybird.pyxres") # Charger les ressources depuis le fichier .pyxres
|
|
|
|
self.bird_x = SCREEN_WIDTH // 4
|
|
|
|
self.bird_y = SCREEN_HEIGHT // 2
|
|
|
|
self.bird_velocity = 0
|
|
|
|
self.pipes = []
|
|
|
|
self.frame = 0
|
|
|
|
self.score = 0
|
|
|
|
self.game_over = False
|
|
|
|
self.game_started = False # Ajout de l'état de début du jeu
|
|
|
|
self.passed_pipes = [] # Suivi des tuyaux déjà passés
|
|
|
|
self.difficulty_selected = False # Indicateur si la difficulté a été choisie
|
|
|
|
self.difficulty = "easy" # Valeur par défaut
|
|
|
|
pyxel.run(self.update, self.draw)
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
if self.game_over or not self.difficulty_selected:
|
|
|
|
return
|
|
|
|
|
|
|
|
self.frame += 1
|
|
|
|
|
|
|
|
# Si le jeu n'a pas commencé, on attend que l'utilisateur appuie sur espace
|
|
|
|
if not self.game_started:
|
|
|
|
if pyxel.btnp(pyxel.KEY_SPACE):
|
|
|
|
self.game_started = True # Le jeu commence dès qu'on appuie sur espace
|
|
|
|
self.bird_velocity = BIRD_LIFT # On applique un premier saut
|
|
|
|
|
|
|
|
# Si le jeu a commencé, on gère la logique normale
|
|
|
|
if self.game_started:
|
|
|
|
# Saut du joueur
|
|
|
|
if pyxel.btnp(pyxel.KEY_SPACE):
|
|
|
|
self.bird_velocity = BIRD_LIFT
|
|
|
|
|
|
|
|
# Mise à jour de la position de l'oiseau
|
|
|
|
self.bird_velocity += BIRD_GRAVITY
|
|
|
|
self.bird_y += self.bird_velocity
|
|
|
|
|
|
|
|
# Limiter l'oiseau aux bords de l'écran
|
|
|
|
if self.bird_y < 0:
|
|
|
|
self.bird_y = 0
|
|
|
|
if self.bird_y > SCREEN_HEIGHT - BIRD_SIZE:
|
|
|
|
self.bird_y = SCREEN_HEIGHT - BIRD_SIZE
|
|
|
|
self.game_over = True
|
|
|
|
|
|
|
|
# Création des tuyaux
|
|
|
|
if self.frame % PIPE_FREQ == 0:
|
|
|
|
pipe_height = random.randint(20, SCREEN_HEIGHT - PIPE_GAP - 20)
|
|
|
|
self.pipes.append([SCREEN_WIDTH, pipe_height])
|
|
|
|
|
|
|
|
# Mise à jour de la position des tuyaux
|
|
|
|
for pipe in self.pipes:
|
|
|
|
pipe[0] -= PIPE_SPEED
|
|
|
|
|
|
|
|
# Vérification des collisions
|
|
|
|
for pipe in self.pipes:
|
|
|
|
# Si l'oiseau touche un tuyau, le jeu est terminé
|
|
|
|
if self.bird_x + BIRD_SIZE > pipe[0] and self.bird_x < pipe[0] + PIPE_WIDTH:
|
|
|
|
if self.bird_y < pipe[1] or self.bird_y + BIRD_SIZE > pipe[1] + PIPE_GAP:
|
|
|
|
self.game_over = True
|
|
|
|
|
|
|
|
# Retirer les tuyaux hors de l'écran
|
|
|
|
self.pipes = [pipe for pipe in self.pipes if pipe[0] + PIPE_WIDTH > 0]
|
|
|
|
|
|
|
|
# Mise à jour du score
|
|
|
|
for pipe in self.pipes:
|
|
|
|
# Vérifier si l'oiseau a traversé le tuyau
|
|
|
|
if pipe[0] + PIPE_WIDTH < self.bird_x and pipe not in self.passed_pipes:
|
|
|
|
self.score += 1
|
|
|
|
self.passed_pipes.append(pipe) # Marquer le tuyau comme "passé"
|
|
|
|
|
|
|
|
def draw(self):
|
|
|
|
pyxel.cls(0) # Effacer l'écran
|
|
|
|
|
|
|
|
# Si le menu de sélection de difficulté est actif
|
|
|
|
if not self.difficulty_selected:
|
|
|
|
self.draw_menu()
|
|
|
|
return
|
|
|
|
|
|
|
|
# Dessiner le fond
|
|
|
|
pyxel.blt(0, 0, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0) # Dessiner l'arrière-plan complet (ciel, nuages, sol)
|
|
|
|
|
|
|
|
# Dessiner l'oiseau en utilisant l'image du sprite dans le fichier .pyxres
|
|
|
|
pyxel.blt(self.bird_x, self.bird_y, 0, 128, 0, 8, 8, 0) # Le 0,0 ici représente la position du sprite dans le fichier pyxres
|
|
|
|
|
|
|
|
# Dessiner les tuyaux
|
|
|
|
for pipe in self.pipes:
|
|
|
|
pyxel.rect(pipe[0], 0, PIPE_WIDTH, pipe[1], 11) # Tuyau du dessus
|
|
|
|
pyxel.rect(pipe[0], pipe[1] + PIPE_GAP, PIPE_WIDTH, SCREEN_HEIGHT - pipe[1] - PIPE_GAP, 11) # Tuyau du dessous
|
|
|
|
|
|
|
|
# Afficher le score
|
|
|
|
pyxel.text(10, 10, f"Score: {self.score}", 7)
|
|
|
|
|
|
|
|
# Si le jeu est terminé
|
|
|
|
if self.game_over:
|
|
|
|
pyxel.text(SCREEN_WIDTH // 2 - 30, SCREEN_HEIGHT // 2, "GAME OVER", 8)
|
|
|
|
pyxel.text(SCREEN_WIDTH // 2 - 30, SCREEN_HEIGHT // 2 + 10, f"Score: {self.score}", 7)
|
|
|
|
|
|
|
|
# Si le jeu n'a pas encore commencé, afficher un message d'attente
|
|
|
|
if not self.game_started:
|
|
|
|
pyxel.text(SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2, "Press SPACE to Start", 8) # Afficher le texte sans centrage automatique
|
|
|
|
|
|
|
|
def draw_menu(self):
|
|
|
|
# Affichage du menu de sélection de la difficulté
|
|
|
|
pyxel.text(SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 3, "Select Difficulty", 7)
|
|
|
|
pyxel.text(SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2, "1. Easy", 7)
|
|
|
|
pyxel.text(SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2 + 10, "2. Medium", 7)
|
|
|
|
pyxel.text(SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2 + 20, "3. Hard", 7)
|
|
|
|
|
|
|
|
# Attente d'une entrée de l'utilisateur pour choisir la difficulté
|
|
|
|
if pyxel.btnp(pyxel.KEY_1):
|
|
|
|
self.difficulty = "easy"
|
|
|
|
self.set_difficulty("easy")
|
|
|
|
elif pyxel.btnp(pyxel.KEY_2):
|
|
|
|
self.difficulty = "medium"
|
|
|
|
self.set_difficulty("medium")
|
|
|
|
elif pyxel.btnp(pyxel.KEY_3):
|
|
|
|
self.difficulty = "hard"
|
|
|
|
self.set_difficulty("hard")
|
|
|
|
|
|
|
|
def set_difficulty(self, difficulty):
|
|
|
|
global PIPE_GAP
|
|
|
|
if difficulty == "easy":
|
|
|
|
PIPE_GAP = 70
|
|
|
|
elif difficulty == "medium":
|
|
|
|
PIPE_GAP = 50
|
|
|
|
elif difficulty == "hard":
|
|
|
|
PIPE_GAP = 30
|
|
|
|
self.difficulty_selected = True # La difficulté a été choisie, commencer le jeu
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
FlappyBirdGame()
|