Projet d'informatique graphique

Puissance 4 - Space Invaders

Matthias Meusburger
Lionel Droz-Bartholet
IUP3GMI Besançon
2002-2003

sommaire :
  1. Généralités
    1. Choix de développement
    2. Organisation
    3. Fichiers sources
    4. Fichiers de textures
    5. Compilation
    6. Utilisation

  2. Puissance 4
    1. Principe
    2. Organisation
    3. Détail des classes

  3. Space Invaders
    1. Principe
    2. Organisation
    3. Détail des classes
    4. Détail des fichiers

  4. Remarques concernant la programmation
    1. Constructeurs
    2. Utilisation de fichiers au sein de Space Invaders

  1. Généralités :

    1. Choix de développement :

      Le développement de ce projet a été réalisé sous Windows avec Visual C++.
      Compte-tenu de la nature du programme, nous avons choisi d'utiliser le langage C++ afin de pouvoir bénéficier des avantages de la programmation objet, qui s'avère particulièrement bien adaptée aux jeux, et ce malgré les limites imposées par l'architecture C d'OpenGL.


    2. Organisation :

      L'application est composée de trois modules : le menu, le jeu du Puissance 4 et le jeu Space Invaders.
      En ce qui concerne OpenGL, pour assurer une cohérence lors du passage d'un module à un autre, chaque module implémente une fonction razOpenGL qui va remettre à leurs valeurs par défaut toutes les lumières et matériaux utilisés.


    3. Fichiers sources :

      Les fichiers sources sont tous placés dans le même répertoire, mais le préfixe de chaque fichier indique son appartenance à l'un ou l'autre jeu : les fichiers appartenant à Space Invaders commencent par le préfixe "SPA_" et les fichiers appartenant au Puissance 4 commencent par "PUI_". Les fichiers ne comportant pas un de ces préfixes sont les fichiers du lanceur, du menu, et de la bibliothèque "Module Manipulateur".


    4. Fichiers de textures :

      Les fichiers de textures utilisés par l'application sont au format BitMaP (BMP) et sont placés dans le même répertoire que les fichiers sources afin d'éviter tout problème de compatibilité entre différents systèmes d'exploitation.


    5. Compilation :

      Le fichier Workspace de Visual C++ est inclus avec les sources afin de permettre une compilation rapide et aisée sous Windows. Cependant, le projet comporte également un fichier Makefile pour sa compilation sans Visual C++.


    6. Utilisation :

      L'application démarre sur un menu permettant de choisir un des jeux. Utilisez pour cela les flèches de direction pour amener au premier plan le jeu désiré. Un appui sur la barre d'espacement lance le jeu en question. Lors d'un jeu, vous pouvez à tout moment revenir au menu grâce à la touche d'échappement ou au menu contextuel. Un appui sur la touche F1 affiche à tout moment les touches à utiliser.


  2. Puissance 4 :

    1. Principe :

      Le jeu reprend le principe du Puissance 4 "classique" à la différence qu'ici l'aire de jeu est en trois dimensions, et il est donc possible de placer des billes en profondeur.
      L'aire de jeu est décomposée en quatre grilles superposées. Chaque grille est composée d'un carré de cases de coté quatre. Chaque joueur, à son tour, dispose d'un curseur placé au dessus de ces quatre grilles, qu'il peut déplacer pour se positionner. Une fois positionné, le joueur lâche sa bille sur l'aire de jeu, qui va tomber et atterrir sur la première case inoccupée. Le premier joueur qui aligne quatre billes de sa couleur gagne!


    2. Organisation :

      Puissance 4 est composé de quatre classes :
      • PUI_JeuPuissance4, qui est la classe "principale" du jeu du Puissance 4, c'est elle qui sera instanciée par le lanceur.
      • PUI_AireDeJeu, qui va d'une part dessiner l'aire de jeu et d'autre part contenir les structures de données représentant le jeu en mémoire.
      • PUI_Bille, qui va contenir les méthodes nécessaires à l'affichage d'une bille sur l'aire de jeu.
      • PUI_Curseur, qui va matérialiser le curseur que le joueur peut déplacer avant de lâcher une bille (classe fille de PUI_Bille).


    3. Détail des classes :

      • PUI_JeuPuissance4 :
        Cette classe matérialise un jeu du Puissance 4. C'est elle qui va s'occuper de tous les traitements inhérents au déroulement d'une partie.
        C'est aussi à elle qu'incombe la plupart des traitements OpenGL :
        • définition des lumières.
        • affichage principal (fonction display).
        • capture des évènements claviers.
        • définition et changement du mode d'affichage (solide/filaire, fenêtré/plein-écran) et des différentes vues de caméra possibles.
        • affichage du texte (fin de partie ou aide)

      • PUI_AireDeJeu :
        Cette classe matérialise l'aire de jeu, qui est implémentée sous la forme d'un tableau d'entiers à trois dimensions. Cette abstraction est simple à comprendre : un "0" signifie que la case est libre, un "1" qu'une bille du joueur 1 y est présente, et un "2" qu'une bille du joueur 2 y figure. Outre la simplicité de cette représentation, il est également plus rapide de manipuler des entiers que des objets.
        La structure de données la plus importante du jeu étant présente dans cette classe, divers traitements y sont effectués :
        • L'ajout d'une bille dans l'aire de jeu (fonction ajoutePUI_Bille)
        • L'évaluation de la fin de la partie.
          Celle-ci est réalisée au moyen de trois fonctions :
          • finDePartie, qui va parcourir itérativement chaque case de l'aire de jeu, et qui, pour chaque case contenant une bille, va lancer la fonction chercheAlignement.
          • chercheAlignement, qui pour une case et une couleur donnée, va lancer la fonction explore sur toutes les cases qui lui sont connexes.
          • explore, qui va partir dans la direction donnée par chercheAlignement, et renvoyer le nombre de billes de la même couleur alignées dans cette direction.

        Les fonctions d'affichage de la grille de l'aire de jeu ainsi que les appels des fonctions d'affichage des billes pouvant s'y trouver sont également prises en charge dans cette classe.

      • PUI_Bille :
        Cette classe va contenir les différentes caractéristiques d'une bille :
        • ses coordonnées dans l'aire de jeu
        • ses coordonnées d'affichage
        • le numéro du joueur auquel elle appartient
        Elle va également permettre l'affichage d'une bille dans le matériau correspondant à chaque joueur et dans le mode idoine (solide/filaire).

      • PUI_Curseur :
        Cette classe hérite de PUI_Bille, puisqu'un curseur n'est finalement qu'une bille que l'on peut déplacer en x et en z.
        Elle contient les méthodes d'affichage, qui sont des appels aux fonctions correspondantes de la classe mère, ainsi qu'une méthode permettant de changer les coordonnées x et z du curseur dans l'aire de jeu en cas de déplacement.


  3. Space Invaders :

    1. Principe :

      Vous dirigez un vaisseau spatial situé au bas de l'écran (un X Wing pour être précis). Plusieurs rangées de vaisseaux spatiaux aliens (des Tie Raptors) se déplacent horizontalement en haut de l'écran et descendent d'un cran à chaque aller-retour. Vous devez détruire ces aliens avant qu'ils n'atteignent le bas de l'écran et vous touchent, et ce en évitant leurs tirs. Le jeu est composé de cinq niveaux : "facile", "moyen", "difficile", "encore plus dur" et "suicidaire".


    2. Organisation :

      Le jeu Space Invaders est composé de 6 classes et de 3 fichiers :
      • Classes :
        • SPA_Ship, qui permet de gérer un vaisseau.
        • SPA_particule, qui permet de dessiner et de gérer une particule.
        • SPA_Laser, qui permet de gérer un tir de vaisseau.
        • SPA_Explosion_x_wing, qui permet de gérer l'explosion du vaisseau du joueur.
        • SPA_Explosion, qui permet de gérer l'explosion d'un vaisseau ennemi.
        • SPA_JeuSpaceInvader, qui est la classe "principale" du jeu Space Invaders, c'est elle qui sera instanciée par le lanceur.

      • Fichiers :
        • SPA_TieRaptor, qui représente un vaisseau ennemi.
        • SPA_Tir, qui représente un tir de vaisseau.
        • SPA_x_wing, qui représente le vaisseau du joueur.


    3. Détail des classes :

      • SPA_Ship :
        Cette classe matérialise un vaisseau.
        Elle va contenir les différentes caractéristiques d'un vaisseau :
        • ses coordonnées dans l'espace.
        • savoir s'il faut afficher (dessiner) le vaisseau ou non
        • savoir si un vaisseau est vivant ou non (s'il est touché ou pas)
        • le type d'un vaisseau (tie raptor ou x_wing).
        Cette classe permet d'initialiser tous ces paramètres (méthodes précédées du mot 'set') et de lire ces paramètres (méthodes précédées du mot 'get').


      • SPA_particule :
        Cette classe matérialise une particule.
        Une particule est un point constitué :
        • de trois couleurs,
        • du canal alpha (pour gérer la transparence de la particule),
        • de trois coordonnées (pour gérer la particule dans l'espace),
        • d'une vitesse.
        Pour ce qui est de la couleur et des coordonnées, des initialisateurs et des sélecteurs permettent de gérer ces paramètres.
        La vitesse, quant à elle, est calculée aléatoirement lors de la création de chaque particule.
        Cette vitesse est donc différente pour chaque particule créée.
        Enfin une méthode 'DrawParticule' permet de dessiner une particule à l'écran en tenant compte des données sur la couleur et des coordonnées.


      • SPA_Laser :
        Cette classe contient les différentes caractéristiques d'un tir.
        Un tir est caractérisé par :
        • trois coordonnées,
        • un joueur (d'où provient le tir),
        • une variable qui indique si le tir est actif ou pas (à afficher ou non).
        Le fichier SPA_Tir permet de dessiner un tir de vaisseau alors que cette classe SPA_Laser gère ce tir.
        Cette classe n'est constituée que d'initialisateurs de sélecteurs.


      • SPA_Explosion_x_wing :
        Cette classe matérialise une explosion de x_wing. Elle utilise la classe SPA_particule.
        Une explosion de x_wing est constituée de 500 particules.
        Le constructeur de cette classe choisit une couleur pseudo-aléatoire pour chaque particule et initialise le canal alpha à 1 (non transparent) pour signaler que l'explosion n'est pas active.
        Une méthode 'SetPosition' permet de signaler les coordonnées initiales de l'explosion.
        Ces coordonnées ne gèrent en aucun cas la position de chaque particule.
        Une méthode 'SetColor' permet de réinitialiser la couleur de chaque particule.
        La méthode 'DrawExplosion_x_wing' permet de dessiner une explosion, c'est-à-dire de dessiner toutes les particules au point de coordonnées initial où l'explosion doit se produire et de dessiner chaque particule à l'aide de la méthode 'DrawParticule' de la classe particule.
        Une autre méthode importante de cette classe est la méthode 'UpdateExplosion_x_wing' qui met à jour l'explosion. Mettre à jour une explosion c'est en fait la propager.
        Pour chaque particule, on recalcule une nouvelle position à partir de l'ancienne et de la méthode 'GetSpeed' qui choisit aléatoirement une nouvelle position pour la particule.
        Cette méthode décrémente en même temps le canal alpha pour rendre chaque particule un peu plus transparente à chaque fois que la méthode 'UpdateExplosion_x_wing' est appelée.
        Ainsi, on donne l'illusion que la brillance de chaque particule s'estompe avec le temps.
        Lorsque le canal alpha est à 0, on remet la variable actif à faux pour signaler de ne plus gérer les particule, puisque l'explosion n'est plus visible.


      • SPA_Explosion :
        Gère une explosion de Tie Raptor.
        Cette classe est presque la même que la classe SPA_Explosion_x_wing excepté qu'une explosion de Tie Raptor n'est constituée que de 50 particules.
        L'autre différence est que cette classe peut gérer 32 explosions à la fois car il y a 32 Tie Raptor.


      • SPA_JeuSpaceInvader :
        Cette classe matérialise un jeu du Space Invader.
        C'est elle qui va s'occuper de tous les traitements inhérents au déroulement d'une partie. C'est aussi à elle qu'incombe la plupart des traitements OpenGL :
        • définition des lumières.
        • affichage principal (fonction display).
        • capture des évènements claviers.
        • définition et changement du mode d'affichage (solide/filaire, fenêtré/plein-écran) et des différentes vues de caméra possibles.
        • affichage du texte (fin de partie ou aide)
        Cette classe est composée d'un nombre important de méthodes. Nous allons donc nous intéresser uniquement aux plus importantes :
        • Pour commencer nous allons décrire comment l'univers (l'espace) a été créé.
          En réalité, c'est une sphère texturée avec tous les vaisseaux à l'intérieur.
          Ce stratagème permet de donner une impression de 3D lorque l'on fait tourner la scène avec la souris.
          Pour réaliser cette 'espace', deux méthodes sont principalement utilisées.
          La méthode Sphère, qui dessine une sphère et précise les points d'attache de la texture.
          Et la méthode 'LoadBMP' qui permet de charger une image BMP en mémoire.
        • Pour dessiner les différents vaisseaux, on appelle les méthodes 'Draw_x_wings', 'Draw_Tie_Raptor' et 'Draw_Tir' contenues dans les fichiers SPA_x_wing, SPA_TieRaptor et SPA_Tir.
          La principale méthode est celle appelée 'scene_jeu' qui permet de gérer le déroulement de la partie.
          Cette méthode est commentée pour comprendre son fonctionnement.
          Plus simplement, cette méthode réalise les opérations décrites ci-dessous :
          - vérifie si on est en fin de partie. Si oui, alors effectue un test sur le nombre de vies restantes pour savoir si c'est la fin du jeu (game over), ou si on passe au niveau suivant.
          - Si ce n'est pas la fin de partie, alors on vérifie si l'on doit afficher le x_wing ou non.
          - Vérifie si tous les Tie Raptor sont détruits ou non,
          - Pour chaque Tie Raptor, on le déplace s'il est vivant, si on a atteint un bord, on fait descendre les Tir Raptor.
          - On vérifie que les Tie Raptor n'ont pas atteint le X Wing (les Tie Raptor ne sont pas en bas de l'écran).
          - On choisit si un Tie Raptor doit tirer ou non.
          - On gère chaque tir, en les faisant se déplacer vers le bas pour les tirs de Tie Raptor et vers le haut pour les tirs de X_wing.
          - Si un tir est en contact avec un vaisseau, on lance une explosion. En contact signifie avoir les même coordonnées à plus ou moins 5%.
          - Si tous les Tie raptor on été détruis, on indique la fin de partie.
          - On gère chaque explosion.
        • Une autre méthode importante est la remise à zéro des lumières et matériaux utilisés.
          Ainsi si on choisit l'autre jeu, il n'y aura pas de problèmes de lumières ou de matériaux.
          La remise à zéro est l'affectation des lumières et des matériaux avec les valeurs par défaut d'openGL.
          Cette méthode s'appelle 'razOpenGL'.
        Les autres méthodes sont assez compréhensibles. Pour ce qui est des variables utilisées, elles sont commentées dans l'entête de la classe et ont des noms assez explicites.

    4. Détail des fichiers :

      • SPA_x_wing
        Ce fichier contient les méthodes qui permettent de dessiner un vaisseau x_wing.
        Deux types de vaisseaux x_wing ont été implantés.
        D'une part un vaisseau en volume (méthodes précédées du mot 'Solid') et d'autre part un vaisseau en fil de fer (méthodes précédées du mot 'Wire').
        Ce fichier utilise des listes pour faciliter et optimiser l'implantation de certaines parties du vaisseau x_wing.
        Par exemple une liste a été utilisée pour créer les ailes. En effet le fait d'avoir 4 ailes identiques justifie le fait d'utiliser une liste pour ne pas avoir à répéter 4 fois les mêmes instructions.


      • SPA_TieRaptor.
        Ce fichier permet de dessiner un vaisseau de type Tie Raptor.
        Comme le fichier SPA_x_wing, ce fichier dessine deux type de vaisseau Tie Raptor. Un en fil de fer et l'autre en volume.
        Des listes sont également utilisées pour éviter la répétition de lignes d'instructions.


      • SPA_Tir.
        Ce fichier permet de dessiner un tir de vaisseau.
        Un tir n'est rien d'autre qu'un cylindre non fermé.


  4. Remarques concernant la programmation :

    1. Constructeurs :

      On peut remarquer dans les différents modules que la majorité des initialisations des variables membres des objets ne sont pas réalisées dans les constructeurs mais dans des fonctions d'initialisation (init). Cette approche semble étrange, car c'est le rôle du (ou des) constructeur(s) d'initialiser un objet. Cependant, dans la mesure où il est possible de sortir des différents modules et d'y revenir, ces méthodes permettent de réinitialiser un objet. Sans elles, il aurait été nécessaire de détruire et de recréer l'objet pour le remettre à son état d'origine.


    2. Utilisation de fichiers au sein de Space Invaders

      Il peut être légitime de se demander pourquoi de "simples" fichiers C sont présents dans le jeu Space Invaders, alors que le reste de l'application est en C++. Tout d'abord, l'abstraction de ces fichiers peut ne pas être considérée comme objet. En effet, ces fichiers ne contiennent aucune caractéristique propre, et leurs méthodes n'effectuent pas de traitements à proprement parler ; il ne s'agit en fait que d'instructions de dessin. D'autre part, il s'agit d'un choix conditionné par un souci de modularité. En effet, les dessins de X Wing, de Tie Raptor et des tirs peuvent sous cette forme être réutilisés dans un autre programme de la manière la plus simple qui soit.