Projet Tamagotchi

Introduction

L’objectif de ce semestre est de réaliser un jeu en Python : un Tamagotchi. Le but étant de manipuler au maximum tout ce que vous avez appris au premier semestre.

Le projet sera bien évidemment noté et constituera votre seule note de contrôle continue. Il est donc à réaliser sérieusement…

Voici quelques informations sur le déroulé du projet :

  • Le projet est à faire en binôme. Les monômes ne sont pas autorisés, sauf cas exceptionnel (nombre impair d’étudiants par exemple).
  • Vous aurez 4 séances de 3h pour travailler sur votre projet. Cependant, travailler en dehors de ces séances est fortement conseillé. Les séances avec le professeur sont surtout là pour vous aider à avancer en cas de blocage.
  • La bonne réalisation du projet n’est pas le seul critère de notation, l’assiduité sera aussi évaluée, et notamment votre progression au fil des semaines. Lisez bien les critères de notation dès le début et gardez-les toujours en têtes.
  • Vous aurez deux versions à rendre de votre projet. Une version textuelle et une version graphique. La version textuelle est la plus importante dans la notation ! Préférez faire une version textuelle parfaite, que deux versions à moitié faites.
  • Si vous fournissez des graphismes réalisés par vous même, sachez que la qualité visuelle de ceux-ci n’est pas prise en compte dans la notation.

Notation

Vous aurez 3 notes dans ce projet:

  • Une note d’assiduité : Après chaque séance, vous devrez rendre un journal de bord (voir la section appropriée). Il y aura donc 4 rendus, chaque rendu compte pour 5 points de la notation, ce qui fait une note sur 20 à la 4ème séance.

  • Une note du projet textuelle:

    • Le jeu fonctionne correctement et ne bug pas : 5 points

    • Le code est propre et documenté (utilisation des commentaires pour expliquer ce qu’il fait) : 5 points

    • Toutes les fonctionnalités demandées sont réalisées : 10 points

    • Ajout personnel de fonctionnalité : 3 points

      Vous avez donc une note sur 20 + 3 points bonus pour d’éventuels ajouts non demandés.

  • Une note du projet graphique:

    • Le jeu fonctionne correctement et ne bug pas : 5 points

    • Le code est propre et documenté (utilisation des commentaires pour expliquer ce qu’il fait) : 5 points

    • Toutes les fonctionnalités demandées sont réalisées : 10 points

    • Ajout personnel de fonctionnalité : 3 points

      Vous avez donc une note sur 20 + 3 points bonus pour d’éventuels ajouts non demandés.

Le projet graphique doit reprendre quasiment tout le code du projet textuel, ainsi si le projet textuel est bien fait, il sera alors facile d’avoir une bonne note en projet graphique.

La note finale du projet est une moyenne pondérée des trois notes :

projet = (2 * assiduité + 2 * textuelle + graphique)/5

Ainsi la note graphique ne compte que pour 20% de la note !

Le journal de bord

Le journal de bord est un document que vous devez réaliser afin de réaliser le suivi de votre projet. Ce dernier est à compléter après chaque séance. Vous devez rendre votre journal de bord au plus tard une semaine après la fin d’une séance.

Le journal de bord doit contenir les éléments suivants :

  • Les noms et prénoms du binôme
  • Une présentation détaillée du jeu, et ce qu’il est possible de faire (au moment du rendu)
  • Une feuille de suivie : Vous devez écrire ce que vous avez fait, quand et par qui. Par exemple :
14/01/2020 à 11h36 - Okabe Rintaro : J'ai ajouté une fonction pour envoyer des sms dans le passé (D-mail).
15/01/2020 à 14h57 - Mayuri Shiina : J'ai ajouté un bruitage dans une fonction : "Tuturu !"

Remplissez la feuille de suivi le plus régulièrement possible ! La majorité des points du journal de bord sera basée sur cette feuille. Vous devez progresser régulièrement.

  • Une feuille de planning : Vous devez écrire ce que vous allez faire, quand et par qui. Par exemple :
18/02/2020 - Okabe Rintaro : Je vais créer une fonction pour me souvenir de mes voyages dans les autres 
lignes (Steins Reader)
19/02/2020 - Mayuri Shiina : Je vais faire une fonction qui distribue des Oopas, et le Metal Oopa sera le 
plus dur à avoir !
  • Une page détaillant les difficultés rencontrées et comment vous les avez résolus ou comment vous allez les résoudre
