Tuto pyxel : Animer un personnage

Tutoriels Pyxel

Animer un personnage dans une application Pyxel
Python
NSI
Programmation
Pyxel
Nuit du code
Auteur·rice

F. LALLEMAND

Date de publication

2 septembre 2023

Objectifs du tutoriel
  • Créer une application Pyxel avec fond coloré uni ;
  • Créer un personnage qui se déplace avec les touches du clavier ;

Nous utiliserons pyxelstudio.net pour coder ce tuto.

Géométrie générale de la fenêtre

La fenêtre de jeu est un rectangle de 256 pixels de large sur 128 pixels de haut. L’origine du repère est située en haut à gauche de la fenêtre. Les coordonnées des points sont donc comprises entre 0 et 255 pour les abscisses et entre 0 et 127 pour les ordonnées.

Géométrie de la fenêtre

Géométrie de la fenêtre

Le fichier de ressource pyxres

Pour ce tuto, nous utiliserons le fichier de ressource jump_games.pyxres issu des exemples de Pyxel.

Pour ouvrir, modifier ou consulter le contenu d’un tel fichier, il faut utiliser l’éditeur de ressource de Pyxel. Pour cela, il faut d’abord charger ce fichier dans pyxelstudio : voir la page dédiée.

Editeur de ressource

Editeur de ressource

On peut voir et faire défiler l’ensemble des images du fichier de ressources dans la partie droite de l’éditeur. Dans la partie gauche, on zoome sur un carré de 16 pixels de côté, avec possibilité de modifier l’image à la souris.

Astuce utile : quand on déplace la souris sur l’image, les coordonnées du pointeur sont affichées en haut à droite de la fenêtre. Cela permet de repérer facilement les coordonnées des points.

Sous l’image se trouve la palette de couleur. Nous disposons de 16 couleurs, numérotées de 0 à 15.

Affichage du personnage et du fond coloré

Nous constatons que le dessin du personnage occupe le carré de coordonnées (0, 0) à (15, 15). Nous allons donc afficher le personnage en bas à gauche de la fenêtre, avec la commande pyxel.blt(x, y, img, u, v, w, h, [colkey]) :

  • x et y sont les coordonnées du point en haut à gauche de l’image dans la fenêtre de l’application ;
  • img est le numéro de l’image dans le fichier de ressource (ici, il n’y en a qu’une seule, numéro 0) ;
  • u et v sont les coordonnées du point en haut à gauche de l’image dans le fichier de ressource ;
  • w et h sont la largeur et la hauteur de l’image dans le fichier de ressource.
  • colkey est le numéro de la couleur que l’on souhaite rendre transparente. Si on ne souhaite pas rendre de couleur transparente, on peut ne pas renseigner ce paramètre.

Paramètres de blt

Paramètres de blt

Voici le code obtenu :

import pyxel

class App:
    def __init__(self):
        pyxel.init(256, 128, fps=30)
        # on charge le fichier de ressources
        pyxel.load("jump_game.pyxres")
        # variable définissant l'abscisse initiale du personnage
        self.x_personnage = 0
        # on lance l'application
        pyxel.run(self.update, self.draw)
        
    def update(self):
        pass

    def draw(self):
        # on efface l'écran et on remplit la fenêtre de bleu (code 12)
        pyxel.cls(12)
        # on affiche le personnage à l'abscisse x_personnage et à l'ordonnée 127 - 16
        pyxel.blt(self.x_personnage, pyxel.height - 16, 0, 0, 0, 16, 16)

App()

On obtient :

Personnage en bas à gauche

Personnage en bas à gauche

Déplacement du personnage

Nous allons maintenant faire bouger le personnage avec les touches du clavier. Pour cela, nous allons utiliser la méthode update de la classe App. Cette méthode est appelée automatiquement par Pyxel à chaque image. Nous allons donc modifier la valeur de self.x_personnage en fonction des touches du clavier qui sont pressées.

Cependant, l’abscisse du personnage doit toujours rester comprise entre 0 et 255 pour qu’il ne disparaissent pas de l’écran. Nous allons donc utiliser la fonction min pour que self.x_personnage ne puisse pas être inférieur à 0 et la fonction max pour qu’il ne puisse pas être supérieur à 255.

import pyxel

