TD3 : Aquarium

Ce TD a pour objectif de présenter :

  • La gestion des ressources

  • L’utilisation des sprites

  • La gestion de la profondeur

Mise en place

Téléchargez le projet Aquarium.zip et dézippez-le. Vous remarquez la présence d’un répertoire data contenant les ressources graphiques :

../_images/data.png

Ouvrez ensuite le fichier aquarium.py et lancez-le :

../_images/demo1.gif

Le projet est incomplet. Quelques remarques :

  • L’écran de l’aquarium s’avère très petit

  • Le poisson est entouré d’un rectangle bleu étrange

  • Le poisson fait demi-tour sans changer d’orientation

  • Il sort de l’écran par la droite sans jamais revenir.

Notions clefs

Sprite

Nous avons dessiné des formes géométriques (cercle,rectangle) dans Pong. Mais maintenant, nous voulons avoir un décor plus sympathique. Pour cela, nous utilisons des images stockées sous forme de fichiers PNG ou BMP. Nous n’utilisons pas le format JPG car il dégrade l’image et crée des imperfections sur le bord des objets ce qui a tendance à se remarquer dans un jeu 2D. Une image utilisée dans un jeu pour représenter un personnage s’appelle un « sprite », traduit par « lutin » en français. La librairie Pygame crée un sprite à partir d’un fichier image avec la fonction pygame.image.load(…).

Connaître la résolution d’une image

Faîtes un clic droit sur l’image qui vous intéresse et choisissez propriétés :

../_images/size.png

Valeur Rouge,Vert,Bleu d’une couleur

En infographie, chaque couleur se décrit à partir d’un triplet de valeurs : R(ouge), V(ert) et B(leu) ou RGB en anglais. Chaque valeur varie entre 0 et 255, soit un total de 16 millions (=256^3) de couleurs possibles, ce qui est le standard actuellement sur nos écrans.

La valeur 0 code l’absence de lumière. Ainsi (0,0,0) représente le noir et (255,255,255) représente le blanc. Une couleur grise sera de la forme (x,x,x) où les trois valeurs sont identiques. Ainsi un gris moyen a pour valeurs (128,128,128). Le rouge pur a pour valeur (255,0,0). Même raisonnement pour le vert pur (0,255,0) et le bleu pur (0,0,255).

La superposition d’une lumière rouge et d’une lumière verte donne du jaune (0,255,255) car nous superposons des couleurs en synthèse additive. Dans ce modèle, la couleur se comporte comme de l’énergie : plusieurs sources de lumière se cumulent pour donner une nouvelle couleur plus claire. Ainsi, l’addition du Rouge, du Vert et du Bleu donne du blanc. Dans cette logique, on peut considérer que le rouge (200,0,0) est deux fois plus lumineux que le rouge (100,0,0).

Il existe de nombreuses applications qui donnent les composantes RVB associée à une couleur : Convertisseur Couleur > RVB.

Gestion de la profondeur par couche

Nous utilisons des sprites 2D, mais cela ne nous empêche pas de « simuler » un effet de profondeur. Pour cela, nous allons utiliser des couches (layers). Dans une couche, tous les éléments sont sur un même plan. Pour simuler la profondeur, nous empilons plusieurs couches. Le couche la plus basse est dessinée en premier et la couche la plus haute correspond à la couche dessinée en dernier. Le résultat correspond donc à ce que l’on verrait en empilant des calques sur lesquels se trouvent des dessins.

../_images/couches.png

Ainsi dans les jeux 2D, on trouve l’empilement suivant :

  • Fond : ciel - montagnes - nuages

  • Décors : maisons / bâtiments

  • Décoration : petits objets / oiseaux

  • Personnages / Bonus

  • Informations (HUD : head up display) : scores / points de vie / argent…

Dans les jeux modernes, les applications comme Unity utilise la carte GPU pour accélérer leur performance. Cependant, en vue orthographique, ces applications sont obligées d’avoir une gestion des couches pour savoir dans quel ordre seront affichés les éléments graphiques.

To-do List

Etape 1 : Les poissons

  • Faites en sorte que la taille de la fenêtre du jeu corresponde à la taille du fichier image fond.png

  • Le poisson vert une fois qu’il atteint les ¾ de l’aquarium doit changer de direction et se déplacer vers la gauche (rebond).

  • Le sprite (l’image) du poisson inclut un fond qui doit disparaître à l’affichage.

    • Ouvrez la documentation de PyGame : https://www.pygame.org/docs/ref/surface.html

    • Recherchez la fonction qui permet de fixer la colorkey d’une image (CTRL-F rechercher peut vous aider).

    • Pour connaître les valeurs RGB de la couleur de fond, on peut lire la valeur du pixel à la coordonnée (0,0) généralement non utilisée par le sprite. Ainsi on pourra écrire : Couleur_fond = monSpritePoisson.get_at((0,0)).

    • Utilisez cette fonction sur le sprite du poisson en écrivant : monSpritePoisson.XXX( ??? )XXX désigne le nom de la fonction à trouver et ( ??? ) désigne le code RVB de la couleur de fond.

    • Voici ce que vous devez obtenir :

../_images/transparence.png
  • Comme notre poisson fait des allers-retours de gauche à droite, orientez son nez dans son sens de déplacement.

    ../_images/direction.png
    • Consultez la documentation à cette page : https://www.pygame.org/docs/ref/transform.html

    • Examinez la première fonction dans la liste. Elle permet de faire une symétrie gauche/droite d’un sprite. Attention, elle ne modifie pas l’image, elle calcule une nouvelle image et la retourne. Elle prend un booléen en paramètre, attention à son rôle.

    • Pour gérer l’orientation, vous devriez obtenir une ligne de la forme :

      • SpritePoissonDroit = pygame.transform.XXXXX(SpritePoissonGauche, ??? , ???)

  • Créez un deuxième poisson. Vous pourrez vous inspirer du code du précédent. Son parcours doit être différent du premier.

Etape 2 : Les plantes

  • Disposez une plante dans le décor

    • Chargez une image de plante pour obtenir un nouveau sprite (fonction load utilisée dans le source).

    • La taille de la plante est un peu grande ! Nous allons la réduire en écrivant :

      • pygame.transform.scale(IMAGE, (largeur, hauteur)) pour la réduire.

Etape 3 : Gestion de la profondeur

Nous allons maintenant gérer les différentes couches d’affichage. Voici un exemple d’empilement :

../_images/stack.png

Si l’on crée une fonction par couche, on va alors trouver dans la boucle de jeu while, la structure suivante :

screen.blit(fond,(0,0))
DessineCouche1()
DessineCouche2()
DessineCouche3()
DessineCouche4()

Etape 4 : Finitions

Complétez votre aquarium pour le rendre le plus joli possible :

  • Au moins trois poissons différents

  • Des poissons de tailles différentes

  • Toutes les plantes fournies

  • Tous les décors fournis

Avertissement

Vous devez faire en sorte qu’au moins un poisson passe au moins devant un élément du décor et au moins derrière un autre.