Okabe Rintaro : J'ai encore échoué à *spoiler*. Je vais essayer de *spoiler* pour *spoiler*, en espérant que cela marche cette fois.

Note du prof: Je ne vais pas vous spoiler Steins;Gate quand même !

Vous pouvez réaliser ce journal de bord avec n’importe quel éditeur de texte (Bloc-note, Word, Latex, etc.)

Le rendu

Le journal de bord ainsi que l’avancement du code est à rendre par mail à l’adresse suivante : ie.pole3d@gmail.com

Vous devez mettre comme titre de mail : [L1_X] NOM 1 - NOM 2 : Rendu Tamagotchi N°YX est votre groupe (A ou B) et Y le numéro du rendu (de 1 à 4).

Vous devez rendre votre projet au plus tard une semaine après la fin de la séance.

Par exemple, la première séance est prévu le vendredi 6 mars 2020, vous devez donc rendre votre travail AVANT le vendredi 13 mars 2020 à 23h59

Le projet (version textuelle)

La réalisation du projet est assez libre du moment que les fonctionnalités ci-dessous sont bien réalisés. L’utilisation d’un maximum fonctions est très recommandée !

Le nom et statistiques de votre Tamagotchi

Au lancement de votre programme, vous devez donner un nom à votre Tamagotchi.

Votre Tamagotchi doit posséder différentes statistiques :

  • Faim
  • Joie
  • Santé

Ces statistiques doivent être représentés graphiquement par une jauge qui devras être affiché après chaque action. Voici un exemple :

