Jeu de plateforme tangible

De Wiki de Projets IMA
Révision datée du 15 avril 2016 à 09:01 par Rex (discussion | contributions) (Partie Jeu)


Cahier des charges

Présentation générale du projet

Il s'agit de réaliser un système tangible qui à l'aide de cubes matérialise un niveau de jeu en 2D de type Mario. Ainsi dès le moment où nous disposons des cubes sur une surface,
ces cubes sont analysés puis ils apparaissent instantanément dans le jeu. Il est ainsi possible de modifier les niveaux pendant que l'utilisateur principal joue. On peut donc crée une infinité de niveaux.

Cahier des charges

Le dispositif devra être capable :
- De détecter des cubes matériels formant un "niveau".
- D'analyser ces cubes et de les convertir en numérique.
- De les intégrer à un jeu fonctionnant sur PC
- D'être suffisamment rapide pour que si une personne change des cubes le niveau du jeu s'actualise.

Choix techniques : matériel et logiciel

Après rendez-vous avec Mr Boé nous sommes partis sur une solution à base d'ARTag. En effet, nous allons devoir réaliser des cubes sur lesquels nous placerons des Tags qu'une webcam
pourra détecter et qu'un ordinateur pourra analyser à l'aide de la bibliothèque ARToolkit qui permet de faire du développement pour de la réalité augmentée. Il y aura plusieurs sortes de cubes
( Un cube de départ et de fin de niveau et des cubes simples de chemins ou de vides ) chacun de ces cubes aura sur lui un tag. Les cubes pourront avoir des tailles différentes selon ce qu'ils sont et ainsi augmenté le réalisme.


      Schéma du dispositif

Établissement d'une liste de matériel

En ce qui concerne le matériel nous aurons besoin :
- D'une webcam pour faire les acquisitions vidéos.[Fournie 27/01/2015]
- D'une raspberry Pi pour les traiter.[Fournie 27/01/2015]
- D'utiliser l'imprimante 3D afin de confectionner les cubes pour le jeu.

Contraintes attendues

- La position de la webcam par rapport aux cubes : positionner la webcam suffisamment loin pour avoir un nombre de cubes suffisant tout en faisant attention
à la résolution de la caméra.
- Les obstacles entre la caméra et les cubes : par exemple si une personne met sa main entre la webcam et les cubes ceux-ci vont disparaître dans le jeu.
- La détection de la position des cubes les uns par rapport aux autres.

Déroulement des séances

Semaine 1 et 2

Nous avons cette première semaine tenté de comprendre les différents programmes fournis par ArToolkit pour pouvoir l'adapter comme nous le souhaitions mais également d'installer et de configurer la Raspberry. Malheureusement après plusieurs tentatives nous avons constaté que la raspberry n'était pas assez puissante pour pouvoir faire tourner Artoolkit. Nous avons donc abandonné l'idée de la raspberry pour utiliser une webcam.

Semaine 3

A partir de cette semaine nous avons décidé de nous partager le projet, c'est-à-dire l'un de nous s'occupe de la partie jeu et l'autre de la partie Artoolkit.

Partie Artoolkit

Pour cette partie nous avons décidé d'utiliser un programme dont le code était fourni dans les exemples de la bibliothèque en le modifiant afin de le faire convenir à nos besoins. La première difficulté fut de comprendre le code car il utilise beaucoup de fonctions qui ne sont pas utiles à notre jeu de plateforme. Après analyse il a fallu supprimer toutes les fonctions d'animations 3D du programme. Après cela, il était nécessaire de pouvoir déterminer la position de plusieurs patterns de façon simultanée afin de pouvoir effectuer une comparaison de position les uns par rapport aux autres. Pour cela nous avons dû utiliser une variable fournie dans les bibliothèques d'Artoolkit à savoir patt_trans[3][4] qui est une matrice qui nous donne les coordonnées en x,y et en z du pattern par rapport à la caméra. Cela fait, il fallait maintenant comparer les positions des différents patterns par rapport à un cube de "départ" imposé. Pour cela il faut réaliser une boucle qui va vérifier la présence des patterns et si il y a présence, sauvegarder ses coordonnées et regarder par rapport aux coordonnées de la base mais cela ne fonctionne qu'en partie pour le moment.

Partie Jeu

