mines-ap2022-groupe-3 / agar.io

Projet d'étude pour le groupe 3 en python avancé
MIT License
2 stars 0 forks source link

Agar.io

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.

Objectifs et démarche

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...

Prérequis

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...

Code de démarrage

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 :

# 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

Astuces vs-code

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 :

Astuce #4 : si vous voulez avoir en permanence une indication sur la qualité de votre code, regardez la zone en bas à gauche

Un petit détail

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.

On écoute ce qu'il se passe

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.

Continuons

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()

Le plateau de jeu

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 ?

Un 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.

Un blop qui bouche

Nous 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.

Un blop qui suit la souris

A chaque itération on récupère la position du curseur de la souris avec pg.mouse.get_pos()

Version simple -> le blop est au meme endroit que la souris

On modifie la position du blop en fonction de la position de la souris

Version complexe -> le blop se dirige vers la souris

On peut par exemple utiliser les vecteurs de pygame.

Indice Chercher Vector2.normalize sur la doc pygame

Les fruits

Il faut maintenant faire manger notre blop. On va procéder comme suit :

# exemple de fruit en position 10, 10 sur le plateau
fruit = (10, 10)

Options

Pour les rapides, je vous invite à aborder les sujets suivants (dans l'ordre qui vous inspire le plus):

Afficher la taille du blop en titre de l'application :

Rechercher comment fonctionne pg.display.set_caption

Plusieurs fruits

Avoir plusieurs fruits de couleurs différentes.

Variables globales

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.

Ligne de commande

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.

Vitesse de réaction

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 ?

Notes à propos des environnements virtuels

Voici un très rapide résumé des commandes pour gérer ses environnements virtuels

Note à propos des dépôts git imbriqués

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