Vous pouvez me contacter via Facebook pour questions & suggestions :
Page Facebook relative à mon site
Dans ce chapitre j'évoque le module time ; les surfaces ainsi que les objets de type rect.
Il est beaucoup plus simple de manipuler un objet de type rect qu'une surface.
Il est donc conseillé de convertir une surface en un objet rect.
Ne confondez pas le module pygame.time avec le module du même nom de la bibliothèque de base de Python.
le module pygame.time est essentiel pour gérer le temps dans les applications pygame.
pygame.time.wait(ms) : cette fonction suspend l'exécution du programme pendant le nombre de millisecondes spécifié en argument.
pygame.time.get_ticks() : cette fonction renvoie le temps écoulé depuis l'initialisation de Pygame en millisecondes.
pygame.time.delay(ms): cette fonction est identique à pygame.time.wait().
pygame.time.Clock() : classe permettant de gérer le temps dans une boucle de jeu.
En appliquant la méthode tick() à l'objet de type pygame.time.Clock vous fixez
le nombre d'itérations par seconde dans la boucle de jeu.
#pygame_gestion_temps.py
import pygame
pygame.init()
largeur, hauteur = 500, 500
fenetre = pygame.display.set_mode((largeur, hauteur))
pygame.display.set_caption("gestion du temps")
# création d'un objet de type pygame.time.Clock
frequence = pygame.time.Clock()
# Position initiale du carré
x, y = (0,0)
encore = 0
# -------------boucle de jeu
while encore < 80 :
fenetre.fill('ivory')
temps_ecoule = pygame.time.get_ticks()/1000
print("Temps écoulé en secondes: ", temps_ecoule)
carre = pygame.draw.rect(fenetre, 'khaki', (x, y, 50, 50))
x +=4
y+=4
encore+=1 # incrémentaton encore
frequence.tick(8)
pygame.display.flip()
# ------------------------------
# sequence exécutée une fois
pygame.time.wait(1000) # Pause de 1 seconde (1000 millisecondes)
temps_ecoule = pygame.time.get_ticks()/1000
print("Temps écoulé en secondes: ", temps_ecoule)
pygame.time.delay(1000)
temps_ecoule = pygame.time.get_ticks()/1000
print("Temps écoulé en secondes: ", temps_ecoule)
pygame.quit()
La boucle de jeu est exécutée 80 fois donc durant (80/8) 10 secondes.
Or le premier print() affiche 1.12 s ... Il se passe donc une seconde entre l'initialisation et le démarrage du script.
Temps écoulé en secondes: 1.127 Temps écoulé en secondes: 1.253 Temps écoulé en secondes: 1.38 Temps écoulé en secondes: 1.505 ... Temps écoulé en secondes: 11.053 Temps écoulé en secondes: 12.18 Temps écoulé en secondes: 13.24
Notez que l'animation démarre au bout de 8 secondes. Donc le temps d'initialisation de Pygame est relativement important ...
Ensuite le temps écoulé augmente de 1/8 de seconde environ ; ce qui est logique puisque la FPS est de 8.
#pygame_gestion_temps2.py
import pygame
from pygame.locals import *
pygame.init()
fenetre = pygame.display.set_mode((400, 400))
pygame.display.set_caption("gestion du temps")
# création d'un objet de type pygame.time.Clock
frequence = pygame.time.Clock()
encore = 0
# -----------------boucle de jeu-----------------
while encore < 21 :
for event in pygame.event.get():
if event.type == QUIT:
break
fenetre.fill('skyblue')
frequence.tick(8)
temps =frequence.get_time()
print(f"Nombre de millisecondes entre deux itérations : {temps}")
taux = frequence.get_fps()
print(f"FPS effective : {taux}")
encore+=1
pygame.display.flip()
# ---------------
pygame.quit()
L'objet de type pygame.time.Clock se nomme frequence.
Affichage dans le shell:
FPS effective : 0.0 Nombre de millisecondes entre deux itérations : 126 FPS effective : 0.0 Nombre de millisecondes entre deux itérations : 126 FPS effective : 0.0 ... Nombre de millisecondes entre deux itérations : 126 FPS effective : 7.97448205947876 Nombre de millisecondes entre deux itérations : 125 FPS effective : 7.97448205947876 Nombre de millisecondes entre deux itérations : 125 FPS effective : 7.97448205947876
Le taux de rafraichissement est d'abord de 0 puis proche de 8.
Le nombre de millisecondes entre deux itérations est de 125 ms voire 126(1/8 de seconde).
Une surface est le canevas sur lequel Pygame dessine.
Toutes les entités visuelles d’un jeu sont des surfaces.
# pygame_surfaces.py
# créer des surfaces
import pygame
pygame.init()
dimensions = (600, 600)
fenetre = pygame.display.set_mode(dimensions)
pygame.display.set_caption("les surfaces")
fenetre.fill('skyblue')
# création de surfaces
surface1 = pygame.Surface((300, 300))
surface2 = pygame.Surface((100,100))
surface1.fill('green')
surface2.fill('red')
style= pygame.font.SysFont("Arial", 35, 1, 1)
texte = style.render("Bonjour mes amis", 1, 'navy')
image = pygame.image.load("images_sons/logo.png").convert_alpha()
# dessiner les surfaces
fenetre.blit(surface1, (150, 150))
fenetre.blit(surface2,(250,250))
fenetre.blit(texte,(150,400))
fenetre.blit(image,(150,500))
pygame.display.flip()
# nature des objets
print(f"type de fenetre : {type(fenetre)}")
print(f"type de surface1 : {type(surface1)}")
print(f"type de surface2 : {type(surface2)}")
print(f"type de texte : {type(texte)}")
print(f"type de image : {type(image)}")
boucle_jeu = True
#-------------------boucle de jeu--------------
while boucle_jeu :
for event in pygame.event.get():
if event.type ==pygame.QUIT:
boucle_jeu =False
# -----------------------------------------
pygame.quit()
Il peut être intéressant de convertir des surfaces en des objets de type rect afin de simplifier la programmation du jeu.
En effet on peut appliquer à une instance de la classe Rect() de nombreuses propriétés et méthodes
Citons entre autres :
Propriétés : x,y top, left, bottom, right topleft, bottomleft, topright, bottomright midtop, midleft, midbottom, midright center, centerx, centery size, width, height Méthodes : move() colliderect()
Vous allez apprécier !
La gestion des collisions devient très simple via la méthode colliderect() applicable à des instances
de la classe Rect().
#pygame_objet_rect.py
# création d'objets de type rect à partir de surfaces.
import pygame
from pygame.locals import *
pygame.init()
X=400
Y=400
deltaB = 10
deltaR =10
deltaV =10
fenetre = pygame.display.set_mode((X,Y))
pygame.display.set_caption("objets rect")
# création de trois objets de type Rect à partir de surfaces
surface1 = pygame.Surface((40,40))
surface1.fill('blue')
sprite_bleu = surface1.get_rect() # première instance de Rect
sprite_bleu.center = (200,360)
print(f" type de surface1 : {type(surface1)}")
print(f" type de sprite_bleu : {type(sprite_bleu)}")
surface2 = pygame.Surface((40,40))
surface2.fill('ivory')
pygame.draw.circle(surface2,'red', (20,20),20)
sprite_rouge = surface2.get_rect() # deuxième instance de Rect
sprite_rouge.center = (100,100)
print(f" type de surface2 : {type(surface2)}")
print(f" type de sprite_rouge : {type(sprite_rouge)}")
surface3 = pygame.Surface((80,80))
surface3.fill('ivory')
pygame.draw.ellipse(surface3, 'green', (40,40,40,30))
sprite_vert = surface3.get_rect() # troisième instance de Rect
sprite_vert.center = (300,250)
print(f" Type de surface3 : {type(surface3)}")
print(f" Type de sprite_vert : {type(sprite_vert)}")
frequence = pygame.time.Clock()
continuer = True
#-------------------
while continuer :
for event in pygame.event.get():
if event.type == QUIT:
continuer = False
# déplacement vertical automatique de sprite_bleu
if sprite_bleu.top <=0:
deltaB = -deltaB
if sprite_bleu.bottom >=Y:
deltaB = -deltaB
sprite_bleu = sprite_bleu.move(0,deltaB)
# déplacement horizontal automatique de sprite_rouge
if sprite_rouge.left <=0:
deltaR =-deltaR
if sprite_rouge.right >=X:
deltaR = -deltaR
sprite_rouge= sprite_rouge.move(deltaR,0)
# déplacement diagonal automatique de sprite_vert
if sprite_vert.left <=0:
deltaV = -deltaV
if sprite_vert.right >=X:
deltaV = -deltaV
if sprite_vert.bottom >=Y:
deltaV = -deltaV
if sprite_vert.top <=0:
deltaV = -deltaV
sprite_vert = sprite_vert.move(deltaV,deltaV)
if sprite_bleu.colliderect(sprite_rouge):
print("Collision détectée entre carré bleu et rond rouge !")
if sprite_bleu.colliderect(sprite_vert):
print("Collision détectée entre carré bleu et ellipse verte !")
fenetre.fill('ivory')
fenetre.blit(surface1,sprite_bleu)
fenetre.blit(surface2,sprite_rouge)
fenetre.blit(surface3,sprite_vert)
pygame.display.update()
frequence.tick(8)
# fin boucle infinie
pygame.quit()
sprite_bleu = surface1.get_rect() : la méthode get_rect() crée un objet rect à partir d'une surface.
pygame.draw.circle(surface2,'red', (20,20),20) : dessiner un rond dans une surface carrée
sprite_rouge = surface2.get_rect() : créer une instance la classe Rect()
sprite_bleu.center = (200,360) : positionner un objet rect
if sprite_bleu.top <=0: application de la propriété "top" à un objet rect
if sprite_bleu.bottom >=Y: application de la propriété "bottom" à un objet rect
sprite_bleu = sprite_bleu.move(0,deltaB) : application de la méthode move() à un objet rect
if sprite_bleu.colliderect(sprite_rouge): : plus besoin de programmer les contacts entre deux objets ;
la méthode colliderect() teste le début de chevauchement de deux objets.
fenetre.blit(surface1,sprite_bleu) : chaque objet rect est lié à une surface.
Les propriétés applicables à une instance de Rect() simplifient sensiblement les tests pour savoir si l'objet de type rect touche un bord.
... Collision détectée entre carré bleu et ellipse verte ! Collision détectée entre carré bleu et ellipse verte! Collision détectée entre carré bleu et ellipse verte ! Collision détectée entre carré bleu et rond rouge ! Collision détectée entre carré bleu et rond rouge ! Collision détectée entre carré bleu et rond rouge ! ...
Je rappelle qu'une image chargée dans un programme est une surface.
Il est tout aussi utile de créer un objet rect à partir d'une surface correspondant à une image.
# pygame_images_rect.py
# images transformées en objet rect
import pygame
from pygame.locals import *
pygame.init()
largeur, hauteur = (500,500)
fenetre = pygame.display.set_mode((largeur, hauteur))
image1 = pygame.image.load("images_sons/fusee.png").convert_alpha()
image2 = pygame.image.load("images_sons/planete.png").convert_alpha()
# création d'instances de Rect() à partir d'images
fusee = image1.get_rect()
planete = image2.get_rect()
print(f"type de image1 : {type(image1)}")
print(f"type de fusee : {type(fusee)}")
print(f"type de image2 : {type(image2)}")
print(f"type de planete: {type(planete)}")
fusee.center = (largeur//2,hauteur//2)
planete.center = (largeur//2,50)
delta = 10
frequence = pygame.time.Clock()
continuer = True
#-------------boucle de jeu--------------
while continuer :
for event in pygame.event.get():
if event.type == QUIT:
continuer = False
if event.type == KEYDOWN :
if event.key == K_LEFT :
if fusee.left>=10 :
fusee= fusee.move(-10,0)
if event.key == K_RIGHT :
if fusee.right<=largeur -10 :
fusee = fusee.move(10,0)
if event.key == K_UP :
if fusee.top>= 10:
fusee = fusee.move(0,-10)
if event.key == K_DOWN :
if fusee.bottom<=hauteur -10 :
fusee = fusee.move(0,10)
# déplacement horizontal automatique de la planete
if planete.left <=0:
delta= 10
if planete.right >=largeur:
delta = -10
planete = planete.move(delta,0)
if fusee.colliderect(planete):
print("Collision !")
fenetre.fill('cyan')
fenetre.blit(image1,fusee)
fenetre.blit(image2,planete)
frequence.tick(8)
pygame.display.update()
pygame.quit()
image1 = pygame.image.load("images_sons/fusee.png").convert_alpha() : création d'une surface à partir d'une image.
fusee = image1.get_rect() : création d'un objet rect à partir d'une surface.
fusee.center = (largeur//2,hauteur//2) : position initiale du sprite "fusee".
if fusee.colliderect(planete): de nouveau emploi de la méthode colliderect() pour gérer la collision.
La shell affiche :
L'objectif du jeu : éviter des collisions du carré bleu avec les deux ronds rouges.
Le joueur peut déplacer le carré bleu à gauche ou à droite via les touches du clavier.
# jeu_video_sonorise.py
# jeu vidéo crée avec des objets rect & sonorise
import pygame
from pygame.locals import *
pygame.mixer.init()
pygame.init()
blanc =(255,255,255)
rouge = (255, 0, 0)
vert =(0,255,0)
bleu = (0,0,255)
X, Y = 400,400
fenetre = pygame.display.set_mode((X, Y))
deltaB =10
deltaR = 8
deltaV = 12
pygame.display.set_caption("Le jeu dure 60 secondes !")
fenetre.fill(blanc)
# objets audio
son1 = pygame.mixer.Sound("images_sons/crash1.mp3")
son2 = pygame.mixer.Sound("images_sons/crash2.mp3")
points = 100
frequence = pygame.time.Clock()
# créer un style de texte
style= pygame.font.SysFont("Arial", 35, 0, 0)
texte = style.render(f"Votre score : {points}", 1, 'black')
# création de trois objets de type Rect
surface1 = pygame.Surface((40,40))
surface1.fill(bleu)
sprite1 = surface1.get_rect()
sprite1.center = (200,360)
surface2 = pygame.Surface((40,40))
surface2.fill(blanc)
pygame.draw.circle(surface2,rouge, (20,20),20)
sprite2 = surface2.get_rect()
sprite2.center = (100,100)
surface3 = pygame.Surface((40,40))
surface3.fill(blanc)
pygame.draw.circle(surface3,vert, (20,20),20)
sprite3 = surface3.get_rect()
sprite3.center = (300,250)
#boucle de jeu executée 240 à raison de 8 itérations par seconde donc pendant 30 s
for compteur in range(1,480):
for event in pygame.event.get():
# déplacement latéral par clavier du carré bleu
if event.type == KEYDOWN :
if event.key == K_LEFT :
if sprite1.left>=10 :
sprite1 = sprite1.move(-10,0)
if event.key == K_RIGHT :
if sprite1.right <=390 :
sprite1 = sprite1.move(10,0)
# déplacement vertical automatique du carré bleu
if sprite1.top <=0:
deltaB= -deltaB
if sprite1.bottom >=Y:
deltaB = -deltaB
sprite1 = sprite1.move(0,deltaB)
# déplacement horizontal automatique du rond rouge
if sprite2.left <=0:
deltaR = -deltaR
if sprite2.right >=X:
deltaR = -deltaR
sprite2 = sprite2.move(deltaR,0)
# déplacement horizontal automatique du rond vert
if sprite3.left <=0:
deltaV= -deltaV
if sprite3.right >=X:
deltaV = -deltaV
sprite3 = sprite3.move(deltaV,0)
# gestion des collisions
if sprite1.colliderect(sprite2):
son1.play()
points-=5
if sprite1.colliderect(sprite3):
son2.play()
points-=5
fenetre.fill(blanc)
fenetre.blit(surface1,sprite1)
fenetre.blit(surface2,sprite2)
fenetre.blit(surface3,sprite3)
pygame.display.update()
frequence.tick(8)
#-------------------------
# bloc exécuté une fois au sortir de la boucle de jeu
if points < 0:
points = 0
texte = style.render(f"Votre score : {points}", 1, 'black')
fenetre.blit(texte,(50,350))
pygame.display.flip()
pygame.time.delay(5000) # pause de 5 s pour lire le score
pygame.quit()
Les sprites sont des objets de type rect.
Ce jeu est sonorisé.
La boucle de jeu est exécutée 480 fois grâce à un for ...
Comme la FPS (fréquence par seconde) est de 8 images par seconde cela signifie que le jeu dure 60 secondes (480 / 8).
À l'issue de cette durée il y a donc sortie de la boucle de jeu et affichage du score qui
sera de 100 si aucune collision mais qui peut être zéro ...
À chaque collision la variable points est décrémentée de 5.
On ne pas peut sortir du jeu plus tôt car le clic sur le bouton X de la fenêtre de jeu n'est plus pris en compte.