Passons désormais au troisème chapitre de ce tuto / cours de SNT, consacré à la découverte de Pygame en Python ! 😃

   Pour cette nouvelle étape, nous allons animer notre sprite (Il aura ainsi une bien meilleure tête...) ! 🤩

   Pour ce faire, au lieu d'afficher toute notre feuille de sprite / spritesheet : "rabidja.png" (qui reste toujours dans le dossier "graphics"), nous allons la découper en rectangles, appelés frames, et on va ensuite faire défiler ces frames avec un compteur (timer) comme pour un vrai dessin animé ! 😎

  

 

rabidja.png

  

   Ainsi, si on regarde notre spritesheet, on remarque que les dessins n'ont pas été agencés n'importe comment. On trouve ainsi 5 lignes, chacune correspondant à une animation différente ☺️ :

  1. La première correspond à l'état Idle, c'est-à-dire quand Rabidja ne fait rien. On remarque qu'il y a 8 frames qui se mettent en boucle.
  2. La deuxième est similaire mais correspond à la marche / walk.
  3. La troisième correspond au saut / jump et se limite à 2 frames.
  4. La quatrième que nous n'utiliserons pas dans ce tuto (mais que vous retrouverez dans les Big Tuto SDL 2 / SFML 2) correspond au double saut / double jump.
  5. La cinquième ne servira pas non plus ici et correspond à la mort / death. (Oh non ! 😱).

   La technique va donc être de découper notre feuille en rectangles de 50 x 40 pixels (la taille de notre sprite) avec une formule mathématique très basique :

x = N° de la frame x PLAYER_WIDTH (= largeur du sprite soit 40 pixels)

y = Etat du joueur (Idle/walk/jump) x PLAYER_HEIGHTH (= hauteur du sprite soit 50 pixels).

   Ainsi, si on est Idle, y va valoir 0 (0 x 50), si on marche (walk), y va valoir 50 (1 x 50), et si on saute (jump), y va valoir 100 (2 x 50) puisqu'on aura donné les valeurs 0, 1 et 2 aux constantes Idle, walk et jump.

   Pour la frame, c'est pareil avec x, où on va multiplier la valeur de la frame par la largeur du sprite.

   Ainsi, frame 0, x = 0, frame 1, x = 40, frame 2, x = 2 x 40 = 80 et ainsi de suite. Il faudra juste faire attention au saut qui se limite à deux frames (mais on verra ça plus tard ! 😋).

   Maintenant qu'on a la théorie, passons à la pratique ! 😅

  On va reprendre le projet précédent. Rappelez-vous qu'à chaque fois que vous voulez compiler et lancer le programme avec la flèche verte, il faut le faire dans le main, sinon il ne se passera rien !!! 😨

   Passons maintenant à la mise à jour du code source du fichier Constantes.py ! 🤪

   Comme d'habitude recopiez / modifiez les passages qui ne sont pas grisés. 😆

 

 

Fichier : Constantes.py

 

# Créé par Jay81, le 16/06/2024 en Python 3.7

"""Constantes du jeu"""

# Paramètres de la fenêtre
LARGEUR = 640
HAUTEUR = 360

# Personnalisation de la fenêtre
TITRE = "Rabidja"
ICONE = ""

# Listes des images du jeu (graphics)
BACKGROUND = "graphics/background.png"
SPRITE_JOUEUR = "graphics/rabidja.png"

# Taille du sprite du jouer
PLAYER_HEIGHTH = 50
PLAYER_WIDTH = 40

# Machine à états
DROITE = 1
GAUCHE = 2

IDLE = 0
WALK = 1
JUMP = 2
DOUBLEJUMP = 3
DEAD = 4

