====== 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 ''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