Ce que vous allez apprendre
Ce chapitre est consacre a la gestion des entrees utilisateur. Vous allez decouvrir la difference cruciale entre les evenements (un appui ponctuel sur une touche) et l'etat des touches (une touche maintenue enfoncee). Vous decouvrirez aussi comment utiliser la souris comme methode de controle alternative. A la fin, votre raquette bougera enfin !
Le concept
Pygame propose deux approches pour lire le clavier :
- Les evenements (
pygame.event.get()) : ils se declenchent une seule fois quand la touche est pressee ou relachee. Ideal pour les actions discretes : ouvrir un menu, mettre en pause, changer de mode. - L'etat des touches (
pygame.key.get_pressed()) : retourne un dictionnaire de booleens indiquant quelles touches sont actuellement enfoncees. Ideal pour le mouvement continu : deplacer un personnage, une raquette.
La regle d'or : utilisez les evenements pour les actions ponctuelles, et l'etat des touches pour les actions continues.
Pour la souris, pygame.mouse.get_pos() retourne la position actuelle du curseur sous forme de tuple (x, y). C'est parfait pour un controle direct et fluide de la raquette.
Etape par etape
1. Evenement pour changer de mode
On utilise un evenement KEYDOWN pour basculer entre le mode clavier et le mode souris avec la touche M. C'est une action ponctuelle : on appuie une fois, le mode change.
use_mouse = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.key == pygame.K_m:
use_mouse = not use_mouse
Si on utilisait get_pressed() pour cette action, le mode basculerait 60 fois par seconde tant que M est enfoncee, ce qui serait inutilisable.
2. Etat des touches pour le mouvement
Pour le deplacement de la raquette, on lit l'etat des touches a chaque frame. Tant que la fleche gauche est enfoncee, la raquette se deplace vers la gauche. On supporte aussi les touches A et D pour les joueurs habitues aux controles WASD.
if use_mouse:
mouse_x, _ = pygame.mouse.get_pos()
paddle_x = mouse_x - PADDLE_WIDTH // 2
else:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
paddle_x -= PADDLE_SPEED
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
paddle_x += PADDLE_SPEED
En mode souris, on centre la raquette sur le curseur en soustrayant la moitie de sa largeur. En mode clavier, on deplace la raquette de PADDLE_SPEED pixels par frame.
3. Limiter la raquette a l'ecran
Sans contrainte, la raquette pourrait sortir de l'ecran. On utilise max() et min() pour la garder dans les limites. C'est ce qu'on appelle le clamping.
# Clamp paddle to screen
paddle_x = max(0, min(paddle_x, SCREEN_WIDTH - PADDLE_WIDTH))
Cette ligne garantit que paddle_x ne sera jamais inferieur a 0 (bord gauche) ni superieur a SCREEN_WIDTH - PADDLE_WIDTH (bord droit). On soustrait PADDLE_WIDTH car paddle_x represente le bord gauche de la raquette.
4. Afficher le mode actif
On affiche le mode de controle actuel et les instructions disponibles en bas de l'ecran, pour que le joueur sache toujours comment interagir.
mode = "MOUSE" if use_mouse else "KEYBOARD"
info = font.render(
f"Mode: {mode} [M] Switch [Arrows/AD] Move [ESC] Quit",
True, (150, 150, 150)
)
screen.blit(info, (10, SCREEN_HEIGHT - 25))
Points cles a retenir
Astuce : vous pouvez combiner les deux approches. Par exemple, utilisez un evenement KEYDOWN pour tirer un projectile (une seule fois par appui) et get_pressed() pour le mouvement continu du vaisseau.
Piege courant : attention, K_LEFT n'est pas la meme chose que K_a. La premiere est une touche fleche, la seconde est la lettre A. Sur certains claviers (AZERTY), vous devrez aussi gerer K_q au lieu de K_a.
Piege courant : n'oubliez pas que PADDLE_SPEED = 8 signifie 8 pixels par frame. A 60 FPS, cela fait 480 pixels par seconde. Ajustez cette valeur pour un mouvement confortable.
Fonctions Pygame utilisees :
pygame.key.get_pressed(): etat de toutes les touches (True/False)pygame.mouse.get_pos(): position du curseur (x, y)pygame.K_LEFT,K_RIGHT, etc. : constantes des touches
Code complet
"""Brick Breaker - Chapter 4: Handling Input"""
import pygame
import sys
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FPS = 60
BG_COLOR = (20, 20, 40)
PADDLE_WIDTH = 100
PADDLE_HEIGHT = 15
PADDLE_COLOR = (200, 200, 200)
PADDLE_SPEED = 8
paddle_x = SCREEN_WIDTH // 2 - PADDLE_WIDTH // 2
paddle_y = SCREEN_HEIGHT - 40
BALL_RADIUS = 8
BALL_COLOR = (255, 255, 255)
ball_x = SCREEN_WIDTH // 2
ball_y = SCREEN_HEIGHT // 2
BRICK_ROWS = 6
BRICK_COLS = 10
BRICK_WIDTH = 70
BRICK_HEIGHT = 20
BRICK_PADDING = 5
BRICK_OFFSET_X = 30
BRICK_OFFSET_Y = 50
def rainbow_color(row, total_rows):
hue = int(360 * row / total_rows)
color = pygame.Color(0)
color.hsva = (hue, 100, 100, 100)
return (color.r, color.g, color.b)
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Brick Breaker - Chapter 4")
clock = pygame.time.Clock()
font = pygame.font.SysFont("monospace", 14)
use_mouse = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.key == pygame.K_m:
use_mouse = not use_mouse
# Input: key states (continuous) vs events (discrete)
if use_mouse:
mouse_x, _ = pygame.mouse.get_pos()
paddle_x = mouse_x - PADDLE_WIDTH // 2
else:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
paddle_x -= PADDLE_SPEED
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
paddle_x += PADDLE_SPEED
# Clamp paddle to screen
paddle_x = max(0, min(paddle_x, SCREEN_WIDTH - PADDLE_WIDTH))
screen.fill(BG_COLOR)
# Draw bricks
for row in range(BRICK_ROWS):
for col in range(BRICK_COLS):
x = BRICK_OFFSET_X + col * (BRICK_WIDTH + BRICK_PADDING)
y = BRICK_OFFSET_Y + row * (BRICK_HEIGHT + BRICK_PADDING)
color = rainbow_color(row, BRICK_ROWS)
if (row + col) % 2 == 0:
color = tuple(min(255, c + 30) for c in color)
pygame.draw.rect(screen, color, (x, y, BRICK_WIDTH, BRICK_HEIGHT))
pygame.draw.rect(screen, (255, 255, 255),
(x, y, BRICK_WIDTH, BRICK_HEIGHT), 1)
# Draw paddle
pygame.draw.rect(screen, PADDLE_COLOR,
(paddle_x, paddle_y, PADDLE_WIDTH, PADDLE_HEIGHT))
# Draw ball
pygame.draw.circle(screen, BALL_COLOR, (ball_x, ball_y), BALL_RADIUS)
# Instructions
mode = "MOUSE" if use_mouse else "KEYBOARD"
info = font.render(
f"Mode: {mode} [M] Switch [Arrows/AD] Move [ESC] Quit",
True, (150, 150, 150)
)
screen.blit(info, (10, SCREEN_HEIGHT - 25))
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
sys.exit()
Telechargement
Telecharger le code source de ce chapitre : brick-breaker-ch04.zip
