ou avec le raccourci clavier Ctrl + F9
print("Bonjour, je vais bientĂŽt programmer le jeu Pong !!!")
print() ?
ou appuyer sur Ctrl + F9
Le contenu graphique dans la fenĂȘtre d'affichage nĂ©cessite d'introduire la maniĂšre de reprĂ©senter numĂ©riquement les couleurs. La partie suivante y est consacrĂ©e.
Comment sont représentées les couleurs numériquement ?
Positionnement dans une fenĂȘtre d'affichage.

Découvrir la documentation de Pygame...
cible.py:
pygame.draw.circle() pour tracer un cercle, ou encore pygame.display.flip(). Il est possible de raccourcir ces écritures :
L'utilisation de librairies en Python...
pygame.display.quit()sys.exit() provenant du module sysdelay() de la librairie time.
Les différents types de variables que l'on peut rencontrer en programmation.
| Attributs de la balle | Nom de la variable | Type de la variable |
|---|---|---|
| Couleur | c | Liste de 3 entiers int |
| Rayon | r | int |
| Position (abscisse) | x | int |
| Position (ordonnée) | y | int |
| Déplacement (abscisse) | dx | int |
| Déplacement (ordonnée) | dy | int |
| Forme | cercle (pour l'instant cette variable ne changera pas) | --- |
Actuellement, l'image est tracĂ©e une seule fois. Il va falloir utiliser une boucle infinie modifiant le contenu de la fenĂȘtre d'affichage 30 fois par seconde. CelĂ signifie que chaque itĂ©ration de la boucle doit durer $\frac{1}{30}$-Ăšme de seconde.
Cette boucle de jeu sera créee à l'aide d'une boucle "While" qui vous est présentée ici :
Présentation de la boucle while permettant de répéter des instructions de maniÚre répétée...
dx suivant lâaxe x et dy suivant lâaxe y. Il faut donc rajouter dans la boucle infinie les instructions suivantes :
Normalement, le résultat est le suivant :
screen.fill(couleurFond)
x = x+dx et y=y+dy. Ils se résument dans le tableau suivant :
| Attribution Ă $x$ d'une valeur $a$ | Ajouter $a$ Ă une variable $x$ | Retirer $a$ Ă une variable $x$ | Multiplier une variable $x$ par $a$ | Diviser une variable $x$ par $a$ |
|---|---|---|---|---|
x=a |
x+=a |
x-=a |
x*=a |
x/=a |
L'objectif est de trouver une maniÚre de détecter lorsque la balle heurte le bord de l'écran afin de lui faire changer de sens horizontalement.
dx est positifdx est négatif
dx = dx * (-1)
|
dx *= (-1)
|
dx = -dx
|
On considÚre que la balle entre en collision avec le bord lorsque la condition suivante est vérifiée : $$x+r >width$$
On considÚre que la balle entre en collision avec le bord lorsque la condition suivante est vérifiée : $$(x-r \lt 0)$$
code source : pong1.3.py
Si l'une des conditionx+r > width OU x-r < 0 est remplie, elle rĂ©alisera la mĂȘme instruction dx = -dx.
On peut regrouper ces deux conditions en un seul test :
| supérieur | inférieur | supérieur ou égal | inférieur ou égal | égalité |
|---|---|---|---|---|
> |
< |
>= |
<= |
== |
| addition | soustraction | multiplication | division | modulo (reste de la division euclidienne) |
|---|---|---|---|---|
+ |
- |
* |
/ |
% |
| Attribution Ă $x$ d'une valeur $a$ | Ajouter $a$ Ă une variable $x$ | Retirer $a$ Ă une variable $x$ | Multiplier une variable $x$ par $a$ | Diviser une variable $x$ par $a$ |
|---|---|---|---|---|
x=a |
x+=a |
x-=a |
x*=a |
x/=a |
Le code Python est le suivant :
On souhaite maintenant ajouter des balles au jeu. Chaque balle doit avoir 5 attributs (positions [x,y], vitesses [dx, dy], rayon r). Actuellement, Si on veut afficher 10 balles, cela revient à manipuler 5*10 = 50 variables différentes.
De mĂȘme, chaque balle doit avoir des actions propres (afficher, avancer, test de collision) qu'il faudrait dupliquer.
Une mĂ©thode grossiĂšre consiste Ă copier chaque partie du code rĂ©alisĂ© pour la premiĂšre balle et Ă lâadapter pour chaque balle. Cela conduirait Ă un code trĂšs long, rĂ©pĂ©titif et fastidieux Ă lire.
Une des solutions pour remĂ©dier Ă ce problĂšme est :Il suffit pour cela dâincorporer les diffĂ©rentes lignes de codes Ă©crites pour chaque actions dans la boucle while dans des fonctions indĂ©pendantes qui peuvent ĂȘtre appelĂ©es Ă nâimporte quel instant.
De maniĂšre gĂ©nĂ©rale, une fonction peut avoir des paramĂštres en entrĂ©e et renvoyer des paramĂštres en sortie. Dans le cas prĂ©sent, dans le cas dâune balle unique, on pourra dĂ©finir les fonctions suivantes :afficher() : permet de dessiner la balleavancer() : permet de faire avancer la balletestCollision() : teste la collision sur les bordsfill(color) : donne une couleur color au fondcircle(screen, couleurBalle , [x,y], r, 0) : dessine un cercle sur l'Ă©cran Ă une position donnĂ©e, une couleur et un rayon.afficher(), nous procĂ©dons de la maniĂšre suivante :
afficher() avec le mot clé def
Le code est le suivant :
C'est normal ! CelĂ signifie que la variable x est inconnue dans la fonction afficher().
En effet, les variables utilisĂ©es dans chaque fonction ont par dĂ©faut une portĂ©e locale. CelĂ signifie qu'elle doivent ĂȘtre dĂ©clarĂ©e et utilisĂ©e Ă l'intĂ©rieur de la fonction. Elle n'existent pas en dehors de cette fonction.
Si une variable, dĂ©clarĂ©e a l'extĂ©rieur, doit ĂȘtre utilisĂ©e et modifiĂ©e Ă l'intĂ©rieur de la fonction il est nĂ©cessaire de la dĂ©clarĂ©e comme variable globale en dĂ©but de fonction comme ceci :
global x,y,dx,dytestEvenement() qui s'occupe de la dĂ©tection des Ă©vĂšnements clavier/souris et qui gĂšre l'arrĂȘt du jeu et la fermeture de la fenĂȘtre.
La solution est de dĂ©finir une liste de valeurs pour chaque attribut de la balle. Si nous manipulons N balles, chaque liste comportera N valeurs de mĂȘme type. Chaque liste est alors considĂ©rĂ© comme une variable unique qui permet de manipuler N valeurs.
Quel que soit le nombre N de balles, lâutilisation des listes permet alors de ne manipuler que 6 variables correspondant Ă chaque attribut dâune balle.
Pour découvrir les listes, nous allons utiliser la console de l'IDE :
L de 3 valeurs (qui pourrait représenter une couleur RVB)
L étant toujours en mémoire dans la console) :
[]. Taper la commande suivante :
20 car le premier élément de la liste est repéré par l'indice 0
LElle vaut maintenant ['pong is the best game!!', 10, 15].
L contient une chaĂźne de caractĂšre et deux entiers.
| Commande | Commentaire |
|---|---|
len(L) |
La fonction len renvoie la longueur de la liste L |
L.append(val) |
ajouter une valeur val aprÚs le dernier élément de la liste |
L.insert(i,val) |
ajouter une valeur val aprÚs le i-Úme élément de la liste |
L+=L0 |
concaténer la liste L0 à la liste L |
del(L[i]) |
retirer le i-Úme élément de la liste L |
a=L.pop() |
retirer le dernier élément de la liste L et le stocke dans a . |
L.remove(val) |
retirer la premiĂšre occurence d'un Ă©lĂ©ment ayant la mĂȘme valeur que val . |
L.reverse() |
renverse l'ordre |
L.sort() |
réordonne les éléments de la liste |
val in L |
renvoie True si un élément de la liste vaut val , False sinon. |
val not in L |
renvoie False si un élément de la liste vaut val , True sinon. |
L
42 Ă la fin de la liste
3.141592 en 2Ăšme position de la liste (attention le "premier" est L[0])
>>> len(L)>>> L.append(42)>>> L.insert(1,3.141592)>>> del(L[2]) ou L.remove(3.141592)dx : listes des déplacements horizontaux entre deux framesdy : liste des déplacement verticaux entre deux framesx : liste des abscisses des positionsy : liste des ordonnées des positionsr : liste des rayons des ballesi de la balle sur laquelle elle s'applique. On ajoute un argument i en entrée de la fonction :
append vue précédemment dx, dy, x, y et r.
randomrandint() de la librairie random. On l'importe de la maniĂšre suivante :
valMin et valMax (compris), on utilise :
dx, dy, x, y, r ET couleurBalle
for qui permet lâexĂ©cution dâun bloc dâinstructions un certain nombre de fois, en faisant gĂ©nĂ©ralement varier un indice entre une valeur initiale et une valeur finale avec un pas dâincrĂ©mentation
i varie d'une valeur initiale i=0 Ă une valeur finale i=4 et non 5 !!.
range()
list(range(0,5)), on obtient :
range.
list(range(2,5))list(range(0,100,10))list(range(10,0,-1))N qui représente le nombre de balles. Modifier le code précédent pour afficher N balles. Testez différentes valeurs.
rx = 20 : abscisse de la raquette ry = height/2 : ordonnée de la raquette (positionnée au milieu initialement mais qui variera)dry = 5 : déplacement vertical de la raquetterh = 100 : hauteur de la raquette rw = 20 : largeur de la raquette rcolor = [255, 255, 255] : couleur de la raquette (ici blanc) pygame.draw.rect() qui s'utilise de la maniÚre suivante :
afficher_raquette() :
KEYDOWN ou QUIT ou K_UP, etc. au lieu de pygame.KEYDOWN ou pygame.QUIT ou pygame.K_UP, etc.
testEvenements() qui gĂšre l'Ă©vĂšnement "quitter la fenĂȘtre de jeu".
Si l'évÚnement vaut pygame.KEYDOWN, c'est que une touche (n'importe laquelle) a été appuyée.
testEvenement() comme ceci :
pygame.key.get_pressed() renvoie une liste représentant l'état de chaque touche du clavier : 1 pour appuyée, 0 pour relùchée.
pygame.key.get_pressed() est 273, celui de "flĂšche du bas" est 274
K_UP vaut 273 et K_DOWN vaut 274.
bouger_raquette() suivante :
bouge_raquette() afin de réaliser le déplacement souhaité.
KEYDOWN est détecté
testCollision(i) qui teste la collision de la ballei avec les bords. Il est nécessaire de faire un schéma pour bien comprendre la situation :
Pour quâil y ait collision entre la balle et la raquette, il faut que le point N de la iĂšme balle soit tangent ou traverse lĂ©gĂšrement le bord droit de la raquette. Les conditions suivantes doivent simultanĂ©ment ĂȘtre respectĂ©es :
and. Pour la i-Úme balle, cette condition logique s'écrit donc :
testCollision pour que le bord droit de la raquette se comporte comporte comme le bord droit de l'écran et fasse rebondir la balle.
Le pong réalisé est ainsi jouable. Il ne s'agit bien sûr pas d'un jeu finalisé. Il nous aura permis d'introduire toutes les notions fondamentales de programmation python ainsi que des morceaux de code réutilisables pour d'autres types de projets.
Il est possible de poursuivre et d'améliorer le jeu :
pygame.Rect est un outil que nous n'avons pas utilisé mais qui est plus adapté aux problÚmes de collision.