Accueil

Traduction

Tutoriel Python - sommaire

Tutoriel Python - recherche

L'auteur : Patrick Darcheville

Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site

Bibliothèque Pygame de Python - sons et gestion de la souris

Dans ce chapitre je vais présenter les modules mixer & mouse (gestion du son et de la souris).
Je vais aussi vous montrer comme créer un logiciel de dessin basique avec Pygame : l'intérêt pédagogique est la gestion de la souris.

À la racine de C: créez un nouveau dossier et nommez le "pygame2_prog". Les programmes de ce chapitre seront stockés dans ce nouveau dossier.

Compléments sur le module draw

Dans le chapitre précédent ce module a déjà été abordé ; nous avions dessiné des formes et rempli d'une couleur de fond.
Cette fois je vais vous montrer commment dessiner le contour d'une forme.

Contours de forme

Dans ce programme je vous montre comment "contourer" les formes.

Le programme (extraits)

#pygame2_test1.py
# module draw - approfondissements
import pygame
pygame.init()
blanc = ...
rouge = ...
bleu = ...
vert = ...
jaune =...
cote = 50
rayon = 30
rx = 100
ry =50
points = [(200, 200), (300, 200), (250, 300), (150, 300)] 
boucle_jeu = True
 
fenetre = pygame.display.set_mode((400,400))
pygame.display.set_caption('pygame2_test1.py')
fenetre.fill(blanc)
pygame.draw.rect(fenetre, rouge, (50,50, cote, cote),1)
pygame.draw.circle(fenetre,vert, (50,150),rayon,2)
pygame.draw.ellipse(fenetre, bleu, (50,200,rx,ry),3)
pygame.draw.polygon(fenetre,jaune,points)
pygame.draw.polygon(fenetre,vert,points,10)
pygame.display.flip()
 
while boucle_jeu :
	...
 
# fin boucle infinie
pygame.quit()

Je ne vous communique qu'un extrait du code ; à vous de compléter. Si vous avez bien compris le chapitre précédent, ça ne devrait pas vous poser problème.

Notez qu'il y a deux instructions pratiquement identiques (pygame.draw.polygone(...) :

pygame.draw.polygon(fenetre,jaune,points)
pygame.draw.polygon(fenetre,vert,points,10)

la première ligne colore le fond et la deuxième instruction dessine un contour vert de 10 pixels d'épaisseur. Donc pour dessiner un contour il faut rajouter un paramètre précisant l'épaisseur du contour.

Le rendu

approfondissement de pygame

Pour remplir et contourer (oui ce verbe existe !) une forme il faut donc deux instructions : une pour le remplissage et une pour le contour.

Des rectangles avec des coins arrondis

Le script

# coins_arrondis.py
# rectangles avec coins arrondis
 
import pygame
pygame.init()

fenetre = pygame.display.set_mode((400, 400))

# Dessiner des carrés
fenetre.fill('green')
pygame.draw.rect(fenetre, 'purple', pygame.Rect(30, 30, 60, 60), 5, 30)
pygame.draw.rect(fenetre, 'orange', pygame.Rect(100, 100, 60, 60), 0, 30)
pygame.draw.rect(fenetre, 'olive', pygame.Rect(200, 200, 60, 60), 0, 0)
pygame.draw.rect(fenetre, 'aqua', pygame.Rect(300, 300, 60, 60), 5, 0)
pygame.display.flip()

Plutôt que de désigner les couleurs par leur code RGB, je peux utiliser leur nom mais en anglais.
Le troisième argument de pygame.draw.rect() est pygame.Rect() et non pas un tuple de 4 valeurs.

Le rendu

pygame : rectangles avec coins arrondis

Les deux premières formes apparaissent sous forme de ronds (et non pas de carrés). En effet il s'agit de carrés avec coin arrondis et comme le radius (dernier argument) vaut la moitié du côté. Ils apparaissent sous forme de ronds.
Le premier "rond" est contouré et le deuxième est plein car l'avant dernier argument vaut respectivement 5 et zéro.