Pour cette partie nous avons décidé d'utiliser le langage de programmation C pour programmer notre jeu avec l'aide de la bibliothèque SDL, qui permet de réaliser des Applications graphiques comme les jeux 2D ou 3D. Cette librairie correspond donc tout à fait avec ce que nous avons besoin dans notre projet. Nous avons donc du apprendre à manipuler cette librairie et ses nombreuses fonctions à l'aide de différents tutoriels trouvés sur internet. Nous avons ensuite choisi d'utiliser la technique de Tile Mapping de cette bibliothèque. Cette technique permet de créer un niveau de jeu à l'aide d'une matrice de nombres comprises à l'intérieur d'un fichier texte. Écrire et lire dans un fichier à partir d'un programme C étant dans nos compétences déjà acquises, nous pourrons donc plus facilement faire la liaison entre nos deux parties grâce à cette technique par l’intermédiaire de fichiers texte. Nous nous concentrons donc dans cette partie plus sur la programmation du jeu, par le traitement des fichiers texte, de la création et l’interaction avec les décors (collisions) puis de l'animation.

Semaine 4

Partie Conception

Nous avons réalisé les cubes sur l'imprimante 3D et nous avons donc du modifier le code car la taille n'était pas exactement la même que celle des cubes en cartons.

                                        Réalisation des cubes sur imprimante 3D

Partie Artoolkit

Après avoir rencontré des difficultés avec la détection sur les trois dimensions nous avons décidé d'effectuer des tests pour une dimension afin de simplifier dans un premier temps le code. Après plusieurs manipulations il s'est avéré qu'il fallait prendre en compte que la bibliothèque rendait le programme extrêmement précis ( pour un cube immobile on obtenait une marge d'erreur de 6 pour l'axe des x et 7 pour l'axe des y ). Ainsi il a été nécessaire d'incorporer cette marge d'erreur à notre code. On a ainsi obtenu le résultat escompté :
                                        Exemple de disposition des cubes      Résultat obtenu dans la console

Les différents chiffres présents dans la console identifient les patterns utilisés de la façon suivant :
1 pour le cube principal A
2 pour le cube B
3 pour le cube C etc..
Cela nous permettra par la suite lors de la programmation du jeu de pouvoir différencier des cubes représentant le sol, ceux qui représentent des tuyaux etc..

Code pour déterminer la position d'un cube

Partie Jeu

Certaines fonctions du jeu comme la fonction de création de niveau à partir du fichier texte, la gestion de l'animation du personnage et des collisions ont été réalisé et testé positivement.
Création du niveau à partir d'une matrice comprise dans un fichier texte :
                                             Création d'un level à partir d'un fichier texte


Nous avons ensuite implémenté une méthode de scrolling à notre programme. Des problèmes ont été rencontrés lors de la réunion de toutes ces fonctions. La solution fut finalement trouvée en équipe, nous avions oublié de prendre en compte l'animation du personnage dans le scrolling de l'écran. L'étape suivant est donc la mise en place d'une " gravité" , qui est en fait un forçage du personnage vers le bas , hors saut. Donc ensuite ajout au personnage la possibilité de sauter. Nous en sommes actuellement à ce point dans cette partie car il y a un problème de collision en l'air lors d'un saut.

Semaine 5

Partie Artoolkit

Nous avons rajouté dans le programme une fonction qui écrit la matrice du niveau dans un fichier texte afin de permettre à l'application du jeu de le lire pour pouvoir réaliser le niveau en scrolling.


                                             Résultat obtenu dans la console

Partie Jeu

L'installation de la gravité dans le jeu pour le personnage est finie avec résolution des problèmes de collision en l'air. Pour cela il a fallu prendre une décision : quand le joueur appuie sur une direction en y et en x et que le jeux détecte une collision uniquement dans la direction des x, nous avions la possibilité soit d'autoriser uniquement le mouvement du personnage vers l'axe des y, soit d'interdire tout mouvement. Nous avons donc décidé de choisir la deuxième solution , car dans le cas ou le personnage était déjà en l'air lors de cette collision, si on lui autorisait encore à monter sur l'axe des y , on avait une impression que le personnage volait le long des décors.

Semaine 6

Partie Artoolkit

Cette semaine nous nous sommes posés la question de la réunion de nos deux programmes.
Pour cela nous avons décidé d'utiliser des threads pour pouvoir faire tourner les deux programmes de façons simultanées. Nous avons également vu avec Mr Boé la semaine dernière qu'il nous faudrait trouver un moyen pour économiser des ressources du processeur car nous étions dans l'optique d'un scrolling de base à savoir que le jeu devait réactualiser la carte en continu pour éviter de manquer le changement de position d'un cube.
Ainsi nous sommes parvenu à une solution en écrivant une fonction qui somme la totalité de la valeur des cubes.
Fonction pour
Ainsi, en cas de changement de la valeur on passe une valeur chgt à 1 qui repasse à 0 le tour suivant. De cette façon, le programme du jeu ne doit recharger la map qu'en cas de modification de la variable changement.