Metal Oopa
[##########...] Faim (85/100)
[#############] Joie (100/100)
[####.........] Santé (40/100)

Vous êtes libres d’ajouter de nouvelle jauge, voici quelques idées :

  • Soif
  • Expériences
  • Niveau

Les actions

Vous devez créer un menu pour gérer différentes actions. Vous devez au minimum réaliser les actions suivantes :

  • Nourrir : Vide la jauge de faim, si la jauge est déjà vide, la santé diminue (il faut manger sainement !)
  • Jouer : Lance un mini-jeu, si vous gagnez le mini-jeu, la jauge de joie augmente
  • Nettoyer : Le Tamagotchi peut éventuellement faire ses besoins, si c’est le cas, vous pouvez le nettoyer
  • Soigner : Remplis la jauge de Santé

Pour le mini-jeu de l’action jouer, vous êtes libre d’utiliser celui de votre choix, par exemple : le jeu du +/-, le pierre/papier/ciseau, etc… Vous pouvez même proposer plusieurs jeux !

Après chaque action, vous devez ré-afficher les statistiques de votre tamagotchi

La gestion du temps et impact sur les statistiques

Pour gérer l’évolution des différentes jauges, il faut “mesurer” le temps. Chose que l’on a pas vu en cours. Voici une solution “facile” pour mesure le temps :

# A mettre au début
from datetime import datetime

# Mesure du temps
now = datetime.now()
timestamp = datetime.timestamp(now)

Dans cet exemple, la valeur timestamp contient le nombre de seconde qu’il s’est écoulé depuis le 1 janvier 1970. Grâce au timestamp, il est possible de compte le nombre de seconde qu’il s’écoule entre deux actions:

now = datetime.now()
temps_dernier_repas = datetime.timestamp(now)

# On fait des actions, comme jouer, etc...
now = datetime.now()
temps_depuis_dernier_repas = datetime.timestamp(now) - temps_dernier_repas
print("Il s'est écouté ", temps_depuis_dernier_repas, " secondes")

Exemples

Voici quelques exemples pour vous aider :

Chronométrer une action

from datetime import datetime

date_actuelle = datetime.now() # Enregistre la date au moment de l'appel de la fonction, par exemple : 18/03/2020 11:37:18

date_actuelle_en_secondes = datetime.timestamp(date_actuelle) # Convertit la date en secondes écoulées depuis le 1er janvier 1970

# On peut faire des opérations qui prennent du temps, par exemple :
text = input("Ecrit quelque chose : ")

nouvelle_date = datetime.now() # Enregistre la date après avoir saisie quelque chose, par exemple, il sera : 18/03/2020 11:38:49

nouvelle_date_en_secondes = datetime.timestamp(nouvelle_date) # Convertit la nouvelle date en secondes.

temps_ecoule = nouvelle_date_en_secondes - date_actuelle_en_secondes # Calcule le temps écoulé en secondes entre les deux dates

print("Tu as mis ", temps_ecoule, " seconde pour écrire : ", text)

Faire une action toutes les X secondes

from datetime import datetime

dernier_check = datetime.timestamp(datetime.now())  # J'ai combiné les deux fonctions d'un coup
while True:
    actuellement = datetime.timestamp(datetime.now())
    if actuellement - dernier_check >= 2:
        print("il s'est passé deux secondes")
        dernier_check = actuellement # Ne pas oublier de remettre à jour le dernier check

Une fois que vous avez réussi à bien gérer le temps. Vous pouvez gérer la diminution des jauges. Voici quelques idées (libre à vous de faire autrement) :

  • La faim augmente de 1 toutes les 30 secondes
  • La joie diminue de 1 toutes les 30 secondes. Elle diminue de 10 à la place si la faim est au dessus de 70/100
  • La santé diminue de plus en plus vite si la faim et la joie sont bas.

Evènements

Vous pouvez gérer différent évènements qui peuvent survenir pendant la durée du jeu. Vous devez à minimum, gérer la mort de votre tamagotchi (la santé arrive à zéro).

Vous êtes libre de créer différents évènements au cours du jeu, voici quelques idée :

  • Evolution du Tamagotchi si certaines conditions sont réunis
  • Anniversaire du Tamagotchi (évènement se produisant après 4/5 min de jeu par exemple).

Le projet (version graphique - Pygame)

L’objectif de cet partie est de reprendre votre code de la version textuelle, et de la transformer en version graphique. Pour ne rien perdre de la version textuelle, créez un nouveau fichier, vous y copierai petit à petit les fonctions de la version textuelle en les adaptant à la version graphique

Installer Pygame

Ouvrir une fenêtre de commande (Dans la barre de recherche en bas de votre écran, taper: cmd)

Puis saisir la commande : python -m pip install -U pygame --user.

Dans le cas où il ne se passe rien, écrivez python3 au lieu de juste python

Introduction à Pygame

Le code de base

Comme pour le module random ou datetime, il faut importer Pygame dans Python. De plus, il faut ici aussi initialiser le module. Pour cela, ajoutez les lignes de code suivante:

import pygame
successes, failures = pygame.init()
print("{0} reussites et {1} echecs".format(successes, failures))

Le print un peut particulier permettra d’afficher dans le terminal (la partie droite de Pyzo ou Spider) les éventuels problèmes.

La fenêtre

Le code précédant à créer une fenêtre invisible, vous ne pouvez pas encore la voir car vous n’avez pas spécifié de taille. Pour définir une fenêtre utilisez le code suivant :

screen = pygame.display.set_mode((720, 480))  
clock = pygame.time.Clock()
FPS = 60
clock.tick(FPS)

La première ligne de code définie la taille de l’écran (ici 720 pixels par 480 pixels) et la stock dans une variable screen.

La seconde ligne est une horloge qui met permet la mise à jour des données du jeu à intervalle régulier. Contrairement à la version textuelle où une mise à jour été fait après une action de l’utilisateur, là c’est mis à jour à chaque frame.

La troisième ligne concerne le FPS, rien a voir avec un jeu de tir, cela veux dire Frame Per Seconds. C’est à dire combien d’image par secondes. L’œil humain peut voir en moyenne 60 Frame par seconde et comme le Tamagotchi n’est pas gourmand en ressource, on peut se le permettre. Notez que pour des gros jeux, le FPS est capé à 30. Plus il y a de FPS plus le jeu demande des ressources. Ainsi pour ne pas ralentir le jeu, le nombre de FPS est souvent diminué en pratique.

La boucle de jeu

La boucle de jeu est une boucle qui va être répété indéfiniment à chaque frame, elle est construite de la façon suivante :

while True:
    clock.tick(FPS)

Sauf que ce n’est pas suffisant, si vous faites juste ça, vous ne pourrez pas quitter votre programme. Ajoutez le bout de code suivant :

while True:
    clock.tick(FPS)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit()

Ces lignes permettent de tester les éventuelles évènements qui ont été obtenu. Ici en occurrence, on teste si l’évènement QUIT à été lancé. Cet évènement est déclenché lorsque l’on cherche à fermer la fenêtre Pygame.

Si vous avez tout correctement suivi jusque là, vous devez avoir un joli écran noir qui peut se fermer, bravo !

Importer des images

Pour utiliser des images, il vaut mieux utiliser des images au format PNG. Vous pouvez utiliser soit des créations personnelles, soit des images libres de droit sur internet.

Pour ma part, je vais utiliser l’image d’un blob libre de droit (trouvable sur Pixabay) que j’ai redimensionné pour qu’elle rentre dans la fenêtre de jeu (il est possible de redimensionner l’image directement avec du code, mais c’est un peu compliqué, alors on fait au plus simple !).

Mon Tamagotchi
Mon Tamagotchi

Il vaut mieux créer un dossier où ranger ses images, par exemple, là où il y a mon script Python, j’ai crée un dossier img où j’ai mis mon image.

Pour l’utiliser dans votre programme, il faut charger l’image AVANT la boucle de jeu, avec le code suivant :

mon_blob = pygame.image.load("img\\blob.png").convert_alpha()

Note: le \ étant un caractère spécial, il est important de le doubler pour écrire le chemin de l’image.

Avec cet ligne, le blob est chargé, mais pas affiché ! On a pas encore dit où le mettre sur l’écran. Pour l’afficher, il faut utiliser la fonction screen.blit(surface a afficher, (coord_x, coord_y)) qui doit être placé DANS la boucle de jeu.

Exemple:

mon_blob = pygame.image.load("img\\blob.png").convert_alpha()
while True:
    # Le code d'avant... (clock, events ...)
    screen.blit(mon_blob, (360, 240))
    # A mettre à la fin de la boucle !
    pygame.display.flip()

La ligne de code pygame.display.flip() doit être mise à la fin de la boucle, c’est elle qui calcul l’image finale. Les blit, c’est un peu comme les calques de photoshop. On empile les calques dans l’ordre apparition (la première est tout en dessous, et la dernière tout au dessus). Puis, le flip calcule l’image à afficher avec la superposition de tout les blits.

A ce niveau là, vous devez avoir un magnifique blob qui apparait à l’écran !

Essayez de mettre un fond à votre fenêtre pour que le blob ne soit pas dans le noir complet ;). Vous avez toutes les connaissances pour le faire maintenant !

Dessiner un rectangle à l’écran

Pour dessiner un rectangle, voici le code à utiliser:

while True:
    # L'ANCIEN CODE
    # Avant le flip
    mon_rectangle = pygame.Surface((200, 25))
    mon_rectangle.fill((255, 255, 255))
    screen.blit(mon_rectangle, (20, 400))
    
    pygame.display.flip()

Quelques explications s’impose !

La ligne pygame.Surface((longueur, largeur)) permet de créer une surface x * y. Rien de bien compliqué.

La ligne mon_rectangle.fill((R,G,B)) permet de remplir la surface avec une couleur au format (R,G,B). Si vous ne connaissait pas ce format de colorimétrie, je vous invite à trouver la couleur de votre choix sur : https://htmlcolorcodes.com/fr/ qui vous donne les valeurs RGB pour une couleur donnée.

La ligne screen.blit(...) n’a plus de secret pour vous maintenant !

Dans cette exemple, la taille est figé à (200,25), mais rien n’empêche de remplacer 200 par une variable jauge_faim dont la valeur évoluera au cours du temps !

En combinant les images, et les rectangles, vous devriez être capable d’afficher les différentes jauges de votre tamagotchi désormais. (Une image évoquant la statistique, suivi d’un rectangle plus ou moins grand en fonction du niveau de la jauge).

Gestion des touches

Dernière chose à savoir pour arriver à faire tout ce que vous souhaitez : la gestion des touches ! Les touches, c’est des évènements ! Et on a déjà vu où se passe la gestion d’évènements, au début de la boucle ! Il suffit juste de modifier légèrement cette parti du code pour gérer les touches :

while True: 
    if event.type == pygame.QUIT:
        quit()
    elif event.type == pygame.KEYDOWN:
        if event.key == pygame.K_w:
            # Code si W est pressé
        elif event.key == pygame.K_SPACE:
            # Code si espace est pressé
        # ...

On rajoute simplement un évènement de type KEYDOWN qui est un évènement qui se déclenche si une touche est pressé. Puis on teste l’évènement de la touche pour déterminer pour quelle touche appuyé, quelle action il faut réaliser.

Pour voir la liste des touches, vous pouvez voir le site : https://www.pygame.org/docs/ref/key.html

En conclusion

En combinant toute les informations ci-dessous, vous devriez, avec un peu de travail, faire une version graphique de votre jeu. Il faut “juste” combiner toutes vos connaissances. Utiliser les conditions, et les boucles qui vont bien. N’hésitez pas à m’appeler en cas de problème !