Les deux dernières formes sont bien des carrés car le radius est égal à zéro.

Notez aussi la syntaxe ; pygame.Rect(x,y,largeur,hauteur) est contenu dans pygame.draw.rect().
Ce qui veut dire que je dessine des formes dans des objets de type rect !
La notion d'objet de type rect sera abordée dans le prochain chapitre.

Droites et lignes brisées

Nous allons cette fois dessiner des droites et des lignes brisées.

Le programme (extrait)

#pygame2_test2.py
# dessiner lignes simples et brisées
import pygame
pygame.init()

points = [(200, 500), (300, 500), (250, 600), (150, 600)]
points2 = [(210, 510), (310, 510), (260, 610), (160, 610)]
boucle_jeu = True
 
fenetre = pygame.display.set_mode((400,700))
pygame.display.set_caption('pygame2_test2.py')
fenetre.fill('white')
pygame.draw.line(fenetre, 'black', (50,50), (350, 350),3) 
pygame.draw.line(fenetre, 'black', (50, 350), (350, 50),3)
pygame.draw.lines(fenetre, 'red', False, points,2)
pygame.draw.lines(fenetre, 'green', True, points2,2) 
pygame.display.flip()
 
while boucle_jeu :
	for event in pygame.event.get(): 
		if event.type == pygame.QUIT: 
			boucle_jeu = False
 
# fin boucle infinie
pygame.quit()

Encore une fois je ne vous commmunique que des extraits de code.
La fonction line() dessine des droites.

La fonction lines() dessine des lignes brisées.
Pour cette dernière fonction le troisième paramètre est un booléen qui précise s'il faut (ou pas) relier le premier et le dernier point. Donc si ce paramètre vaut True vous dessinez en fait le contour d'un polygone.

Le rendu

approfondissement de pygame

En bas de la fenêtre on dessine, toujours avec la fonction line() une ligne brisée rouge et un polygon vert.

La gestion du texte

Le module font permet de créer des textes ; afficher le score obtenu par exemple.

Un texte qui défile verticalement dans la fenêtre

Le texte "Règles du jeu" se déplace de haut en bas puis de bas en haut alternativement sans jamais sortir de la fenêtre.

Le code

#pygame2_test3.py
# gestion du texte
import pygameun
pygame.init() 
fenetre = pygame.display.set_mode((400,400)) 
pygame.display.set_caption("Le module font") 
blanc = (255, 255, 255)
noir = (0,0,0)
style= pygame.font.SysFont("Arial", 35, 1, 1) 
texte = style.render("Règles du jeu", 1, noir)
Y =35
delta = 2
clock = pygame.time.Clock()

boucle_jeu = True
# boucle de jeu
while boucle_jeu :
    
       for event in pygame.event.get(): 
             if event.type == pygame.QUIT: 
                   ...
       fenetre.fill(blanc)
       fenetre.blit(texte,(50,Y))
       pygame.display.flip()
       Y+=delta
       if Y>=360:
              delta = ...
       if Y <=40:
             delta = ...
       clock.tick(16)
 
# fin boucle infinie
pygame.quit()

Notez bien l'instruction style= pygame.font.SysFont("Arial", 35, 1, 1) : création d'un style de police "Arial", de taille 35px, gras et italique.
texte = style.render("Règles du jeu", 1, noir) : création du texte "Règles du jeu" utilisant le style défini dans la variable style.
fenetre.blit(texte,(50,Y)) : affichage du texte dans la fenêtre de jeu avec les coordonnées 50,Y
Pour que le texte ne sorte jamais de la fenêtre il faut que delta soit tantôt égal à +2 ou -2 afin que Y soit tantôt incrémenté ou décrémenté de 2.

Le rendu

approfondissement de pygame

Notez la FRS (fréquence de rafraichissemen par seconde) qui est de 16.

