Outils pour utilisateurs

Outils du site


nsi:tds:jeux:plateforme:module_player

Le joueur

Principe général

Première approche

Le mouvement gauche - droite ne pose pas de problème. C'est le mouvement vertical qu'il faut travailler.

Un mouvement vertical réaliste sera obtenu grâce à trois paramètres :

  • la position $y$
  • la vitesse $v_y$
  • l'accélération de la pesanteur $g$.

Quand le joueur a les pieds sur terre, $y$ ne change pas, $v_y = 0$ et $g$ n'agit pas.

Quand le joueur saute, au début de sont saut, $v_y = V$, où $V < 0$ est une vitesse de saut à choisir pour un saut réaliste. Puis à chaque période de temps, on a : $y \leftarrow y + v_y$ et $v_y \leftarrow v_y + g$.

Ainsi quand $v_y < 0$, le sprite monte à l'écran et quand $v_y > 0$ il descend. L'action de $g$ est qu'au début du saut, le sprite monte. Puis il perd de la vitesse, atteint son sommet et se met à descendre.

def jump(self):
    """
    amorce un saut
    """
    self.vy = self.JUMP_VELOCITY

...


def update_position(self, plateformes):
    """
    Calcule la nouvelle position tenant compte de la vitesse
    courante et sans dépasser les limites
    """
    self.rect.centerx += self.vx
    self.vy += self.G #pesanteur
    self.rect.centery += self.vy
    if self.rect.centerx > self.xmax:
        self.rect.centerx = self.xmax
    elif self.rect.centerx < self.xmin:
        self.rect.centerx = self.xmin
    self.vx *= 0.2
    if abs(self.vx) < 1:
        self.vx = 0

Détection de plate-forme

Si on fait ce qui précède, les plates-formes sont ignorées et le sprite tombe aussitôt à travers le sol.

Pour résoudre ce problème, on va détecter si les pieds du joueurs ont traversé la ligne supérieure d'une plate-forme en descendant. Le personnage sera toujours considéré en chute libre. Si sa chute lui fait traverser une plate-forme, on arrête la chute.

  • si self.vy > 0seulement si le sprite descend
  • pour chaque plate-forme pf,
    • si le sprite était au-dessus de pf au début de son mouvement
      c'est à dire self.rect.bottom - self.vy ⇐ pf.rect.top
    • si le sprite est au-dessous du top de pf à la fin de son mouvement
      c'est à dire self.rect.bottom > pf.rect.top
    • dans ce cas, on ramène le sprite sur le dessus de la plate-forme

Notez que l'on fait toujours tomber le sprite. Comme on le ramène aussitôt s'il traverse la plate-forme, on ne le voit pas traverser, il semble immobile.

def update_position(self, plateformes):
    """
    plateformes: liste des plates-formes
    Calcule la nouvelle position tenant compte de la vitesse
    courante et sans dépasser les limites
    """
    self.rect.centerx += self.vx
    self.vy += self.G #pesanteur
    self.rect.centery += self.vy
    if self.rect.centerx > self.xmax:
        self.rect.centerx = self.xmax
    elif self.rect.centerx < self.xmin:
        self.rect.centerx = self.xmin
    self.vx *= 0.2
    if self.vy > 0:
        for pf in pygame.sprite.spritecollide(self, plateformes, False):
            if self.rect.bottom - self.vy <= pf.rect.top < self.rect.bottom:
                self.vy = 0
                self.rect.bottom = pf.rect.top
                break
    if abs(self.vx) < 1:
        self.vx = 0

Pas de saut dans le saut

On ne souhaite pas que le sprite puisse sauter s'il est déjà en train de sauter ou qu'il est en train de chuter. On rajoute alors une marqueur jumping qui passe à True chaque fois que le sprite saute ou tombe.

script complet

# fichier player.py
import pygame

class Player(pygame.sprite.Sprite):
    COLOR = (255, 255, 0)
    VELOCITY = 10
    JUMP_VELOCITY = -20
    HEIGHT = 50
    WIDTH  = 20
    G = 2

    def __init__(self, x0, y0, xmin, xmax):
        """
        x0, y0: position initiale du coin inférieur gauche
        xmin, xmax: valeurs à ne pas dépasser
        """
        super().__init__()
        self.image = pygame.Surface((self.WIDTH, self.HEIGHT))
        self.image.fill(self.COLOR)
        self.rect = self.image.get_rect()
        self.rect.left = x0
        self.rect.bottom = y0
        self.xmin = xmin
        self.xmax = xmax
        self.jumping = False
        self.vx = 0
        self.vy = 0

    def move_left(self):
        """
        amorce un mouvement vers la gauche
        """
        self.vx = -self.VELOCITY

    def move_right(self):
        """
        amorce un mouvement vers la droite
        """
        self.vx = self.VELOCITY

    def jump(self):
        """
        amorce un saut
        """
        if not self.jumping:
            self.vy = self.JUMP_VELOCITY
            self.jumping = True

    def update_position(self, plateformes):
        """
        plateformes: liste des plates-formes
        Calcule la nouvelle position tenant compte de la vitesse
        courante et sans dépasser les limites
        """
        self.rect.centerx += self.vx
        self.vy += self.G #pesanteur
        self.rect.centery += self.vy
        if self.rect.centerx > self.xmax:
            self.rect.centerx = self.xmax
        elif self.rect.centerx < self.xmin:
            self.rect.centerx = self.xmin
        self.vx *= 0.2
        if self.vy > 0:
            self.jumping = True
            for pf in pygame.sprite.spritecollide(self, plateformes, False):
                if self.rect.bottom - self.vy <= pf.rect.top < self.rect.bottom:
                    self.vy = 0
                    self.rect.bottom = pf.rect.top
                    self.jumping = False
                    break
        if abs(self.vx) < 1:
            self.vx = 0
        
nsi/tds/jeux/plateforme/module_player.txt · Dernière modification : de goupillwiki