Table des matières
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 > 0… seulement si le sprite descend - pour chaque plate-forme
pf,- si le sprite était au-dessus de
pfau début de son mouvement
c'est à direself.rect.bottom - self.vy ⇐ pf.rect.top - si le sprite est au-dessous du top de
pfà la fin de son mouvement
c'est à direself.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
