Contrôles : touches de déplacement
Commençons par implanter le contrôleur. Le contrôleur traite les actions du joueur et enregistre des commandes dans son état. Ce sont les commandes qui seront traitées par la simulation.
On va créer un contrôleur basique, avec deux commandes :
-
Une commande
quitter
, sous forme d'un booléen valantTrue
si on doit quitter,False
sinon. -
Une commande
deplacement
, sous forme d'un vecteur indiquant dans quelle direction le joueur veut déplacer le personnage.
Pour pouvoir changer facilement les touches associées à une commande, on va les spécifier sous forme de constantes.
TOUCHE_QUITTER = pygame.K_ESCAPE
TOUCHE_HAUT = pygame.K_UP #K_UP est la flèche haut sur le clavier.
TOUCHE_BAS = pygame.K_DOWN #K_DOWN = flèche bas
TOUCHE_DROITE = pygame.K_RIGHT #K_RIGHT = flèche droite
TOUCHE_GAUCHE = pygame.K_LEFT #K_LEFT = flèche gauche
Classe Controles
On peut créer une classe pour l'état du controleur. Pour représenter un vecteur, on va utiliser la classe Vector2
du module math
de pygame, qui supporte des opérations de base (addition, soustraction, ...) qui nous seront bien pratiques par la suite. On va l'importer directement pour ne pas avoir à toujours écrire pygame.math.Vector2
.
from pygame.math import Vector2
class Controles :
def __init__(self):
self.quitter = False
self.direction = pygame.math.Vector2(0,0)
Dans la fonction d'initialisation des controles, on ajoute l'objet correspondant au gamestate :
Quitter
Dans la fonction d'opération, on regarde les évènements de la dernière frame, et on met à jour en conséquences. Commençons par la commande quitter
. A quelque détails prets, on peu reprendre le code que l'on a écrit lors de notre découverte de pygame.
def traiter_controles(etat):
for e in pygame.event.get():
if e.type == pygame.KEYDOWN:
if e.key == TOUCHE_QUITTER:
etat.controles.quitter = True
Direction
Pour la direction, elle va dépendre des touches qui sont enfoncées, et non des touches qui sont appuyées. On va donc regarder directement l'état du clavier au lieu de passer par des évènements. Pour ça, on peut utiliser la fonction get_pressed
du module key
. Cette fonction renvoie une liste de booléns. La valeur à l'indice k
indique si la touche de code k
est pressée (True
) ou non (False
).
Par exemple, pour afficher si la touche K_ESCAPE
est enfoncée, on fait :
Comme on utilise nos constantes au lieu de mettre directement les touches, ça donne :
clavier = pygame.key.get_pressed()
if clavier[TOUCHE_HAUT]:
# on veut aller en haut
if clavier[TOUCHE_BAS]:
# on veut aller en bas
if clavier[TOUCHE_DROITE]:
# on veut aller à droite
if clavier[TOUCHE_GAUCHE]:
# on veut aller à gauche
Remarquez que c'est des if
et non des elif
, parce que les quatres touches peuvent être enfoncées en même temps. Pour créer notre direction, on part d'un vecteur nul (0,0)
, et on ajoute ou retire 1.0
de manière à le faire "pointer" dans la direction choisie avec les touches.
TODO (prof) SCHEMA, parler des axes
On peut utiliser l'opérateur +=
, qui permet de faire une addition dite en place.
direction = Vector2(0, 0)
clavier = pygame.key.get_pressed()
if clavier[TOUCHE_HAUT]:
direction.y += 1.0
if clavier[TOUCHE_BAS]:
direction.y -= 1.0
if clavier[TOUCHE_DROITE]:
direction.x += 1.0
if clavier[TOUCHE_GAUCHE]:
direction.x -= 1.0
Ce qui est bien avec cette méthode, c'est que deux touche opposées s'annulent : appuyer à la fois sur haut et bas ne génère pas de déplacement.
On peut ajouter ça à notre code de controleur, sans oublier de mettre à jour l'état :
def traiter_controles(etat):
for e in pygame.event.get():
if e.type == pygame.KEYDOWN:
if e.key == TOUCHE_QUITTER:
etat.controles.quitter = True
direction = Vector2(0, 0)
clavier = pygame.key.get_pressed()
if clavier[TOUCHE_HAUT]:
direction.y += 1.0
if clavier[TOUCHE_BAS]:
direction.y -= 1.0
if clavier[TOUCHE_DROITE]:
direction.x += 1.0
if clavier[TOUCHE_GAUCHE]:
direction.x -= 1.0
etat.controles.direction = direction
Affichage en console
Pour vérifier, on va afficher la direction dans la console à chaque tour de boucle principale. Pour que les évènements clavier soient accessibles, il nous faut aussi créer une fenêtre, ce que l'on va également faire dans la fonction main
.
## les constantes vont dans la partie config, en haut du fichier
LARGEUR_FENETRE = 1280
HAUTEUR_FENETRE = 720
def main():
pygame.init()
etat = GameState()
fenetre = pygame.display.set_mode([LARGEUR_FENETRE, HAUTEUR_FENETRE])
initialiser_controles(etat)
initialiser_simulation(etat)
initialiser_rendu(etat)
clock = pygame.time.Clock()
while not etat.controles.quitter:
clock.tick(FPS)
traiter_controles(etat)
avancer_simulation(etat)
afficher_rendu(etat)
print(etat.controles.direction)
pygame.quit()
if __name__ == "__main__":
main()
En exécutant le programme, et en jouant avec les flèches directionnelles du clavier, on obtient une sortie console de ce type, qui change en fonction des touches que l'on maintient :
Vous trouverez ci-dessous le code complet de notre jeu avec son contrôleur.
Code complet
import pygame
from pygame.math import Vector2
####################
#### CONFIG ####
####################
## Général
FPS = 60
LARGEUR_FENETRE = 1280
HAUTEUR_FENETRE = 720
## Controles
TOUCHE_QUITTER = pygame.K_ESCAPE
TOUCHE_HAUT = pygame.K_UP
TOUCHE_BAS = pygame.K_DOWN
TOUCHE_DROITE = pygame.K_RIGHT
TOUCHE_GAUCHE = pygame.K_LEFT
## Simulation
## Rendu
####################
#### GENERAL ####
####################
class GameState :
def __init__(self):
self.controles = None # on met a None parce que ces attributs seront initialisés plus tard
self.simulation = None
self.rendu = None
####################
#### CONTROLEUR ####
####################
class Controles :
def __init__(self):
self.quitter = False
self.direction = Vector2(0,0)
def initialiser_controles(etat):
etat.controles = Controles()
def traiter_controles(etat):
for e in pygame.event.get():
if e.type == pygame.KEYDOWN:
if e.key == TOUCHE_QUITTER:
etat.controles.quitter = True
direction = Vector2(0, 0)
clavier = pygame.key.get_pressed()
if clavier[TOUCHE_HAUT]:
direction.y += 1.0
if clavier[TOUCHE_BAS]:
direction.y -= 1.0
if clavier[TOUCHE_DROITE]:
direction.x += 1.0
if clavier[TOUCHE_GAUCHE]:
direction.x -= 1.0
etat.controles.direction = direction
####################
#### SIMULATION ####
####################
def initialiser_simulation(etat):
pass
def avancer_simulation(etat):
pass
####################
#### RENDU ####
####################
def initialiser_rendu(etat):
pass
def afficher_rendu(etat):
pass
####################
#### MAIN ####
####################
def main():
pygame.init()
etat = GameState()
fenetre = pygame.display.set_mode([LARGEUR_FENETRE, HAUTEUR_FENETRE])
initialiser_controles(etat)
initialiser_simulation(etat)
initialiser_rendu(etat)
clock = pygame.time.Clock()
while not etat.controles.quitter:
clock.tick(FPS)
traiter_controles(etat)
avancer_simulation(etat)
afficher_rendu(etat)
print(etat.controles.direction)
pygame.quit()
if __name__ == "__main__":
main()