Rendu
Bon c'est bien rigolo, mais on veut voir quelque chose bouger à l'écran !
Rendu naïf
Préparons le moteur de rendu. La couleur du personnage sera enregistrée dans une constante.
Le moteur de rendu fait un rendu à l'écran. Pour ça, on a besoin de connaître la fenêtre crée à partir de la fonction main
. On le rajoutera en paramètre de la fonction d'initialisation:
On ajoute donc l'objet au gamestate quand on initialise :
Il nous faut modifier la fonction main
en conséquences :
fenetre = pygame.display.set_mode([LARGEUR_FENETRE, HAUTEUR_FENETRE])
initialiser_controles(etat)
initialiser_simulation(etat)
initialiser_rendu(etat, fenetre)
Finalement, quand on fait le rendu et met à jour l'affichage, il nous suffit de :
- remplir l'écran d'une couleur unie pour effacer la frame précédente
- dessiner un cercle qui représente le personnage. On peut directement passer sa position à la fonction
circle
. - appeler
display.flip()
pour répercuter les changements sur l'écran
On va définir une couleur d'arrière plan sous forme d'une constante
On définit une fonction supplémentaire pour l'affichage du personnage, que l'on appelle dans le rendu. Cette fonction supplémentaire permet de garder le code plus clair, et de différencier ce qui relève de l'affichage général et ce qui relève de l'affichage du personnage.
def rendre_personnage(etat):
ecran = etat.rendu.ecran
position = etat.simulation.personnage.position
pygame.draw.circle(ecran, COULEUR_PERSONNAGE, position, TAILLE_PERSONNAGE)
def afficher_rendu(etat):
ecran = etat.rendu.ecran
ecran.fill(COULEUR_ARRIERE_PLAN)
rendre_personnage(etat)
pygame.display.flip()
Le code complet se trouve dans le dépliant :
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
VITESSE_PERSONNAGE = 5
TAILLE_PERSONNAGE = 10
## Rendu
COULEUR_ARRIERE_PLAN = (0, 0, 0)
COULEUR_PERSONNAGE = (255, 146, 205)
####################
#### 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 ####
####################
class Personnage:
def __init__(self, position):
self.position = position
class Simulation:
def __init__(self, personnage):
self.personnage = personnage
def initialiser_simulation(etat):
pos = Vector2(LARGEUR_FENETRE/2, HAUTEUR_FENETRE/2)
p = Personnage(pos)
etat.simulation = Simulation(p)
def avancer_simulation(etat):
direction = etat.controles.direction
etat.simulation.personnage.position += direction * VITESSE_PERSONNAGE
####################
#### RENDU ####
####################
class Rendu:
def __init__(self, ecran):
self.ecran = ecran
def initialiser_rendu(etat, ecran):
etat.rendu = Rendu(ecran)
def rendre_personnage(etat):
ecran = etat.rendu.ecran
position = etat.simulation.personnage.position
pygame.draw.circle(ecran, COULEUR_PERSONNAGE, position, TAILLE_PERSONNAGE)
def afficher_rendu(etat):
ecran = etat.rendu.ecran
ecran.fill(COULEUR_ARRIERE_PLAN)
rendre_personnage(etat)
pygame.display.flip()
####################
#### 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, fenetre)
clock = pygame.time.Clock()
while not etat.controles.quitter:
clock.tick(FPS)
traiter_controles(etat)
avancer_simulation(etat)
afficher_rendu(etat)
pygame.quit()
if __name__ == "__main__":
main()
Référentiels
Si on execute le code, on le personnage se déplace bien, mais les directions haut et bas semblent inversées !
C'est parce que dans notre simulation, nous utilisons un référentiel avec axe vertical qui croit vers le "haut", alors que l'écran utilise référentiel avec un axe vertical qui croît vers le bas.
TODO (prof) schema ici omg
C'est bien plus intuitif d'avoir un axe vertical vers le "haut" dans la simulation, parce qu'en science, par exemple en Physique, on a l'habitude d'une telle représentation. Adaptons donc le rendu en transformant chaque coordonnée y
en HAUTEUR_FENETRE - y
(c'est le changement de référentiel), à l'aide d'une fonction
On modifie la fonction rendre_personnage
en conséquences :
def rendre_personnage(etat):
ecran = etat.rendu.ecran
position = etat.simulation.personnage.position
pygame.draw.circle(ecran, COULEUR_PERSONNAGE, ref_sve(position), TAILLE_PERSONNAGE)
Le code complet se trouve dans ce dépliant :
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
VITESSE_PERSONNAGE = 5
TAILLE_PERSONNAGE = 10
## Rendu
COULEUR_ARRIERE_PLAN = (0, 0, 0)
COULEUR_PERSONNAGE = (255, 146, 205)
####################
#### 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 ####
####################
class Personnage:
def __init__(self, position):
self.position = position
class Simulation:
def __init__(self, personnage):
self.personnage = personnage
def initialiser_simulation(etat):
pos = Vector2(LARGEUR_FENETRE/2, HAUTEUR_FENETRE/2)
p = Personnage(pos)
etat.simulation = Simulation(p)
def avancer_simulation(etat):
direction = etat.controles.direction
etat.simulation.personnage.position += direction * VITESSE_PERSONNAGE
####################
#### RENDU ####
####################
class Rendu:
def __init__(self, ecran):
self.ecran = ecran
def ref_sve(v):
return Vector2(v.x, HAUTEUR_FENETRE - v.y)
def initialiser_rendu(etat, ecran):
etat.rendu = Rendu(ecran)
def rendre_personnage(etat):
ecran = etat.rendu.ecran
position = etat.simulation.personnage.position
pygame.draw.circle(ecran, COULEUR_PERSONNAGE, ref_sve(position), TAILLE_PERSONNAGE)
def afficher_rendu(etat):
ecran = etat.rendu.ecran
ecran.fill(COULEUR_ARRIERE_PLAN)
rendre_personnage(etat)
pygame.display.flip()
####################
#### 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, fenetre)
clock = pygame.time.Clock()
while not etat.controles.quitter:
clock.tick(FPS)
traiter_controles(etat)
avancer_simulation(etat)
afficher_rendu(etat)
pygame.quit()
if __name__ == "__main__":
main()
Si on l'execute, le personnage se déplace bien dans les bonnes directions.
TODO (prof) AJOUTER DES LIMITES AU DEPLACEMENT !!! plutot plus tard ?