1. Introduction

Mon projet consiste en un jeu écrit en python. J'ai toujours bien aimé les jeux vidéos. Je ne suis pas à fond dans les jeux vidéos comme certains de mes amis mais j'ai toujours été passionée par les pokémon, ainsi que les marios, quand je jouait à la game-boy ou la nintendo DS. Et du coup grace à ce projet j'ai eu l'occasion de découvrir comment faire un jeu simple grâce à python. Mon idée de jeu est de faire une toure avec des blocks qui vont et viennent de la gauche à la droite et a chaque fois les blocks vont plus vites et si on arrive pas à faire la tour, on perd. J'ai cru que j'était original dans mon idée mais j'ai découvert que pas du tout... Maintenant que j'y pense, j'ai déjà dû joué à ce jeu étant plus petit. Mais ça ne fait rien car c'est l'occasion de faire ma propre version de ce jeu. Le jeu d'origine s'appelle stacker.

2. Matériel et méthodes

2.1 Matériel

Pour le matériel j'ai utilisé un ordinateur et un Raspberry pi. Au final, je n'ai plus eu besoins de mon Raspberry pi et seulement de mon ordinateur.

2.1.1 Software

Le jeu est écrit en python et donc il faut le programme python. Ensuite, pour que ça fonctionne, il faut importer le module pygame. Malheureusement, pygame n'est pas un module de base du programme python et pour pouvoir l'utiliser il faut le télécharger. C'est pour cela que au début j'utilisait mon raspberry, car quand je l'ai reçu, pygame était déjà installé. Le soucis c'est que pour voir à quoi ressemble le jeu il faut directement voir sur un écran ce qu'il ce passe et donc soit connecter le raspberry à une télévision en hdmi, soit y accéder sur son ordi grâce à une application qui s'appelle VNC Viewer. Mais le contrôle du raspberry, par ce moyent, est assez lent et la visiblité assez mauvaise. Il est difficile de travailler comme ça. Du coup je voulais vraiment tout faire par mon ordi et j'ai donc du trouvé un moyen d'installé pygame sur un windows, ce qui est plus compliqué que sur un mac car le terminal est différent que un mac (car il faut téléchargé pygame par le terminal). Pour pouvoir écrire le code je ne souhaitait pas utiliser nano qui est dans le terminal et permet d'écrire du code (sur windows, pour avoir un terminal pareil à un linux, il faut télécharger cygwin) alors j'ai télécharger un programme qui s'appelle Atom et qui est très utile pour écrire du code dans n'importe quel langage et très simple d'utilisation.

2.2 Méthode

2.2.1 Pygame



Pour mon projet j'ai donc utiliser python qui est un langage de programmations et me permet d'écrire des programmes et plus précisément (pour mon cas) un jeu. Pour ce faire on peut télécharger des modules (ou library) qui sont des ensembles de fonctions pré-écrites et nous permet de les utiliser pour faire notre programmes. On peut par exemple trouver les modules "randoms" qui permettent de travailler avec des valeurs aléatoires, "math" qui sont les fonctions utiles pour les opérations mathématiques, "time" ou "calendar" qui peuvent être utile pour metre des dates ou l'heures dans le programme, Il existe des centaines d'autres modules mais celle qui m'a été le plus utile pour mon projet et permet de faire un jeu en python c'est le module "Pygame".

Donc pygames est une library qui va nous permettre d'utiliser divers fonctions afin d'afficher des objets, graphiques (tout ce qui va nous être utile pour un jeu) et animer ces objets, ainsi que des sons et des moyens pour contrôler tous ce qui se passe à l'écran avec la souris ou le clavier.

Pour pouvoir utiliser pygame sur mon windows il m'a donc fallu le télécharger. J'ai le programme cygwin, qui est comme le terminal linux et me permet donc d'utiliser les commandes linux apprisent en classent sur un windows. Malheureusement, cygwin ne vient pas avec toute les fonctionnalités d'un terminal linux. Donc pour pouvoir utiliser la commande python pip (pip veut dire PIP Installs Packages) il faut télécharger les fonctionnalités manquantent pour le terminal....Une boucle enfernale... Au finale, j'ai trouvé un site qui expliquait comment installé pygame sur un windows. D'abord, il faut télécharger la bonne version de pygame depuis le site officiel. Puis, il faut utiliser le terminal windows (Commande Prompt) et utiliser (comme pour un terminal linux) la même commande PIP qui vient comme suit

