Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site
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.
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.
Dans ce programme je vous montre comment "contourer" les formes.
#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.
Pour remplir et contourer (oui ce verbe existe !) une forme il faut donc deux instructions : une pour le remplissage et une pour le contour.
# 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.
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.
Nous allons cette fois dessiner des droites et des lignes brisées.
#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.
En bas de la fenêtre on dessine, toujours avec la fonction line() une ligne brisée rouge et un polygon vert.
Le module font permet de créer des textes ; afficher le score obtenu par exemple.
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.
#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.
Notez la FRS (fréquence de rafraichissemen par seconde) qui est de 16.
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.
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.
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.
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.
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.
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.
Attention les différents sons peuvent se chevaucher car ils sont diffusés sur le même canal.
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.
# 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.
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 !
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.
# 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.
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)
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.
#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.
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 :
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).
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.
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.
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.
... degre = 360 # dans la boucle de jeu : degre-=2 if degre ==0 : degre =360 ...
La rotation du logo se fait dans l'autre sens.
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.
# 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.