Gestion du son

Un jeu vidéo c'est en général une ambiance sonore et des effets sons par exemple lors des collisions.
Nous devons alors utiliser le module mixer de pygame pour créer et manipuler des objets audio.

Fond sonore

Je vous propose une animation avec une ambiance sonore : la musique d'Odysée de l'espace.
Vous pouvez diminuer ou augmenter le volume sonore.
Vous pouvez aussi mettre fin à l'ambiance sonore.

Le code

import pygame
#pygame2_test4.py
# ambiance sonore 
pygame.init() 
pygame.mixer.init() 
blanc =(255, 255, 255) 
fenetre = pygame.display.set_mode((500, 400)) 
fenetre.fill(blanc) 
noir = (0,0,0)
style= pygame.font.SysFont("Arial", 20, 0, 0) 
texte1 = style.render \
	("Appuyez sur la touche S pour arrêter le fond sonore ", 1, noir)
texte2 = style.render \
	("Appuyez sur UP pour augmenter le volume ", 1, noir)
texte3 = style.render \
	("Appuyez sur DOWN pour diminuer le volume ", 1, noir)
pygame.display.set_caption("jeu avec son") 
encore = True
ambiance = pygame.mixer.Sound("odyssee.mp3") 
ambiance.play(20) 
fenetre.blit(texte1,(20,50))
fenetre.blit(texte2,(20,100))
fenetre.blit(texte3,(20,150))
pygame.display.flip()

while encore: 
    for event in pygame.event.get(): 
       if event.type == pygame.QUIT: 
           encore = False 
       if event.type == pygame.KEYDOWN: 
           if event.key == pygame.K_ESCAPE: 
               encore = False 
           if event.key == pygame.K_DOWN: 
               volume = ambiance.get_volume() - 0.1
               ambiance.set_volume(volume)
               print(volume)
           if event.key == pygame.K_UP: 
               volume = ambiance.get_volume() + 0.1
               ambiance.set_volume(volume)
               print(volume)
           if event.key == pygame.K_s:
               ambiance.stop()
               print("fin ambiance sonore")
# fin boucle infinie
pygame.quit()

Dans la fenêtre on affiche les consignes au joueur sous forme de trois textes.

La fonction init() permet d’initialiser le module mixer. Elle est nécessaire pour pouvoir utiliser le module.
La fonction mixer.Sound() permet de créer un objet audio.
ambiance = pygame.mixer.Sound("odyssee.mp3") : chargement d'un fichier audio.
ambiance.play(20) : lecture du fichier audio répétée 20 fois.
Le volume de son est compris entre 1 et 0. La fonction get_volume() appliquée à l'objet audio retourne le volume courant.
La fonction set_volume() permet de faire varier la volume du son.
La fonction stop() met fin à la lecture du fichier audio.

Dans ce script certaines instructions sont écrites sur deux lignes.
Le "\" est un symbole spécial qui indique à l'interpréteur qu'il doit prendre en compte la ligne suivante.

Le rendu

approfondissement de pygame

Pour quitter la boucle de jeu vous pouvez cliquer sur le bouton X ou appuyer sur la touche ESC.

Grâce aux instruction print() vous connaissez l'intensité du volume de son.

Effets sonores

Les effets sonores sont de courts fichiers audio qui sont lus suite à un évènements.
Dans le programme qui suit il suffit d'appuyer sur les touches X,C ou V pour déclencher un son bref et à chaque fois différent.

Le code

Je ne vous communique pas les premières et dernières instructions car, si vous avez compris, vous devez les reconstituer sans peine.

...
fenetre = pygame.display.set_mode((500, 400)) 
fenetre.fill(blanc) 
pygame.display.set_caption("jeu avec effets sons") 
encore = True 
son1 = pygame.mixer.Sound("choc1.mp3") 
son2 = pygame.mixer.Sound("alarme1.mp3") 
son3 = pygame.mixer.Sound("alarme2.mp3")
noir = (0,0,0)
style= pygame.font.SysFont("Arial", 20, 0, 0) 
texte1 = style.render \
	("Appuyez sur la touche X ", 1, noir)