python -m pip install pygame

J'ai perdu beaucoup de temps pour résoudre ce problème de téléchargement de pygame alors qu'en fait c'était assez simple...

2.2.2 Conception

Voilà, l'idée que j'avait à l'origine et que j'ai suivit. C'est, au final, assez différents du jeu d'origine.

https://oci.gyre.ch/blog/public/1718/gyre/p/rafael-dousse/2018-05-14__8_.png (liens vers l'image)

Pour commencer le jeu il me fallait une base. Enfin, j'ai découvert avec une vidéo que j'ai regardé, que tous les jeux pygame ont plus ou moins la même base ou le même squelette de jeu. Donc j'ai tout simplement repris la même base que l'on peut voir sur cette photo:



https://oci.gyre.ch/blog/public/1718/gyre/p/rafael-dousse/2018-05-14.png (liens vers l'image en meilleur qualité)

Donc pour commencer j'ai importer importer les modules de pygame et du système (os, on verra plus tard pourquoi on en a besoin)

#Pygame c'est la base de tous jeux
import pygame, os

A chaque fois que l'on voir un # c'est les commentaires inclus dans le programme pour savoir où on en est et ce que la ligne fait, C'est une aide pour le programmeur et python ne tient pas compte, dans le programme, de toute les lignes qui commenent par un #.

Après importer pygame et l'os j'ai donc mit des variables pour la taille de notre écrans donc 500 pixels de large et 460 pixels de haut. Ainsi que la vitesse à laquelle le programme affichera les images (FPS = Frames Per Second ou en français: les images par secondes)

#ces valeurs sont des variables pour la taille de notre écran 
#ainsi que les images par secondes
#ou à quel vitesse on voit les mouvements de notre jeux
WIDTH = 500
HEIGHT = 460
FPS = 30

Ensuite, si on veut un jeu avancé, on peut mettre des images, paysages, en arrières plan. Mon jeu est assez basique donc j'ai juste décidé de mettre un arrière plan en Orange. Pour faire cela on a besoin de variable pour les couleurs. Donc pour cela on choisit quelque couleurs que on peut utiliser plus tards si on le souhaite.

#Variables pour les couleurs
Noir = (0, 0, 0)
Blanc = (255, 255, 255)
Jaune = (255, 255, 0)
Bleu = (0, 0, 255)
Rouge = (255, 0, 0)
cyan = (0, 255, 255)
Orange = (255, 128, 0)

Maintenant que j'ai mes variables de couleurs, j'ai écrit mes deux première fonction qui viennent du template. La première sert à initialiser pygame et tous les modules nécessaires. Le deuxième sert à initialiser les fonctions utile si on veut mettre de la musique ou des sons. Personnellement je ne l'ai pas utiliser mais je l'ai laissé pour si jamais j'en avait besoin. Pour fignoler le jeu vers la fin mais j'ai eu d'autres soucis donc pas le temps pour mettre des sons.

#initialiser pygame and afficher une fenêtre
pygame.init() #cela initialise Pygame
pygame.mixer.init() #permet d'avoir des sons et de la musique

Maintenant il faut pouvoir afficher un écran qui affichera notre jeu et c'est ce qu'indique screen. Pygame.display.set_mode utilise les valeurs de Width et Height pour afficher l'écran et définir la taille. Pygame.display.set_captioin va juste afficher un titre sur le haut de la fenêtre du programme. Je l'ai nommer "My project with Pygame". Pour finir clock va nous être utile plus tard pour indiquer la vitesse à laquelle le jeu doit afficher les images, donc en fonction des FPS décrit avant.

screen = pygame.display.set_mode((WIDTH, HEIGHT))
#ce qui sera afficher sur le haut de la fenêtre
pygame.display.set_caption("My project with Pygame") 
clock = pygame.time.Clock()