# Timer pour l'animation
TIMER = 4

 

   Bon, il n'y a pas grand chose de bien compliqué dans ces constantes. On commence par rentrer la taille de notre sprite (comme ça, si on en change pour mettre Nounouille la Super Grenouille 👽, on n'aura pas à changer ces valeurs dans TOUT le code 😜), et on met ensuite à jour notre machine à états, comme on l'a théorisée ci-dessus (on rentre y compris la mort et le double jump, au cas où on voudrait poursuivre ce tuto plus tard 😉).

   Enfin, on rentre un compte à rebours (timer) pour notre animation. C'est-à-dire qu'on va attendre 4 fps / 60 (images par seconde) avant de changer de frame. Vous pourrez vous amuser à changer la valeur de ce timer plus tard pour accélérer ou ralentir la vitesse de l'animation. 😎

   Passons maintenant au Main (programme principal). Idem, recopiez / modifiez les passages qui ne sont pas grisés. 😀

 

Fichier : Main.py

 

# Créé par Jay81, le 16/06/2024 en Python 3.7

# Import de pygame
import pygame
from pygame.locals import *

#Import des constantes et classes du jeu
from Constantes import *
from Player import *

#Initialisation de pygame
pygame.init()
clock = pygame.time.Clock()

# Ouverture de la fenêtre de jeu en résolution 640 x 360 pixels
fenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))

#Titre
pygame.display.set_caption(TITRE)

#Chargement du fond d'écran (background)
fond = pygame.image.load(BACKGROUND).convert()

#Création du joueur
player = Player()

# Boucle principale du jeu
continuer = True
while continuer :
    # On teste les événements
    for event in pygame.event.get():
        # Si on appuie sur quitter, on ferme le jeu
        if event.type == QUIT:
            continuer = False

    # On affiche le fond d'écran (background)
    fenetre.blit(fond,(0,0))

    #On met à jour le joueur
    player.update()

    # On affiche le sprite
    player.draw(fenetre)

    #On rafraichit l'écran
    pygame.display.update()

    clock.tick(60)  # limite les FPS à 60

pygame.quit()

   

 

   Etudions maintenant les ajouts au code. 😉

   D'abord, on va créer une horloge (clock) en utilisant pygame. Celle-ci nous permettra de gérer le nombre d'images par seconde pour que notre jeu ne tourne ni trop vite, ni trop lentement. 🤪

 

clock = pygame.time.Clock()

   

   Ensuite, dans notre boucle infinie, on va faire deux nouveaux appels à notre class Player() en lui demandant de mettre à jour l'animation de notre joueur (update()) puis de le dessiner (draw()). On verra l'implémentation de ces deux méthodes quand on mettra à jour le fichier Player.py. 😉

 

    #On met à jour le joueur
    player.update()

    # On affiche le sprite
    player.draw(fenetre)

   

   Enfin, à la fin de chaque boucle, on fait appel à notre horloge (clock) définie ci-dessus, pour nous limiter à 60 fps (frames ou images par seconde). Comme vous pouvez le voir, c'est très simple car Pygame gère tout le code à notre place ! 😇

 

clock.tick(60)  # limite les FPS à 60

   

   Et voilà ! Passons maintenant au nerf de la guerre, là où on va trouver le plus de changements : Player.py. Là encore, recopiez / modifiez les passages qui ne sont pas grisés. 😀

 

Fichier : Player.py

    

# Créé par Jay81, le 16/06/2024 en Python 3.7

# Import de pygame
import pygame
from pygame.locals import *

#Import des constantes et classes du jeu
from Constantes import *