texte2 = style.render \
	("OU sur la touche C ", 1, noir)
texte3 = style.render \
	("OU sur la touche V ", 1, noir)

fenetre.blit(texte1,(20,50))
fenetre.blit(...)
fenetre.blit(...)
pygame.display.flip()

while encore: 
    for event in pygame.event.get(): 
       if event.type == pygame.QUIT: 
           encore = False 
       if event.type == pygame.KEYDOWN: 
           if event.key == pygame.K_ESCAPE: 
               encore = False 
           if event.key == pygame.K_x: 
               son1.play() 
...

On utilise les mêmes fonctions du module mixer que dans l'exemple précédent.
Mais cette fois le fichier audio ne doit être lu qu'une fois donc emploi de la méthode play() sans argument.

Le rendu

Attention les différents sons peuvent se chevaucher car ils sont diffusés sur le même canal.

Créer un logiciel de dessin avec Python-Pygame

Vous connaissez Paint et bien sachez que ce n'est pas difficile de réalise avec Python-pygame un programme équivalent.
Dans ce chapitre je vais aborder (mais sans approfondir) la gestion de la souris.

Récupérer la position du pointeur de la souris

Le code

# pygame2_test7.py
# évènements MOUSEBUTTONDOWN: & MOUSEBUTTONUP
import pygame, sys 
pygame.init()
dimensions = 400, 400
fenetre = pygame.display.set_mode(dimensions)
pygame.display.set_caption("gestion de la souris")
noir =(0,0,0)
blanc = (255, 255, 255)
fenetre.fill(blanc)
pygame.display.flip()
suite = True
while suite: 
 
      for event in pygame.event.get(): 
         if event.type == pygame.QUIT: 
           sys.exit()   
         if event.type == pygame.MOUSEBUTTONDOWN: 
             print(event) 
         if event.type == pygame.MOUSEBUTTONUP: 
             print(event)
...

Ce programme affiche les coordonnées X,Y du pointeur de souris lors de l'appui puis du relachement sur le bouton gauche de la souris.

Le rendu

Event(1025-MouseButtonDown {'pos': (3, 4), 'button': 1, 'touch': False, 'window': None})
Event(1026-MouseButtonUp {'pos': (3, 4), 'button': 1, 'touch': False, 'window': None})
Event(1025-MouseButtonDown {'pos': (4, 7), 'button': 1, 'touch': False, 'window': None})
Event(1026-MouseButtonUp {'pos': (401, 397), 'button': 1, 'touch': False, 'window': None})

Vous obtenez à chaque fois la position du pointeur de souris !

Logiciel de dessin - version 1

Nous allons utiliser le module pygame.mouse et plus précisément la fonction get_pos() qui retourne la position du pointeur sous forme d'un tuple.

Le code

# pygame2_test6.py
# Logiciel de dessin - version 1

import pygame, sys 
pygame.init() 
 
fenetre = pygame.display.set_mode((400,400)) 
pygame.display.set_caption("programme de dessin - version 1") 
fenetre.fill('white')
epaisseur = 2
while 1:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
             sys.exit()
       
        if event.type == pygame.MOUSEBUTTONDOWN: 
           debut_ligne = pygame.mouse.get_pos()
           print(debut_ligne)
        if event.type == pygame.MOUSEBUTTONUP:
          fin_ligne = pygame.mouse.get_pos()
          print(fin_ligne)
          pygame.draw.line(fenetre, 'black', debut_ligne, fin_ligne, epaisseur)
    pygame.display.flip()
   
# fin boucle infinie
pygame.quit()

Les instructions print() sont provisoires mais à des fins pédagogiques.

Le rendu