Game_folder et img_folder vont être utiles pour utiliser une image comme personnage (ou plus tôt comme block). Ici on utilise donc le système pour décrire au programme le chemin qu'il faut utiliser pour atteindre l'image. Donc dirname c'est le nom du fichier qui est file et qui veut dire le dossier dans lequel est notre jeu. Ensuite, dans ce fichier on fait un dossier image et on joint les deux dossier grâce à os.path.join(game_folder, "image). C'est gr'ace à ces deux variable que on pourra utiliser une image pour notre bloc.

game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "image")

Maintenant, il m'a fallu décrire, donner des attributs à mon bloc et je vais utiliser plusieurs fonctions qui ont pour nom Sprites. Je vais donc vite définir ce qu'est un sprite. Un sprite est un personnage dans le jeu vidéo ou un objet mouvant qui se déplace dans le décor. Ici, j'utilise donc des sprites pour mes blocs qui bougent. Dans le code, ils sont tous simplement définis comme des sprites.

Voici l'image de bloc que j'ai choisit pour mon jeu:

Je décris donc mon bloc au programme et j'appelle mon bloc self. Je dit que mon block fait parti de la classe des Sprite. Ensuite, il faut donner une forme ou une image à mon bloc et c'est ce que je fait avec self.image en téléchargeant l'image grâce à ma variable img_folder. Je la converti dans un format que python puisse affiché dans les meilleurs récolutions et comme mon imge était trop grande il m'a fallu lui donné taille souhaitable qui est ici de 50*50. Self.rect dit que notre image est un rectangle. C'est comme ça que le lit le programme et c'est utile pour dire parfois une partie du "corp" de l'image. Si on veut le haut ou le bas de notre objet par exemple. Avec self.rect.bottom ça me permet d'avoir mon block en bas de l'écran. Et finalement, à chaque 30 FPS notre block va avancer de 10 pixels par seconde sur notre axe des X donc le bas de l'écrans. C'est donc notre varible des vitesses

class Block(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join(img_folder,"box-highres.png")).convert()
        self.image = pygame.transform.scale(self.image ,(50,50))
        self.rect = self.image.get_rect()
        self.rect.bottom = HEIGHT
        self.speedx = 10

Ici, on va définir de quelle manière va avancer le bloc. Ce que je souhaitais c'était que dès qu'il arrive aubord de l'écran il revienne en arrière. Honnêtement, je me suis pas mal cassé la tête pour trouvé comment faire ça car avant le bloc sortait de l'écran à droite et revenait depuis la gauche de l'écran et j'arrivait pas à comprendre comment changer ça. Si j'appelle ça update, c'est parce que après on va updater tous les sprites pour qu'ils avancent en fonctions des FPS. Donc à chaque fois que ça update on incrémente de 10 sa vitesse et c'est ce que dit cette variable self.rect.x += self.speedx. Ensuite on définit la condition que si la droite du bloc est plus grand que la taille de l'écran, alors sa vitesse soit de moins 10. Et pareille pour la gauche de l'écran. Et c'est ça qui va nous permettre au bloc de faire des allez-retour.

    def update(self):
        self.rect.x += self.speedx
        if self.rect.right > WIDTH:
           self.speedx = -10
        if self.rect.left < 0:
            self.speedx = 10

Maintenant, que j'ai mon block et que j'ai dit comment il va avancé il faut que je puisse pouvoir le controlé selon mon souhait. J'ai donc dit que si on appuie sur espace, alors sa vitesse est de zéro. c'est comme ça que je vais faire ma tour. J'ai rajouté une petite ligne de triche pour aider le joueur. Si le block va trop vite, il peut appuyer sur la flèche du bas pour ralentire la vitesse du block ou plus tôt pour que sa vitesse soit égal à 5. Si je laissait mon doigt appuyer sur la flèche, le block sortait de l'écran c'est pour cela que j'ai dit au programme de s'arrêter à la droite de l'écran si le block était plus grand que l'écran.

        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_SPACE]:
            self.speedx = 0
        #petit cheat pour faciliter le joeur si il a besoin d'aide...
        if keystate[pygame.K_DOWN]: 
            self.speedx = 5
        if self.rect.right > WIDTH:
            self.rect.right = WIDTH

