Pygame - TP 1#

Logo Pygame

Introduction#

Flappy Bird est un jeu vidéo mobile développé en 2013 au Vietnam par Hà Đông Nguyễn . Malgré son gameplay et son apparence très simple, ce jeu se hissera, en janvier 2014, à la première place des téléchargements de l'App Store et du Play Store. Grâce aux publicités intégrées, le développeur touchait jusqu'à 50'000$ par jour. De nombreuses controverses ont entouré Flappy Bird, notamment des accusations de plagiat avec ses tuyaux ressemblant étrangements à ceux des jeux Super Mario Bros. Hà Đông finit même par déclarer sur Twitter que ce jeu lui avait "ruiné sa vie".

Le but de ce TP sera de s'approprier les concepts de Pygame en redéveloppant notre propre version de Flappy Bird. Pour bien comprendre le concept de ce jeu, vous pouvez vous rendre sur flappybird.io pour en faire 2-3 parties.

Vous disposez des 3 images ci-dessous pour votre développement.

Oiseau

Oiseau (bird.png)#

Tuyau haut

Tuyau du haut (tuyau_haut.png)#

Tuyau bas

Tuyau du bas (tuyau_bas.png)#

Objectifs et rendu#

Pour terminer ce TP vous devez :

  1. Suivre les étapes 1-10 ci-dessous afin d'obtenir une première version jouable

  2. Effectuer l'étape Personnalisation afin d'ajouter au moins un élément spécial au jeu

  3. A la fin du TP, dans tous les cas, déposer votre code final du Flappy Bird ici.

Ces rendus comptent à faible coefficient dans votre moyenne d'informatique. Il est donc impératif que votre code soit votre propre production. Cela signifie que vous ne pouvez pas rendre un code pareil à celui d'un collègue, et que l'utilisation de l'IA est strictement interdite. Si vous utilisez des notions de Python autres que celles vues en cours, vous devez m'en informer avant le rendu. Tout manquement à ces règles entraine automatiquement la note de 1.

Création du jeu Flappy Bird#

Ajoutez et dessinez l'acteur Flappy Bird en haut à gauche de l'écran avec l'image bird.png.

  • Avant la boucle while True, définissez une nouvelle variable vitesse qui déterminera la vitesse verticale de l'oiseau. Si celle-ci est positive, alors l'oiseau tombera, si elle est négative, alors l'oiseau montera. Au début, la vitesse devrait être de 1.

  • Définissez une variable VITESSE_MAX qui déterminera la vitesse maximale à laquelle l'oiseau peut tomber. Vous ajusterez cette valeur par la suite, mais vous pouvez y mettre 4 pour commencer.

  • Définissez une variable ACCELERATION qui déterminera l'accélération de l'oiseau vers la Terre. Pour commencer, mettez-y la valeur 0.05.

  • Définissez une variable VITESSE_SAUT qui déterminera la vitesse à laquelle l'oiseau "sautera" quand on appuiera sur une touche. Comme un saut fait monter l'oiseau, cette valeur doit être négative. Par exemple -3.

Complétez la boucle de jeu de sorte que l'oiseau tombe constamment vers le bas en fonction de la variable vitesse. Vous pouvez utiliser pour cela la fonction move().

A chaque tour de boucle de jeu, si la vitesse de l'oiseau est plus petite que la VITESSE_MAX, augmentez la valeur de VITESSE avec l' ACCELERATION. Même si cela est peu visible, vous devriez voir votre oiseau tomber de plus en plus vite vers le bas.

  • Afin de faire "sauter" l'oiseau, commencez par ajouter la ligne de code touches_pressées = get_pressed_keys() à votre boucle de jeu. Vous récupérez ainsi la liste des touches pressées par le joueur

  • Avec un if ... in ..., contrôlez si l'utilisateur a appuyé sur la touche de saut. Vous pouvez choisir n'importe quelle touche du clavier, ou le clic gauche de la souris ("MOUSE_1").

  • Si cette condition est respectée, la vitesse doit prendre la valeur de la variable VITESSE_SAUT

Testez votre programme et ajustez les valeurs des 3 variables constantes (en majuscules) afin que l'effet de saut et de gravité vous convienne.

