Flappy Bird
Flappy Bird est un jeu mobile simple, frustrant et addictif, qui consiste à faire sautiller un oiseau le plus longtemps possible, tout en évitant des tuyaux qui défilent à l'écran. Le projet consiste à recréer ce jeu à l'aide du module Pyxel en suivant le paradigme de la POO.
Un programme minimal
Le module Pyxel est un moteur de jeu qui utilise une boucle de jeu. Tant que la fenêtre est ouverte, Pyxel appelle les fonctions update et draw à chaque image :
On regroupe le tout dans une class Jeu afin d'organiser le code : les différentes données du jeu (comme l'oiseau, les tuyaux, le score etc.) deviennent des attributs, et les fonctions qui agissent sur ces données (update, draw, etc.) deviennent des méthodes. Cela permet d'éviter l'utilisation de variables globales : les méthodes accèdent aux données du jeu via self car celles-ci sont des attributs de la classe.
import pyxel
class Jeu:
def __init__(self):
pyxel.init(240, 160, 'Flappy Bird', fps=60) #(2)!
pyxel.run(self.update, self.draw) #(3)!
def update(self):
pass #(4)!
def draw(self):
pyxel.cls(1) #(5)!
Jeu() #(1)!
-
On instancie un seul objet
Jeu, ce qui exécute immédiatement__init__et donc la boucle de jeu avecpyxel.run. -
On crée une fenêtre de 240×160 pixels, intitulée « Flappy Bird », qui s'actualise 60 fois par seconde.
-
On démarre la boucle de jeu. On donne à Pyxel les méthodes
self.updateetself.drawde la classe. -
Pour l'instant, il n'y a rien à mettre à jour.
-
On efface l'écran en le remplissant avec la couleur 1 (bleu foncé).

Ce code constitue le point de départ pour n'importe quel jeu !
Un oiseau qui tombe et saute
On modélise un oiseau par une class Oiseau en regroupant les données qui le définissent :
-
Position verticale de l'oiseau à l'écran. Comme l'oiseau ne se déplace pas horizontalement, son abscisse peut être fixée. Libre à vous de définir
self.xpour modifier ce comportement. -
Vitesse verticale de l'oiseau (nulle au départ).
On y ajoute ensuite les méthodes update et draw spécifiques à un oiseau. Elles seront appelées dans la boucle générale de jeu.
class Oiseau:
def __init__(self, y):
self.y = y
self.vy = 0
def update(self):
self.y += self.vy #(1)!
self.vy += 0.05 #(2)!
def draw(self):
pyxel.circ(20, self.y, 3, 10) #(3)!
- Mise à jour de la position verticale.
- La gravité accélère l'oiseau vers le bas.
- Dessine à l'écran un disque aux coordonnées (20,
self.y) de rayon 3 et de couleur 10 (jaune).
La classe Jeu est ainsi modifiée pour y ajouter un oiseau :
class Jeu:
def __init__(self):
self.oiseau = Oiseau(20)
pyxel.init(240, 160, 'Flappy Bird', fps=60)
pyxel.run(self.update, self.draw)
def update(self):
self.oiseau.update()
def draw(self):
pyxel.cls(1)
self.oiseau.draw()


Voilà un bel oiseau soumis par la gravité ! On peut facilement faire sauter l'oiseau en modifiant sa vitesse verticale à l'appui de la touche Space :
Libre à vous de modifier les valeurs d'intensité de la gravité et de saut. Ou même de les définir comme constantes ou comme attributs afin de les faire varier au cours du jeu...
Un Flappy Bird rudimentaire
-
Créer une
class Obstaclequi modélise une paire de tuyaux qui défile à l'écran (ou un seul tuyau si vous voulez découpler les deux). Ajouter un seul obstacle à laclass Jeupour tester votre classe. Ne pas gérer les collisions.
Quelques indications
- Utiliser la fonction Pyxel
pyxel.rectpour dessiner un rectangle (voir documentation). - Un obstacle est au moins caractérisé par sa position horizontale et la hauteur de son tuyau supérieur. Le reste (la largeur de l'obstacle, la hauteur entre les deux tuyaux, la vitesse horizontale) peut être défini comme des constantes.
- Utiliser la fonction Pyxel
-
Dans la
class Jeu, définir plutôt une liste d'obstacles et y ajouter de nouveaux obstacles au fur et à mesure. Ne pas oublier de supprimer les obstacles qui sortent de l'écran !
-
Détecter les collisions potentielles entre l'oiseau et les obstacles.

Collision entre un cercle et un rectangle
Tout d'abord, un cercle et un point sont en collision si la distance entre le centre du cercle et le point est inférieure ou égale au rayon du cercle :
dx = cercleX - pointX dy = cercleY - pointY return dx * dx + dy * dy <= cercleRayon * cercleRayon #(1)!- Équivalent à
return sqrt(dx * dx + dy * dy) <= cercleRayonen évitant le coûteux calcul d'une racine carrée !
Pour tester la collision entre un cercle et un rectangle, il suffit de déterminer le point sur le rectangle le plus proche du centre du cercle, et vérifier ensuite la collision entre ce point et le cercle. Pour déterminer ce point si le rectangle n'est pas tourné, on ramène les coordonnées du centre du cercle dans les limites du rectangle :
PointProcheX = max(rectX, min(cercleX, rectX + rectLargeur)) PointProcheY = max(rectY, min(cercleY, rectY + rectHauteur))En combinant avec le programme précédent :
- Équivalent à
-
Dans la
class Oiseau, ajouter un attribut booléenself.en_vieet une méthodemourir. Lorsqu'une collision se produit, l'oiseau meurt et ne peut plus sauter. Si l'oiseau tombe trop bas, relancer la partie via une méthoderesetde la classeclass Jeu.
À votre sauce

C'est la partie créative du projet ! Vous pouvez enrichir votre jeu Flappy Bird à votre guise ! Quelques idées pour vous inspirer :
- Ajouter un score : compter le nombre de tuyaux franchis, la durée de vol, etc.
- Ajouter des vies supplémentaires pour le joueur.
- Ajouter des pièces à collecter entre les tuyaux.
- Personnaliser les graphismes : utiliser une image pour l'oiseau, améliorer le dessin des tuyaux, ajouter un fond qui défile doucement...
- Créer plusieurs oiseaux pour un mode Battle Royale !
- Introduire des zones avec une gravité différente, des tuyaux plus étroits ou plus rapides.
Laissez libre cours à votre imagination et amusez-vous !