La partie de code qui suit est la même chose que pour le bloc 1: la seul différence c'est que c'est pour le deuxième et troisième bloc. Ils ne sont pas tout en bas de l'écran. Ils sont positionnés à la Hauteur - la taille du le bloc 1 et la Hauteur moins 2 fois la taille du block 1. Et la vitesse du bloc 2 est plus grande que le bloc 1 et la vitesse du bloc 3 est plus grande que celle du bloc 2. C'est la les seuls différences.

class Block2(pygame.sprite.Sprite):
    def __init__(self2):
            pygame.sprite.Sprite.__init__(self2)
            self2.image = pygame.image.load(os.path.join(img_folder,"box-highres.png")).convert()
            self2.image = pygame.transform.scale(self2.image ,(50,50))
            self2.rect = self2.image.get_rect()
            self2.rect.bottom = HEIGHT - self2.rect.bottom
            self2.speedx = 15

    def update(self2):
        self2.rect.x += self2.speedx
        if self2.rect.right > WIDTH:
           self2.speedx = -15
        if self2.rect.left < 0:
            self2.speedx = 15


        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_SPACE]:
            self2.speedx = 0
        if keystate[pygame.K_DOWN]:
            self2.speedx = 5
        if self2.rect.right > WIDTH:
            self2.rect.right = WIDTH


class Block3(pygame.sprite.Sprite):
    def __init__(self3):
            pygame.sprite.Sprite.__init__(self3)
            self3.image = pygame.image.load(os.path.join(img_folder,"box-highres.png")).convert()
            self3.image = pygame.transform.scale(self3.image ,(50,50))
            self3.rect = self3.image.get_rect()
            self3.rect.bottom = HEIGHT - 2*(self3.rect.bottom)
            self3.speedx = 20

    def update(self3):
        self3.rect.x += self3.speedx
        if self3.rect.right > WIDTH:
           self3.speedx = -20
        if self3.rect.left < 0:
            self3.speedx = 20


        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_SPACE]:
            self3.speedx = 0
        if keystate[pygame.K_DOWN]:
            self3.speedx = 5
        if self3.rect.right > WIDTH:
            self3.rect.right = WIDTH

Maintenant je met tous mes sprites dans un seul et même block... ou groupe...haha.. Comme ça ça permet de tous les contrôler en une fois plus tôt que individuellement

all_sprites = pygame.sprite.Group() #permet de controler
#tous les sprites
block = Block()
block2 = Block2()
block3 = Block3()
all_sprites.add(block)
all_sprites.add(block2)
all_sprites.add(block3)

J'ai oublié de supprimer la variable suivante . Je voulais l'utiliser pour autre chose mais j'ai pas compris comment faire. Je vais expliquer ça plus tard.

key_states = pygame.key.get_pressed()

Maintenant que on a presque tous, il nous faut notre jeu. Ainsi on dit que le jeu est égal à True pour faire une loupe et garger notre jeu ouvert. Ensuite, on dit que la vitesse d'affichage de l'image est en fonction des FPS.

For event in pygame.event.get(): if event.type == pygame.QUIT:

va permettre au joueur de cliquer sur la croix un haut à droite de l'écran pour pouvoir quitter le jeu. Sans ça il n'y arriverait pas ou plus tôt difficilement. On a donc notre Game= False qui va fermer la loupe.

#Game loop
Game = True
while Game:
    #Garder la loop a la bonne vitesse
    clock.tick(FPS)

    for event in pygame.event.get():
         if event.type == pygame.QUIT:
            Game = False #cet évènement permet
            #de quitter le jeu si le joueur clique sur la croix


Update() va nous permettre de actualiser l'état de nos Sprites que l'on avait mit dans le groupe all_sprites. C'est une des raisons qui permet à l'objet d'avancer.

    all_sprites.update()

Ici, on indique juste la couleur d'arrière plan du jeu qui va être Orange. Orange étant une des variables qu'on avait écrit au début du jeu, et all_sprites.draw va dessiner les Sprites sur l'Ecran.

   screen.fill(Orange)
    all_sprites.draw(screen)

Display.flip va actualiser ce que l'on voit et afficher les mouvements, objets... Et finalement on à la fonction qui permet au joueur de quitter le jeu sans soucis et de désinitialiser tous les modules

    pygame.display.flip() #permet d'afficher et actualiser ce que l'on affiche