Nous allons maintenant faire apparaître des tuyaux toutes les 3 secondes. Pour cela, nous aurons besoin d'un Timer qui comptera le temps et permettra de déterminer le moment d'apparition des tuyaux.

  • Pour créer un nouveau Timer de 3 secondes, écrivez la ligne suivante avant la boucle de jeu : timer_tuyaux = Timer(3)

  • Afin d'instantanément démarrer ce Timer, faites suivre cette ligne de timer_tuyaux.start().

  • Dans la boucle de jeu, ajoutez un print(timer_tuyaux) afin de vérifier que vous avez bel et bien un Timer qui commence à 3s et termine à 0s.

Si le Timer s'affiche correctement, vous pouvez retirer le print()

  • Vous pouvez contrôler si le timer_tuyaux est terminé (c'est-à-dire est arrivé à 0.00s) avec if timer_tuyaux.is_finished():

  • Ajoutez cette condition dans la boucle de jeu. Lorsqu'elle est respectée, faites un print("Nouveaux tuyaux") et redémarrez le Timer avec la méthode start() utilisée précédemment.

  • Vous devriez alors voir le texte Nouveaux tuyaux apparaître toutes les 3 secondes.

Il faut maintenant retirer ce print() et faire véritablement apparaître les tuyaux. Nous n'allons pas créer une variable individuelle pour chaque tuyau, mais allons les stocker dans une liste. Pour cela :

  • Avant la boucle de jeu, créez une liste vide

  • Quand le timer est terminé, créez 2 nouveau acteurs : un tuyau_haut et un tuyau_bas avec les images adéquates. Pour le tuyau du haut, vous pouvez utiliser tuyau_haut = Actor("tuyau_haut.png", 500, -100). Vous pouvez adapter cet exemple pour le tuyau du bas.

  • Ajoutez ces 2 tuyaux à la liste avec append()

  • Pour que les tuyaux apparaissent, il faut les draw. Vous pouvez le faire dans la boucle de jeu avec la logique Pour chaque tuyau dans la liste : dessiner le tuyau.

3 secondes après le lancement, vous devriez voir une paire de tuyau apparaître.

Les tuyaux doivent se déplacer constamment vers la gauche.

  • Dans la boucle de jeu, ajoutez la logique suivante : Pour chaque tuyau dans la liste : move le tuyau vers la gauche. Vous devriez alors voir des tuyaux apparaître toutes les 3 secondes et se déplacer sans arrêt vers la gauche.

  • Quand un tuyau sort de l'écran à gauche, alors il doit être retiré de la liste. La logique est donc : *Pour chaque tuyau dans la liste : si la position horizontale du tuyau est inférieure à -100, alors retirer ce tuyau de la liste. Notez que si tuyau est un acteur, alors tuyau.get_x() permet d'accéder à sa position horizontale. Utilisez remove() pour retirer un élément d'une liste.

  • Modifiez la position initiale d'apparition des tuyaux pour qu'ils débutent en dehors de l'écran, à sa droite.

L'apparition et disparition des tuyaux devrait maintenant être parfaitement implémentée !

Le jeu doit maintenant s'arrêter lorsque Flappy Bird entre en collision avec un tuyau.

  • Créez une nouvelle variable gameover = False avant la boucle de jeu

  • Dans la boucle de jeu, ajoutez la logique suivante : Pour chaque tuyau de la liste, si le Flappy Bird entre en collision avec ce tuyau, alors gameover devient True

  • Ajoutez un ou plusieurs if gameover == False: dans votre programme de sorte à ce que l'apparition de tuyaux, leur mouvement, ainsi que le mouvement de l'oiseau n'aient plus lieu quand on perd.

A ce stade, le jeu est déjà jouable. Cependant, afin qu'il soit vraiment intéressant, certains éléments manquent. Choisissez des améliorations dans la liste ci-dessous et implémentez-en au moins une.

  • Les tuyaux n'apparaissent pas tous à la même hauteur, mais avec un décalage aléatoire en utilisant randint()

  • Un texte de gameover s'affiche quand on perd

  • Ce même texte de gameover contient un score correspondant au nombre de paires de tuyaux que l'on a esquivé

  • Appuyer sur une touche quand on a perdu permet de redémarrer le jeu

  • Le jeu ne démarre pas instantanément, mais seulement lorsqu'on appuie sur une touche

async def main():
  while True:
    await refresh((112, 196, 209))