"""Classe permettant de créer un personnage"""
class Player:

    def __init__(self):
         # Chargement du fichier du sprite
         self.sprite = pygame.image.load(SPRITE_JOUEUR).convert_alpha()

         # Coordonnées du sprite
         self.x = 0
         self.y = HAUTEUR - PLAYER_HEIGHTH - 40

         # Direction du sprite
         self.direction = DROITE

         # Animation
         self.frame = 0
         self.timer = TIMER
         self.state = IDLE
         self.maxframes = 7


    # Mise à jour du sprite
    def update(self):

         # On gère le timer (compte à rebours pour faire défiler l'animation)
         if self.timer < 0:
             if self.frame < self.maxframes:
                  self.frame += 1
             else:
                  self.frame = 0
             self.timer = TIMER
         else:
            self.timer -= 1


    # On dessine le sprite du joueur
    def draw (self, surface):
         surface.blit(self.sprite, (self.x, self.y), 
(self.frame * PLAYER_WIDTH,self.state * PLAYER_HEIGHTH,PLAYER_WIDTH,PLAYER_HEIGHTH))

   

   Analysons maintenant ces ajouts plus en détails ! 🤓

   D'abord, on va changer l'ordonnée y où on va afficher / blitter notre lapin maléfique ! 👺 En effet, on avait mis 0 avant, mais là, il se retrouverait dans le ciel, ce qui n'est pas terrible... 😿

   Alors, on va le blitter au sol en ajoutant à y la HAUTEUR de la fenêtre moins la hauteur de notre perso, moins encore 40 pixels. Bien entendu, cette valeur a été définie pour coller à notre background / fond d'écran et vous pouvez la changer pour tester. 😁

 

self.y = HAUTEUR - PLAYER_HEIGHTH - 40

   

   Ensuite, on va mettre en place les variables pour animer notre sprite, comme dans notre théorie ci-dessus. On va créer frame pour savoir quelle frame (image) on doit afficher. On va aussi créer maxframes et lui donner la valeur 7, comme ça, en partant de 0, on se limite à 8 frames (oui, oui, si vous comptez de 0 à 7, ça fait 8, vous pouvez tester sur vos doigts ! 🤣). Ensuite, on crée notre compte à rebours / timer pour savoir quand changer de frame et enfin on donne la valeur Idle à notre variable state (état), parce que par défaut, notre personnage va commencer en étant statique et en regardant à droite (comme dans la plupart des jeux vidéo... 😜)

 

         # Animation
         self.frame = 0
         self.timer = TIMER
         self.state = IDLE
         self.maxframes = 7

   

   C'est maintenant, que ça va (un peu) se compliquer. 😅

   On va céer une fonction update() (= mise à jour - vous allez devenir des cracks en anglais ! 🧐) qui va mettre à jour l'animation de notre perso. Plus tard, elle pourra aussi gérer ses déplacements, mais on verra ça au chapitre prochain 😜.

   En gros, l'idée, c'est qu'à chaque tour de boucle, on va enlever 1 à notre timer (qui vaut 4 au départ, mais vous pourrez le modifier dans les Constantes 🙂). On teste ensuite, pour voir s'il vaut 0 ou moins. Dans ce cas, le compte à rebours est écoulé et on augmente notre frame SAUF si elle est à la frame max (7). Si c'est le cas, on retourne alors à la frame 0. Dans tous les cas, on réinitialise notre timer et on repart pour un tour !

   Normalement, ça devrait tourner comme une horloge. 🤩

 

    # Mise à jour du sprite
    def update(self):

         # On gère le timer (compte à rebours pour faire défiler l'animation)
         if self.timer < 0:
             if self.frame < self.maxframes:
                  self.frame += 1
             else:
                  self.frame = 0
             self.timer = TIMER
         else:
            self.timer -= 1

   

   Voilà, il ne nous reste plus qu'à afficher notre sprite aux bonnes coordonnées, comme dans la théorie vue ci-dessus (c'est le même calcul mais en langage Python). ☺️

 

    # On dessine le sprite du joueur
    def draw (self, surface):
         surface.blit(self.sprite, (self.x, self.y), 
(self.frame * PLAYER_WIDTH,self.state * PLAYER_HEIGHTH,PLAYER_WIDTH,PLAYER_HEIGHTH))

   

   Et voilà, si vous appuyez sur la flèche verte dans le fichier Main.py, vous verrez maintenant Rabidja s'animer sous vos yeux ébahis ! Vous pouvez jouer avec la vitesse du timer et les coordonnées de blit du sprite pour tester un peu plus. ☺️

    

  

   A bientôt pour le chapitre 4 ! 😄

    

   

This site uses cookies to enable you to log in. We do not store or sell any personal data. By continuing to use this website, you agree to their use. Thanks!