class App:
    def __init__(self):
        pyxel.init(256, 128, fps=30)
        # on charge le fichier de ressources
        pyxel.load("jump_game.pyxres")
        # variable définissant l'abscisse initiale du personnage
        self.x_personnage = 0
        # variable définissant la vitesse du personnage
        self.vitesse = 2
        # on lance l'application
        pyxel.run(self.update, self.draw)
        
    def update(self):
        if pyxel.btn(pyxel.KEY_LEFT):
            # si on appuie sur la touche gauche, on déplace le personnage vers la gauche
            self.x_personnage = max(self.x_personnage - self.vitesse, 0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            # si on appuie sur la touche droite, on déplace le personnage vers la droite
            self.x_personnage = min(self.x_personnage + self.vitesse, pyxel.width - 16)

    def draw(self):
        # on efface l'écran et on remplit la fenêtre de bleu
        pyxel.cls(12)
        # on affiche le personnage à l'abscisse x_personnage et à l'ordonnée 128 - 16
        pyxel.blt(self.x_personnage, pyxel.height - 16, 0, 0, 0, 16, 16)

App()

Remarque : nous avons également défini un attribut vitesse qui permet de modifier la vitesse de déplacement du personnage : il s’agit du nombre de pixels à ajouter, ou à retrancher, à chaque fois que l’on appuie sur une touche fléchée.

Personnage qui se déplace

Personnage qui se déplace

Animation du déplacement

Pour donner une impression d’animation lors du déplacement du personnage, on peut alterner l’affichage de deux images du personnage. Le fichier ressources contient en effet une image du personnage avec les jambes positionnées différemment, comme on peut le voir ci-dessous.

Pour ce faire, on peut utiliser la fonction pyxel.frame_count pour alterner l’affichage des deux images à chaque image. Cette fonction renvoie le nombre d’images affichées depuis le début de l’application. Dans le code ci-dessous, on a de plus défini une variable booléenne self.personnage_marche qui vaut True si le personnage est en train de marcher et False sinon (ce qui permet dans ce cas d’arrêter l’animation).

Animation du personnage

Animation du personnage
import pyxel

class App:
    def __init__(self):
        pyxel.init(256, 128, fps=30)
        # on charge le fichier de ressources
        pyxel.load("jump_game.pyxres")
        # variable définissant l'abscisse initiale du personnage
        self.x_personnage = 0
        # variable définissant la vitesse du personnage
        self.vitesse = 2
        # variable indiquant si un déplacement est en cours
        self.personnage_marche = False
        # on lance l'application
        pyxel.run(self.update, self.draw)
        
    def update(self):
        if pyxel.btn(pyxel.KEY_LEFT):
            self.x_personnage = max(self.x_personnage - self.vitesse, 0)
            self.personnage_marche = True
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.x_personnage = min(self.x_personnage + self.vitesse, pyxel.width - 16)
            self.personnage_marche = True

    def draw(self):
        # on efface l'écran et on remplit la fenêtre de bleu
        pyxel.cls(12)
        # on affiche le personnage à l'abscisse x_personnage et à l'ordonnée 128 - 16
        if self.personnage_marche:
            if pyxel.frame_count % 6 < 3:
                pyxel.blt(self.x_personnage, pyxel.height - 16, 0, 0, 0, 16, 16)
            else:
                pyxel.blt(self.x_personnage, pyxel.height - 16, 0, 16, 0, 16, 16)
            self.personnage_marche = False
        else:
            pyxel.blt(self.x_personnage, pyxel.height - 16, 0, 0, 0, 16, 16)

App()

Personnage qui se déplace

Personnage qui se déplace
Explications

frame_count est le nombre d’images affichées depuis le lancement du jeu. On calcule frame_count % 6 pour obtenir le reste de la division euclidienne de frame_count par 6. On obtient donc un nombre entre 0 et 5. On affiche le premier personnage si ce nombre est inférieur à 3 et le second sinon. On obtient donc un changement d’image toutes les 3 images.

Une dernière amélioration serait souhaitable : lorsque le personnage se déplace vers la gauche, il semble reculer. On peut modifier le code de telle façon qu’il se retourne vers la gauche et regarde toujours dans la direction où il se déplace. Pour cela, il suffit de modifier le paramètre w de la fonction pyxel.blt en lui donnant la valeur -16 lorsque le personnage se déplace vers la gauche.

On définit pour cela encore un nouvel attribut “direction” qui vaut 1 lorsque le personnage se déplace vers la droite et -1 lorsqu’il se déplace vers la gauche. On multiplie donc self.direction par 16 pour obtenir la valeur de w à donner à la fonction pyxel.blt.

import pyxel

class App:
    def __init__(self):
        pyxel.init(256, 128, fps=30)
        # on charge le fichier de ressources
        pyxel.load("jump_game.pyxres")
        # variable définissant l'abscisse initiale du personnage
        self.x_personnage = 0
        # variable définissant la vitesse du personnage
        self.vitesse = 2
        # variable indiquant si un déplacement est en cours
        self.personnage_marche = False
        # variable indiquant la direction du personnage
        self.direction = 1
        # on lance l'application
        pyxel.run(self.update, self.draw)
        
    def update(self):
        if pyxel.btn(pyxel.KEY_LEFT):
            self.x_personnage = max(self.x_personnage - self.vitesse, 0)
            self.direction = -1
            self.personnage_marche = True
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.x_personnage = min(self.x_personnage + self.vitesse, pyxel.width - 16)
            self.direction = 1
            self.personnage_marche = True

    def draw(self):
        # on efface l'écran et on remplit la fenêtre de bleu
        pyxel.cls(12)
        # on affiche le personnage à l'abscisse x_personnage et à l'ordonnée 255 - 16
        if self.personnage_marche:
            if pyxel.frame_count % 6 < 3:
                pyxel.blt(self.x_personnage, pyxel.height-16, 0, 0, 0, self.direction*16, 16)
            else:
                pyxel.blt(self.x_personnage, pyxel.height-16, 0, 16, 0, self.direction*16, 16)
            self.personnage_marche = False
        else:
            pyxel.blt(self.x_personnage, pyxel.height-16, 0, 0, 0, self.direction*16, 16)

App()

Personnage qui se déplace

Personnage qui se déplace
En conclusion

Nous avons vu dans ce tuto comment animer un personnage dans une application Pyxel en utilisant les touches du clavier. Nous avons également vu comment utiliser le fichier de ressources pour afficher une image du personnage avec les jambes positionnées différemment et ainsi donner une impression de marche. Nous avons enfin vu comment faire en sorte que le personnage regarde toujours dans la direction où il se déplace.