Essayez de dessiner un polygone. Pour chaque droite : appui sur la souris ; déplacement du pointeur toujours en appui ; relachement de l'appui : une droite se dessine en noir avec une épaisseur de 2px.

Les coordonnées successives du pointeur de souris affichées par les "print()" :

(68, 32)
(178, 32)
(178, 32)
(185, 133)
(185, 133)
(95, 153)
(95, 153)
(147, 281)
(147, 281)
(260, 204)
(260, 203)
(91, 36)
(70, 36)
(70, 36)
(90, 37)
(253, 205)

Logiciel de dessin - version 2

Dessiner c'est bien mais il faut aussi pouvoir effacer des traits qui ne vous conviennent pas. Il faut donc un mode "dessiner" mais aussi un mode "gommer".
De plus il faudrait pouvoir sauvegarder le dessin produit.

Le code

#pygame2_test8.py
# Logiciel de dessin - version 2
import pygame, sys 
pygame.init() 
 
fenetre = pygame.display.set_mode((500,500)) 
pygame.display.set_caption("programme de dessin - version 2") 
fenetre.fill('white')
couleur = 'black'
epaisseur = 2
consignes = """
Touche D pour dessiner
Touche G pour gommer
Touche S pour sauvegarder le dessin
"""

print (consignes)

while 1:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
             sys.exit()
        if event.type == pygame.KEYDOWN: 
            if event.key == pygame.K_d: 
                couleur = 'black'
                epaisseur = 2
            if event.key == pygame.K_g: 
               couleur = 'white'
               epaisseur =10
            if event.key == pygame.K_s: 
               pygame.image.save(fenetre, "dessin.png") 
        if event.type == pygame.MOUSEBUTTONDOWN: 
           debut_ligne = pygame.mouse.get_pos() 
        if event.type == pygame.MOUSEBUTTONUP:
            fin_ligne = pygame.mouse.get_pos()
            pygame.draw.line(fenetre, couleur, debut_ligne, fin_ligne, epaisseur)
        pygame.display.flip()
         
   
# fin boucle infinie
pygame.quit()

La variable "consignes" est une chaine multiligne donc délimitée par une paire de guillemets triples.

Utilisation du module pygame.image pour sauvegarder le contenu de la fenêtre sous forme d'un fichier png.

Le rendu

Dessinez un polygone de quatre côtés (le mode par défaut est "dessiner").
Puis appuyez sur la touche G pour passer en mode "gommer" ; repassez sur les traits pour les effacer p puis dessinez un triangle après avoir appuyé de nouveau sur la touche D.
Avant de cliquer sur le bouton "fermer" de la fenêtre appuyez sur la touche S ; vérifiez que le répertoire comprend désormais un PNG.
Ci-dessous j'ai dessiné un hexagone : approfondissement de pygame

Compléments

On pourrait bien sûr imaginer une version 3 du programmme de dessin. En effet la version 2 propose une seule couleur de dessin (le noir) et une seule épaisseur de trait (2px).

Les transformations

Une image insérée dans la fenêtre de jeu peut être manipulée afin de modifier son aspect d'origine.
Il faut alors utiliser le module pygame.transform.

Le programme

L'image originale (logo de la bibliothèque Pygame) fait 100 par 30.

À chaque passage dans la boucle de jeu j'affiche une rotation de l'original avec un angle de plus en plus grand.

Le code

Pour créer des symétriques il faut utiliser la fonction flip() avec trois arguments ; les deux derniers sont des booléens.
Pour modifier l'échelle il faut utiliser la fonction scale() avec trois arguments. Notez l'emploi des fonctions get_width() & get_height().
Pour simplement doubler la taille il suffit d'utilisr le raccourci scale2x()
Pour modifier la rotation il faut utiliser la fonction rotate().

Toutes les copies de l'original sont statiques donc en dehors de la boucle de jeu sauf la rotation qui doit être actualisé à chaque exécution de la boucle de jeu.