pygame.quit()

3. Résultats

Je suis mitigé par rapport à mon résultat. Car j'était satisfait d'avoir résolu mon problème de blocs qui sortait de l'écran, d'avoir pu faire apparaitre plusiers blocs à un étage différents. Mais je n'ai pas réussi à finaliser le jeu comme je le voulait à l'origine... J'ai passé de nombreuses heures à regarder des vidéos, épluchés de nombreux sites et observer plusieurs jeux pour trouver une réponse. Mais je n'ai rien trouvé d'utile dans les vidéos ou les sites et les jeux que j'ai utilisé était trop compliqul pour que je comprenne comment faire. Mon soucis étant que j'arrive à faire apparaitre plusieurs blocs mais je n'ai pas réussi à faire apparaitre le premier bloc puis faire apparaitre le second bloc quand on appuyait sur espace pour stopper le premier. Et ainsi de suite. C'est pour cela que j'ai mit que trois blocs car ça ne servait à rien d'en mettre d'autres a part faire un code super long et qui se repète. Un autre soucis était que je ne savait pas comment faire apparaître plusieurs blocs différents dans devoir écrire plusieurs fois la même chose (je parle de: class Block1, class Block2, classe Block3.....). Voici une image du résultat:

2018-05-14 (5).png

4. Discussion

C'était très intéressant de travailler sur ce projet sur lequel j'ai passé beaucoup de temps. J'ai pu découvrir comment fonctionnait un jeu basique et ça m'a donné envie d'en faire plus. Quand on commence à faire un jeu on peut passer des heures à essayer d'améliorer et de tester pleins de choses. Malheureusement pour moi, malgré tout le temps investi, je n'ai pas réussi à finir mon jeu comme je le souhaitait et cela est une grosse déception. Une de mes erreurs a surement été de m'y prendre un peu au dernier moment. Car oui j'ai passé beaucoup de temps sur mon jeu mais je ne m'y suis pas pris beaucoup de temps à l'avance pour le commencé. Le plus frustrant c'est que je sais que mon jeu est simple et que la réponse à tous mes problèmes est surement une chose toute bête et simplissime comme le soucis que j'avait eu avec mon block qui sortait de l'écran. Une autre erreur de ma part et de tous vouloir faire moi-même (et j'ai cette tendance pour tout, pas que le projet) et donc des fois je me trouvent avec beaucoup de question et peu de réponse. Et c'est un vrais soucis dans ma vie. Je vais donc essayer de changer ma gestion du temps et mon problème de tout vouloir faire moi-même pour mon futur et les différents projets (et autres) qui pourront survenir.

5. Conclusion

Malgré mon demi échec, je suis quand même content d'avoir réaliser ce projet car cela m'a permit d'en savoir plus sur les jeux vidéos et leurs fontionnement . J'ai quand même passé pas mal de temps à lire pleins de documentations et regarder des vidéos. Et même si je n'ai pas réussi à finir mon jeu à temps, ce n'est pas ce qui va m'empêcher d'essayer de le finir, juste pour mon plaisir d'avoir pu le finir et d'essayer d'en faire d'autres. C'était une super expérience.

Références

Principales sources de mon projet

  • https://www.pygame.org/docs/ Ce site m'a été utile pour commencer à connaitre les fonctions nécessaire pour créer mon jeu. Il m'a aussi permit de télécharger le module pygame sur mon windows .
  • "Making Games with Python & Pygame" by Al Sweigart
  • http://opengameart.org Le site permet à des artistes de publier leur oeuvres (comme des images de block ou des personnages, ou encore des paysages... pour l'utilisation dans des jeux ). C'est dans ce site que j'ai trouver mon image de block pour mon jeu. Voici la référence du block: "RPG GUI block element" by Bart licensed CC-BY 3.0: https://opengameart.org/content/rpg-gui-block-element .
  • Il y a une chaine youtube qui m'a beaucoup aidé pour comprendre comment utiliser les fonctions du jeux ainsi que comment débutter pour le "squelette" du jeu et c'est la chaine "KidsCanCode".
  • J'ai aussi télécharger des jeux sur pygame.org que d'autres personnes ont fait pour pouvoir voir comment un jeu est fait.