Le but de ce TP est de réaliser un petit jeu en Python basé sur le jeu : https://agar.io.
L'objectif est de vous apprendre à concevoir et réaliser un programme complet, et non de réaliser le nouveau best-seller.
Gardez ainsi en tête que votre objectif est de réaliser un programme qui marche et pas un programme parfait.
avertissement ce document n'est pas un notebook (et le code ne va pas marcher dans un notebook non plus); on peut le lire avec jupyter mais c'est sous-optimal, le mieux est le lire avec vs-code, ou en HTML statique.
Gardez en tête que votre objectif est de réaliser un programme qui marche et
pas un programme parfait.
Aussi on va commencer par se créer un dossier vierge, et l'initialiser comme un
dépôt git
(on fait comment déjà ?)
$ mkdir agario
$ cd agario
$ # et là on crée un dépôt git avec ??
Et ensuite, on va bien faire attention de committer chaque fois qu'on aura
une version qui marche
c'est-à-dire dans ce TP très guidé, un commit par
étape en gros !
Et comme ça quand on aura un bug on pourra se concentrer sur ce qui a changé depuis la version qui marchait
Enfin si vous créez votre dépôt à l'intérieur d'un autre dépôt (de cours par exemple), reportez-vous à la toute dernière section pour comprendre comment `ca fonctionne.
Mais avant de pouvoir commencer, un peu de préparation...
Ce qui suit suppose que vous avez installé Python avec conda
et que vous avez un terminal bash
fonctionnel sur votre ordinateur.
Commencez par créer et activer un environnement dédié au TP:
# on commence par créer un environnement "agario"
(base) $ conda create -n agario python=3.10
# puis on l'active
(base) $ conda activate agario
# votre terminal doit indiquer le nom d'environnement:
(agario) $
NOTE Si vous ne voyez pas, comme montré ici, le (agario)
affiché dans le prompt de bash pour vous rappeler en permanence dans quel environnement on se trouve, il vous faut taper ceci avant de relancer un terminal
$ conda init bash
Installez ensuite la dernière version du module pygame
avec pip
:
(agario) $ pip install pygame
Pour tester votre installation, vous pouvez lancer le programme d'exemple comme suit:
(agario) $ python -m pygame.examples.aliens
soyez patient lors du premier lancement, la librairie initialise des tas de choses...
Un premier code très simple est le suivant, écrivez-le dans un fichier agario.py
et lancez-le avec la commande python
:
ATTENTION je vous recommande de ne pas essayer d'exécuter ce code depuis un notebook :
pygame
n'y est pas installé;# v0 : on repeint l'écran à une période de 1 seconde
#!/usr/bin/env python
import pygame as pg
from random import randint
def main():
clock = pg.time.Clock()
# on initialise pygame et on crée une fenêtre de 640x640 pixels
pg.init()
screen = pg.display.set_mode((640, 640))
# On donne un titre à la fenetre
pg.display.set_caption("agario")
# La boucle du jeu
done = False
while not done:
clock.tick(1)
# on génère une couleur (Rouge, Vert, Bleu) au hasard
random_color = (randint(0, 255), randint(0, 255), randint(0, 255))
screen.fill(random_color)
# enfin on met à jour la fenêtre avec tous les changements
pg.display.update()
# on itère sur tous les évênements qui ont eu lieu depuis le précédent appel
# ici donc tous les évènements survenus durant la seconde précédente
for event in pg.event.get():
continue
pg.quit()
# if python says run, then we should run
if __name__ == "__main__":
main()
Vous pouvez désormais exécuter le programme avec:
(agario) $ python agario.py
Astuce #1 : il est fortement recommandé d'installer l'extension de vs-code pour Python
Astuce #2 : on a créé un environnement virtuel;
du coup il est opportun d'indiquer à vs-code qu'il faut utiliser agario
-
plutôt que base
pour cela cliquer dans la bannière du bas la zone qui indique le Python courant
Astuce #3 : une fois que c'est fait, pour lancer le programme directement depuis vs-code :
⇧ ⌘ P
Shift-Command-P (mac)⇧ ⌃ P
Shift-Control-P (windows)Astuce #4 : si vous voulez avoir en permanence une indication sur la qualité de votre code, regardez la zone en bas à gauche
Il faut savoir que c'est l'appel à pg.display.update()
qui produit réellement l'affichage.
En fait, tous les autres calculs se produisent en mémoire (c'est très rapide), mais à un moment il faut bien parler à la carte vidéo pour l'affichage, et ça c'est beaucoup plus lent (+ieurs centaines de fois plus lent).
Du coup même si ce display
reste dans l'ordre de grandeur de la milliseconde, il faut s'efforcer, pour une bonne fluidité du jeu, de n'appeler update()
que le minimum, pour nous ici une fois par itération de la boucle.
Le snippet :
# ...
# on itère sur tous les évênements qui ont eu lieu depuis le précédent appel
# ici donc tous les évènements survenus durant la seconde précédente
for event in pg.event.get():
continue
# ...
est là pour indiquer que nous écoutons ce qu'il se passe. Il est grand temps de lui indiquer des évènements de jeu à écouter.
Afin d'avoir un comportement plus "normal", nous devons instruire Pygame en lui disant comment réagir aux clicks sur le clavier ou sur la fenêtre:
# v1 : pareil mais au moins on peut sortir du programme
# avec la touche 'q', ou avec la souris en fermant la fenêtre
#!/usr/bin/env python
import pygame as pg
from random import randint
def main():
clock = pg.time.Clock()
# on initialise pygame et on crée une fenêtre de 640x640 pixels
pg.init()
screen = pg.display.set_mode((640, 640))
# On donne un titre à la fenetre
pg.display.set_caption("agario")
# La boucle du jeu
done = False
while not done:
clock.tick(1)
# on génère une couleur (Rouge, Vert, Bleu) au hasard
random_color = (randint(0, 255), randint(0, 255), randint(0, 255))
screen.fill(random_color)
# enfin on met à jour la fenêtre avec tous les changements
pg.display.update()
# on itère sur tous les évênements qui ont eu lieu depuis le précédent appel
# ici donc tous les évènements survenus durant la seconde précédente
for event in pg.event.get():
# chaque évênement à un type qui décrit la nature de l'évênement
# un type de pg.QUIT signifie que l'on a cliqué sur la "croix" de la fenêtre
if event.type == pg.QUIT:
done = True
# un type de pg.KEYDOWN signifie que l'on a appuyé une touche du clavier
elif event.type == pg.KEYDOWN:
# si la touche est "Q" on veut quitter le programme
if event.key == pg.K_q:
done = True
pg.quit()
# if python says run, then we should run
if __name__ == "__main__":
main()
Nous allons commencer par construire notre plateau de jeu ainsi:
Pour valider le bon fonctionnement de ce plateau de jeu, écrivez un programme qui dessine un grille (vous pouvez ben sûr choisir d'autres couleurs):
pour cela, vous pouvez utiliser la méthode
pg.draw.line()
qui dessine une ligne :
# les coordonnées de rectangle que l'on dessine
x1 = 100 # coordonnée x1 (colonnes) en pixels
y1 = 100 # coordonnée y1 (lignes) en pixels
x2 = 400 # coordonnée x2 (colonnes) en pixels
y2 = 200 # coordonnée y2 (lignes) en pixels
# appel à la méthode draw.line()
color = (255, 0, 0) # couleur rouge
pg.draw.line(screen, color, (x1, y1), (x2, y2))
une fois que ça marche, vous faites quoi ?
blop
L'étape suivante est de dessiner le blop
.
Pour cela nous utiliserons https://www.pygame.org/docs/ref/draw.html#pygame.draw.circle
Nous allons créer un cercle de rayon 80 pixels au centre de l'écran.
blop
qui boucheNous créons un vecteur de "direction"
direction = (1, 0)
à chaque itération de la boucle, nous pouvons déplacer le blop dans cette direction en "ajoutant" ce vecteur à la position du blop.
blop
qui suit la sourisA chaque itération on récupère la position du curseur de la souris avec pg.mouse.get_pos()
On modifie la position du blop en fonction de la position de la souris
On peut par exemple utiliser les vecteurs de pygame.
Indice Chercher Vector2.normalize
sur la doc pygame
Il faut maintenant faire manger notre blop
. On va procéder comme suit :
blop
dans une variable :# exemple de fruit en position 10, 10 sur le plateau
fruit = (10, 10)
blop
est proche du fruit alors :
Pour les rapides, je vous invite à aborder les sujets suivants (dans l'ordre qui vous inspire le plus):
Rechercher comment fonctionne pg.display.set_caption
Avoir plusieurs fruits de couleurs différentes.
De manière générale, les variables globales sont considérées comme néfastes à la réutilisabilité du code; retouchez votre code pour minimiser le nombre de variables globales.
On aimerait pouvoir passer sur la ligne de commande les paramètres du jeu; par exemple, le nombre de cases du tableau en hauteur et largeur, la taille d'une case en pixels, ...
Indice: cherchez le module argparse
dans la documentation Python.
Ralentissez le jeu à 4 images/secondes; êtes-vous satisfait de la vitesse de
réaction ? dit autrement, est-ce qu'il arrive que le blop
va trop vite ?
si oui modifiez votre code pour une bonne synchronisation
De la même façon, si vous revenez artificiellement à une image par seconde ou moins, et que vous quittez le jeu avec 'q', est-ce que ça fonctionne immédiatement ? si non, comment améliorer le code pour que ce soit plus réactif ?
Toujours à cette vitesse lente, que constatez-vous au tout début du jeu ? est-ce que c'est grave ? si on voulait vraiment le corriger (pas forcément utile en pratique hein), comment on pourrait faire ?
Voici un très rapide résumé des commandes pour gérer ses environnements virtuels
pour voir la liste
conda env list
pour entrer dans un environnement
conda activate agario
pour sortir de l'environnement
conda deactivate
pour voir dans quel environnement on se trouve (normalement vous avez ça aussi dans le prompt)
echo echo $CONDA_DEFAULT_ENV
pour créer un nouvel environnement
conda create -n un-nouveau python=3.10
(le fait de spécifier la version de Python est optionnel, mais recommandé)
pour détruire un environnement
conda env remove -n un-nouveau
remarquez comment il n'y a pas de env
pour create
, mais il en faut un pour remove
...
Si vous avez reçu ce TP depuis un dépôt git (celui de votre cours d'info), ce qu'on vous invite à faire c'est finalement de créer un dépôt git ... à l'intérieur d'un autre dépôt git.
Sachez que ça marche sans aucun souci (et en pratique on finit par avoir ce genre de tricotage avec une profondeur non triviale, 3 voire même parfois 4 dépôts les uns dans les autres)
La seule chose à savoir c'est que, lorsque vous tapez une commande git
, pour
trouver le "bon" dépôt, on utilise assez naturellement l'algo suivant:
on regarde si le dossier courant est un dépôt git, si oui on a trouvé, sinon on regarde dans le dossier parent, et ainsi de suite
Donc c'est assez simple, mais surtout au tout début, faites juste attention à ne pas ajouter vos fichiers dans le mauvais dépôt