Partie Jeu

Notre niveau était jusqu'à présent constitué de 2 types de tiles, soit un mur, donc l'impossibilité pour le personnage d'y passer à travers, soit du ciel. Nous allons ajouter pour un peu de plus de piquant à notre jeu, un nouveau type : le danger, qui fera perdre à notre personnage une vie lorsqu'il entrera en collision avec ce type de tiles. Pour pouvoir dire à notre programme comment réagir avec ce type de tiles, nous avons modifié la fonction de gestion des collisions ( qui retournait 0 ou 1 selon la détection d'une collision avec un mur ou non) en lui permettant de renvoyer un 2 lorsqu'une collision avec un danger a été détecté.

Voici donc notre nouvelle fonction détectant les collisions :
int CollisionDecor(Map* carte,Sprite* test)
{
    int xmin,xmax,ymin,ymax,i,j,indicetile;
    xmin = test->x / carte->LARGEUR_TILE;
    ymin = test->y / carte->HAUTEUR_TILE;
    xmax = (test->x + test->anim->largeurchar -1) / carte->LARGEUR_TILE;
     ymax = (test->y + test->anim->hauteurchar -1) / carte->HAUTEUR_TILE;
     if (xmin<0 || ymin<0 || xmax>=carte->nbtiles_largeur_monde || ymax>=carte->nbtiles_hauteur_monde)
         return 1;
     for(i=xmin;i<=xmax;i++)
     {
         for(j=ymin;j<=ymax;j++)
         {
             indicetile = carte->schema[i][j];
             if (carte->props[indicetile].mur )
                 return 1;
             if (carte->props[indicetile].danger )
                 return 2;
         }
     }
    return 0;
}


Nous avons donc en parallèle, rajouté un nouveau paramètre à notre petit personnage : ses vies, et donc la possibilité à notre programme de finir en GAME OVER. Pour que le jeu nous affiche un game over lorsque notre personnage n'a plus de vie, nous avons divisé notre programme d'une boucle en deux boucles distinctes. La première étant la boucle faisant tourner le jeu, prenant fin lorsque le joueur appuie sur la touche échap OU que son personnage n'a plus de vie. Le programme arrive alors dans la seconde boucle qui va simplement nous afficher une image de GAME OVER en attente d'une interruption généré par l'appui sur la touche espace, le programme s’arrête alors.

Semaine 7

Rassemblement

Cette semaine, nous avons travaillé sur la réunion de nos programmes. Nous avons dans un premier temps tenté une exécution séparée des deux programmes afin de vérifier que la lecture du fichier de scrolling ainsi que l'actualisation de la carte se faisait correctement. Cela fonctionne mais pour le moment nous actualisons la carte en appuyant sur la touche espace et nous tenterons la semaine prochaine de faire en sorte que cela se fasse en temps réel tout en rajoutant des améliorations du côté du jeu.



                                             Résultat obtenu

Partie Jeu

En parallèle du rassemblement, nous avons améliorer le contenu de notre jeu. Précédemment nous avions rajouté des vies à notre personnage, il nous faut donc maintenant afficher ce nombre de vie pour informer le joueur du nombre de vie qui lui reste. Comme de nombreux jeux de plateforme nous avons décidé d'afficher ce nombre de vie sous forme de cœur. Un cœur rouge représente une vie encore présente alors qu'un cœur vide représente une vie perdu. Pour programmer cela nous créons une nouvelle fonction avec une boucle sur le nombre de vie, on colle les cœurs de la gauche vers la droite, tant que nous sommes dans le nombre de vies restants , on colle des cœurs plein, sinon on colle des cœurs vides.

Semaine 8

Rassemblement

Cette semaine nous avons terminé la mise en place des threads. Pour ce faire nous avons créer une fonction qui parcourt la matrice en sommant les valeurs de presence[i][j] et en vérifiant par rapport à la fois précédente afin de voir s'il y a eu changement. Si aucun changement on continue, mais dans le cas contraire, le programme de la caméra bloque le mutex afin de pouvoir écrire dans le fichier texte puis libère le mutex pour laisser le champs libre au programme du jeu. ( PHOTO DU CODE )