Le rendu

approfondissements de pygame

Une variante

...
degre = 360
# dans la boucle de jeu : 
degre-=2
if degre ==0 :
	degre =360
...

La rotation du logo se fait dans l'autre sens.

Premier jeu amélioré

Dans le chapitre précédent je vous ai présenté un jeu : le joueur gère le déplacement latéral du carré vert et doit éviter une collision avec le carré rouge qui balaie la fenêtre de gauche à droite.

Le code

# premier_jeu_plus.py
# version amélioré d'un jeu de collision
# je déplace le carré borduré de vert 
# et dois éviter une collision avec le carré contouré rouge
import pygame, time
pygame.init()
pygame.mixer.init() 
# paramètres
rouge = (255, 0, 0)
vert = (0,255,0)
bleu = (0, 0, 255) 
dimensions = (400,450)
cote = 50
limite = dimensions[0] - cote
vitesse = 30
remontee = 4 
# vitesse de remontée automatique du carré vert
ecart = 10 
# déplacement latéral du carré vert
compteur =  0
delta = 3 
# déplacement du carré rouge à chaque itération 
suite = True
fenetre = pygame.display.set_mode(dimensions)
pygame.display.set_caption \
	("Déplace le carré vert et évite une collision avec le carré rouge")
frequence = pygame.time.Clock()

# coordonnées de départ des carrés
XR = 200  # abcisse  du carré rouge
YR = 200  # ordonnée  du carré rouge
XV = 175 #abcisse du carré vert
YV = 400  # ordonnée  du carré vert

fond_sonore = pygame.mixer.music.load("hymne.mp3") 
pygame.mixer.music.play(10, 0.0)
choc = pygame.mixer.Sound("choc1.mp3")
blanc = (255,255,255)
style= pygame.font.SysFont("Arial", 35, 1, 1) 

#  début boucle de jeu
while suite :
   compteur+=2
   frequence.tick(vitesse)
   for event in pygame.event.get():
      # boucle de gestion d'évènements
       if event.type == pygame.QUIT: 
           suite = False
       if event.type == pygame.KEYDOWN :
            if event.key == pygame.K_RIGHT :
                XV+=ecart # déplacement à droite
            if event.key ==pygame.K_LEFT:
                XV-=ecart   # déplacement à gauche
   XR += delta
   YV -= remontee 

# le carré vert ne doit pas sortir de la fenêtre de jeu
   if YV <=0 : 
         YV = 400
         XV = 175
   if XV <=0 :
         XV = 0
   if XV >= limite:
         XV = limite
#gestion rebondissement du carré rouge
   if XR >= limite : 
       XR = limite
       delta = -3 
   elif XR <= 0: 
       XR = 0 
       delta = 3
# gestion collision entre deux carrés
   if (abs(XV-XR) < cote) and (abs(YV-YR) < cote) :
      choc.play()
      texte = style.render("Score : " + str(compteur),1, blanc)
      fenetre.blit(texte,(50,400))
      pygame.display.flip()
      time.sleep(5)
      suite = False
      # fin si
      
   fenetre.fill(bleu)          
   pygame.draw.rect(fenetre, rouge, (XR, YR, cote, cote),5)
   pygame.draw.rect(fenetre, vert, (XV, YV, cote, cote),5)
   pygame.display.flip()
# fin boucle infinie
pygame.quit()

frequence.tick(vitesse) avec vitesse valant 30. Donc si vous trouvez que ça va trop vite (ou trop lentement) jouez sur ce paramètre.
À chaque passage dans la boucle de jeu, la variable compteur est incrémentée de 2. Donc si la boucle de jeu a itéré 100 fois avant une collision votre score est de 200 !
En cas de collision il y a une pause (time.sleep(5)) pour lire le score et avant fermeture de la fenêtre de jeu.

Le rendu

approfondissements de pygame

Récupération des images et sons

Les images et sons dans un dossier compressé