Première - TP Pygame - Mouvements et Collisions

Les objets de type Rect

Définir un objet de type Rect

Avec Pygame, un objet de type Rect est la représentation d'un... rectangle ! On définit un tel objet avec la syntaxe suivante :

rect = pygame.Rect(x, y, width, height)

x et y sont ses coordonnées, et width et height ses dimensions (largeur, hauteur).

Coordonnées d'un objet de type Rect

Les coordonnées x et y du rectangle correspondent à son sommet en haut à gauche. Il est possible d'accéder à d'autres coordonnées, comme celles de son centre, comme le montre le schéma suivant :

# Exemple : un rectangle de dimensions 100x200 aux coordonnées (20,20)

>>> R = pygame.Rect(20, 20, 100, 200)
>>> R.x
20
>>> R.bottom
220
>>> R.centerx
70

Déplacer un objet de type Rect

Pour déplacer notre rectangle, rien de plus facile : il suffit de donner une valeur à une des coordonnées décrites ci-dessus.

# Exemple : un rectangle de dimensions 100x200, de centre (100,300)

>>> R = pygame.Rect(0, 0, 100, 200)
>>> R.centerx = 100
>>> R.centery = 300
>>> R.x
50
>>> R.y
150
Lorsqu'une coordonnée est modifiée, les autres sont recalculées !

Afficher un objet de type Rect

Pour afficher le rectangle, on utilise la fonction pygame.draw.rect déjà rencontrée, avec la syntaxe suivante :

pygame.draw.rect(surface, color, rect)

Un rectangle qui bouge

Voici un premier code affichant un rectangle rouge s'éliognant progressivement de l'écran, jusqu'à disparaître...

import pygame

pygame.init()

W,H = 800,600
screen = pygame.display.set_mode((W, H))
clock = pygame.time.Clock()

# Création du rectangle et positionnement
R = pygame.Rect(0,0,100,200)
R.centery = H // 2

BACKGROUND_COLOR = (0,0,0)
RECT_COLOR = (255,0,0)

running = True

while running:
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill(BACKGROUND_COLOR)

    # Déplacement du rectangle d'1 pixel vers la droite
    R.x += 1

    # Affichage du rectangle
    pygame.draw.rect(screen, RECT_COLOR, R)
    
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
Même hors de l'écran, le rectangle continue d'exister pour Python !
Que faut-il modifier pour que le rectangle se déplace en diagonale ?
On peut modifier la variable y de la même manière : R.y += 1
Quelle condition permet de tester si le côté droit du rectangle est toujours visible ?
Si W désigne la largeur de l'écran comme dans le code précédent, alors on peut utiliser la condition suivante :
if R.right < W

Un rectangle qui rebondit

Pour faire rebondir le rectangle sur le côté droit, on peut utiliser le programme suivant.

import pygame

pygame.init()

W,H = 800,600
screen = pygame.display.set_mode((W, H))
clock = pygame.time.Clock()

R = pygame.Rect(0,0,100,200)
R.centery = H // 2

# Vitesses horizontale et verticale du rectangle
vx, vy = 3, 0

BACKGROUND_COLOR = (0,0,0)
RECT_COLOR = (255,0,0)

running = True

while running:
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill(BACKGROUND_COLOR)

    # Déplacement du rectangle
    R.x += vx
    R.y += vy

    # Si collision avec le bord droit, on replace le rectangle contre le bord, et on inverse sa vitesse horizontale
    if R.right >= W:
        R.right = W
        vx *= -1

    # Affichage du rectangle
    pygame.draw.rect(screen, RECT_COLOR, R)
    
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
Remarquez l'astuce pour inverser le déplacement du rectangle : on multiplie sa vitesse horizontale par -1, ce qui a pour effet de la faire passer de 3 à -3 ; le rectangle se déplace alors vers la gauche.
Modifier le programme pour que le rectangle rebondisse également sur la gauche de l'écran.
On rajoute simplement une condition à celle existant déjà :
elif R.x < 0:
    R.x = 0
    vx *= -1
Modifier le programme pour que le rectangle rebondisse également sur le haut et le bas de l'écran.
On rajoute encore des conditions.
if R.y < 0:
    R.y = 0
    vy *= -1
elif R.bottom >= H:
    R.bottom = H
    vy *= -1
Attention, il faut traiter ces conditions séparemment, car le rectangle peut très bien rebondir à gauche ET en haut...

Collisions

Reprenons le code précédent, avec la gestion des rebonds sur les bords, en rajoutant un carré bleu sur l'écran. Lorsque le rectangle est en contact avec le carré, ce dernier devient jaune.

import pygame, random

pygame.init()

W,H = 800,600
screen = pygame.display.set_mode((W, H))
clock = pygame.time.Clock()

R = pygame.Rect(0,0,100,200)
R.centery = H // 2

vx, vy = 4, 3

C = pygame.Rect(0,0,50,50) # Carré de côté 50, au centre de l'écran
C.centerx = W // 2
C.centery = H // 2


BACKGROUND_COLOR = (0,0,0)
RED = (255,0,0)
BLUE = (0,0,255)
YELLOW = (255,255,0)

running = True

while running:
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill(BACKGROUND_COLOR)

    # Déplacement du rectangle
    R.x += vx
    R.y += vy

    # Collisions avec les bords
    if R.right >= W:
        R.right = W
        vx *= -1
    elif R.left < 0:
        R.left = 0
        vx *= -1

    if R.top < 0:
        R.top = 0
        vy *= -1
    elif R.bottom >= H:
        R.bottom = H
        vy *= -1

    # Affichage du rectangle
    pygame.draw.rect(screen, RED, R)

    # Affichage du carré
    if R.colliderect(C):
        pygame.draw.rect(screen, YELLOW, C)
    else:
        pygame.draw.rect(screen, BLUE, C)
    
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
Chute de neige

On souhaite écrire un programme qui fait tomber de la neige depuis le haut de l'écran. Un flocon de neige sera représenté par un objet de type Rect, de petite dimension, et de couleur blanche. Un flocon apparaît en haut de l'écran, puis tombe verticalement, en faisant éventuellement quelques écarts à gauche et à droite...

Balle rebondissante
Le billard
Gestion de la gravité