Libgdx Game

dimanche 30 septembre 2012

TP Mario Sokobane avec Libgdx #8


---> Introduction
---> Contexte
---> Explication
---> Solution
---> Conclusion


Introduction

Si vous êtes en train de lire cet article c’est que vous avez fait un  assez bon parcours à travers mes précédents tutoriels sur la magnifique bibliothèque Libgdx, maintenant nous allons présenter dans ce tutoriel un récapitulatif de la majorité de ce qu’on a vu et cela en un seul code source.

Contexte 

On va réaliser un jeu simple et connu qui s’appelle Mario Sokobane. On va exploiter que les connaissances acquises dans les précédents tutoriels. Donc, je vous conseille d’essayer de réaliser se jeu en suivant les explications données, cela va vous faire un bon TP, et si vous avez essayé mais sans succès, ne vous en fait pas. Vous pouvais lire et comprendre le code source et  ceci vous sera très utile pour comprendre comment fonctionne les choses avec Libgdx 

Explication 

Le principe du Sokobane est connu, vous avez des cases qu’il faut les mettre dans des objectives.
Une fois tous les objectives remplit vous passez à un autre niveau
Il faut commencer par définir les ressources  à utilisées 

Les images :
les images que vous allez utiliser sont des images trouvées à l’aide de Google et modifiées pour avoir une taille de 32x32 ainsi qu’un fond transparent.
Objectif : image d’un objectif à remplir télécharger ici
Case : case qui va être poussé par le petit Mario, télécharger  ici
Case_ok : télécharger ici
Mur : mur infranchissable par mario, telecharger ici
Mariob : image de Mario se dirigeant vers le bas, télécharger ici
Marioh : image de Mario se dirigeant vers le haut, télécharger ici
Mariog : image de Mario se dirigeant vers la gauche, télécharger ici
Mariod : image de Mario se dirigeant vers la droite, télécharger ici
Haut : à clicker/presser pour deplacer mario vers le haut, télécharger ici
Bas : à clicker/presser pour deplacer mario vers le bas, télécharger ici
Droite : à clicker/presser pour deplacer mario vers la droite, télécharger ici
Gauche : à clicker/presser pour deplacer mario vers la gauche, télécharger ici
Bravo : image à afficher à la fin du jeu, télécharger ici

Vous pouvez telecharger le tout ici



Les fichiers textes :
Les fichiers textes représentent les cartes de chaque niveau, et chaque fichier représentant un niveau contient des chiffres qui représentent une image de la carte comme suite :














Une fois les ressources téléchargées, il faut bien sur les mettre dans le fichier assets des deux projets Android/Desktop que vous devez créer.

Le code source
Avant de commencer à voir comment sera mon code source que vous allez vous-même développer sachez qu’il existe plusieurs voir même meilleurs façons de réaliser ce jeu, donc  si vous estimez capable de le réaliser vous-même avec votre propre logique allez-y, sinon vous pouvez suivre ma logique de faire les choses, c’est à vous de voir.
Commencez par déclarez les variables qui vont définir les ressources à utiliser de type par exemple : Texture, Spritebatch …
Puis initialisez les dans la méthode create()
Créer une méthode qui charge un fichier texte selon un niveau donnés en paramètre, pour cela utilisez le stockage interne
Le déplacement de Mario se fera en 32px par 32px cela va vous faciliter la gestion des mouvements de Mario
Utiliser un tableau à deux dimensions qui contiendra la carte (le niveau) et qui va subir des modifications selon l’action des utilisateurs
Créer une fonction qui se charge des entrées utilisateurs
Créer une méthode qui se charge de dessiner le contenu de tableau en respectant la correspondance de chaque chiffre
C’était en grosso modo les grande étapes à effectuées, mais bien sûr il reste pas mal de chose à régler, tel que la fin de la partie, reprendre une partie, le menu du jeu…

La solution

Sachez que si vous n’avez pas réussi à programmer tout le jeu ceci n’est pas grave, le plus  important c’est d’essayer.
Voici maintenant le code source affiché :
Le code source est décomposé en 3 parties comme nous l’avons déjà expliqué dans un tutoriel précédant.

* La partie Logique :
package my.works.LibgdxMarioSokobane;

import java.io.IOException;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class JeuMario implements ApplicationListener {

          private SpriteBatch batch;    
          private Texture textureMariob;
          private Texture textureMariod;
          private Texture textureMariog;
          private Texture textureMarioh;
          private Sprite  spriteMario;
          private Texture textureBloc_ok;
          private Texture textureBloc;
          private Texture textureMur;
          private Texture textureObjective;
          private Texture textureBravo;
          private Texture textureDroite;
          private Texture textureGauche;
          private Texture textureBas;
          private Texture textureHaut;
         
          //Variable
           private int xMario;
           private int yMario;
           private int carte[][];
           private float xDoight,yDoight;
           private float stateTime1;   
           private boolean maintenu, jeuTermine;
           private int niveauPartie ;
          
//******************************* Charger un niveau ****************************************/
public void chargerCarte(int niveau) throws IOException {
       String fichier = null;
       if(niveau ==1)
             fichier = "carte1.txt";
       if(niveau ==2)
             fichier = "carte2.txt";
       if(niveau==3)
             fichier = "carte3.txt";
       if(niveau==4)
             fichier = "carte4.txt";
                   
      FileHandle file = Gdx.files.internal("texte/"+fichier);
                                       
      String contenu= file.readString();
      int k = 0;
      for(int i=0 ; i<=11 ; i++)
       {
              for(int j=0 ; j<=9 ; j++)
              {                  
                  carte[j][i] = Character.digit(contenu.charAt(k++), 10);
              }
              k+=2;
       }
}
          
 //************************Chercher position Mario dans la carte ***************************/
public void chercherMario(){
             
       for( int i = 0 ; i<=11 ; i++)
       {
             for(int j= 0 ; j<=9 ; j++)
             if(carte[j][i] == 5)
             {
                           xMario = j;
                           yMario = (11-i);
                           carte[j][i] =1;
             }
       }
}     
//*****************************************************************************************/
       @Override
public void create() {
            
        batch = new SpriteBatch();
        textureMariob = new Texture(Gdx.files.internal("texture/mariob.png"));
        textureMariod = new Texture(Gdx.files.internal("texture/mariod.png"));
        textureMariog = new Texture(Gdx.files.internal("texture/mariog.png"));
        textureMarioh = new Texture(Gdx.files.internal("texture/marioh.png"));
        textureBloc_ok = new Texture(Gdx.files.internal("texture/block_ok.png"));
        textureBloc = new Texture(Gdx.files.internal("texture/block.png"));
        textureMur = new Texture(Gdx.files.internal("texture/mur.png"));
        textureObjective = new Texture(Gdx.files.internal("texture/objective.png"));
        textureBravo = new Texture(Gdx.files.internal("texture/bravo.png"));
       
        textureBas = new Texture(Gdx.files.internal("texture/bas.png"));
        textureHaut = new Texture(Gdx.files.internal("texture/haut.png"));
        textureDroite = new Texture(Gdx.files.internal("texture/droite.png"));
        textureGauche = new Texture(Gdx.files.internal("texture/gauche.png"));
   
        spriteMario = new Sprite(textureMariob, 0, 0,32, 32);
        carte = new int [10][12];
       
        jeuTermine = false;
        niveauPartie = 1;
      
        try {
                    chargerCarte(niveauPartie);
             } catch (IOException e) {
                   
                    e.printStackTrace();
             }
       
        chercherMario();
       }

       @Override
       public void dispose() {
       }
       @Override
       public void pause() {
       }
//************************* Affichage Graphique de la carte*********************************/
public void chargerCarteGraphique(){
             for(int i = 0; i<=9 ; i++)
             {
                    for(int j = 0 ; j<=11 ; j++)
                    {
                           switch(carte[i][j])
                           {
                           case 0 :
                           batch.draw(textureMur,i*32,(11-j)*32+96);
                                  break;
                           case 2 :
                           batch.draw(textureBloc,i*32,(11-j)*32+96);
                                  break;
                           case 3 :
                           batch.draw(textureObjective,i*32,(11-j)*32+96);
                                  break;
                           case 4 :
                           batch.draw(textureBloc_ok,i*32,(11-j)*32+96);
                               break;
                           }
                    }
             }
             batch.draw(textureBas, 210, 20);
             batch.draw(textureHaut, 265, 20);
             batch.draw(textureGauche, 10, 22);
             batch.draw(textureDroite, 80, 20);
            
       }
// *********************************Gestion des entrées ***********************************/

public void gestionDesEntrees()
{
       Gdx.input.setInputProcessor(new InputProcessor() {
            
             @Override
             public boolean touchUp(int x, int y, int arg2, int arg3) {

                    maintenu =false;
                    return false;
             }
            
             @Override
             public boolean touchMoved(int arg0, int arg1) {
                    return false;
             }
            
             @Override
             public boolean touchDragged(int arg0, int arg1, int arg2) {
                    return false;
             }
            
             @Override
             public boolean touchDown(int x, int y, int arg2, int arg3) {
                    xDoight = x;
                    yDoight = y;
                   maintenu = true;
                    return false;
             }
            
             @Override
             public boolean scrolled(int arg0) {
                    return false;
             }
            
             @Override
             public boolean keyUp(int arg0) {
                    return false;
             }
            
             @Override
             public boolean keyTyped(char arg0) {
                    return false;
             }
            
             @Override
             public boolean keyDown(int arg0) {
                    return false;
             }
       });
}

//****************************** Gestion deplacement Mario *********************************/
public void DeplacementMario()
{
       gestionDesEntrees();
       // Gérer deplacement Mario vers le haut
       if(xDoight>260 && xDoight<324 && yDoight>384 && yDoight<480 && maintenu)
       { // si le doit est posé sur la flèche haut faire :
             maintenu = false;
             if(yMario < 11)
             {
                    switch(carte[xMario][11-(yMario)-1]){
                    case 0 :
                    break;
                    case 1  :
                           yMario++;
                        break;
                    case 3 :
                           yMario++;
                                  break;
                    case 2 :
                        if(yMario< 10)
                           {
                                   stateTime1 += Gdx.graphics.getDeltaTime();
                                if( stateTime1 > 0.008)
                                   {
                               switch(carte[(xMario)][11-(yMario)-2]){
                                  case 1:
                                        carte[(xMario)][11-(yMario)-2]=2;
                                        carte[(xMario)][11-(yMario)-1]=1;
                                        yMario++;
                                        stateTime1 = Gdx.graphics.getDeltaTime();  
                                  break;
                                  case 3:
                                        carte[(xMario)][11-(yMario)-2]=4;
                                        carte[(xMario)][11-(yMario)-1]=1;
                                        yMario++;
                                        stateTime1 = Gdx.graphics.getDeltaTime(); 
                                  break;
                                 
                               default :break;
                                  }
                                  }
                                  }
                           break;
                    case 4:
                           if(xMario< 10)
                           {
                            stateTime1 += Gdx.graphics.getDeltaTime();
                           if( stateTime1 > 0.008)
                           {
                        switch(carte[(xMario)][11-(yMario)-2]){
                           case 1:
                                  carte[(xMario)][11-(yMario)-2]=2;
                                  carte[(xMario)][11-(yMario)-1]=3;
                                  yMario++;
                                  stateTime1 = Gdx.graphics.getDeltaTime();  
                           break;
                           case 3:
                                  carte[(xMario)][11-(yMario)-2]=4;
                                  carte[(xMario)][11-(yMario)-1]=3;
                                  yMario++;
                                  stateTime1 = Gdx.graphics.getDeltaTime(); 
                           break;
                          
                        default :break;
                           }
                           }
                           }
                    break;
                           }
                           }
                           spriteMario = new Sprite(textureMarioh, 0, 0,32, 32);
                    }
       // Gerer deplacement Mario vers le bas
       if(xDoight>215 && xDoight<260 && yDoight>384 && yDoight<480 && maintenu)
       { // si le doit est posé sur la flèche bas faire :
             maintenu = false;
                    if(yMario >0)
                    {
                           switch(carte[xMario][11-(yMario)+1]){
                           case 0 :
                                  break;
                           case 1 :
                            yMario--;
                                  break;
                           case 3 :
                                  yMario--;
                                  break;
                           case 2 :
                                  if(yMario>1)
                                  {
                                   stateTime1 += Gdx.graphics.getDeltaTime();
                                  if( stateTime1 > 0.008)
                                  {
                               switch(carte[(xMario)][11-(yMario)+2]){
                                  case 1:
                                        carte[(xMario)][11-(yMario)+2]=2;
                                        carte[(xMario)][11-(yMario)+1]=1;
                                        yMario--;
                                        stateTime1 = Gdx.graphics.getDeltaTime();  
                                  break;
                                  case 3:
                                        carte[(xMario)][11-(yMario)+2]=4;
                                        carte[(xMario)][11-(yMario)+1]=1;
                                        yMario--;
                                        stateTime1 = Gdx.graphics.getDeltaTime(); 
                                  break;
                               default :break;
                                  }
                                  }
                                  }
                           break;
                           case 4:
                           if(yMario>1)
                           {
                            stateTime1 += Gdx.graphics.getDeltaTime();
                           if( stateTime1 > 0.008)
                           {
                        switch(carte[(xMario)][11-(yMario)+2]){
                           case 1:
                                  carte[(xMario)][11-(yMario)+2]=2;
                                  carte[(xMario)][11-(yMario)+1]=3;
                                  yMario--;
                                  stateTime1 = Gdx.graphics.getDeltaTime();  
                           break;
                           case 3:
                                  carte[(xMario)][11-(yMario)+2]=4;
                                  carte[(xMario)][11-(yMario)+1]=3;
                                  yMario--;
                                  stateTime1 = Gdx.graphics.getDeltaTime(); 
                           break;
                        default :break;
                           }
                           }
                           }
            
                           }
                           }
                           spriteMario = new Sprite(textureMariob, 0, 0,32, 32);
                    }
       // Gerer le demplecement de Mario vers la droite
       if(xDoight>70 && xDoight<130 && yDoight>384 && yDoight<480 && maintenu)
             { // si le doit est posé sur la flèche droite faire :
             maintenu = false;
                           if(xMario < 9)
                           {
                           switch(carte[(xMario)+1][11-(yMario)]){
                           case 0 :
                                  break;
                           case 1 :
                                  xMario++;
                                  break;
                           case 3 :
                                  xMario++;
                                  break;
                           case 2 :
                                  if(xMario < 8)
                                  {
                                        stateTime1 += Gdx.graphics.getDeltaTime();
                                        if( stateTime1 > 0.008)
                                        {
                                      switch(carte[(xMario)+2][11-(yMario)]){
                                        case 1:
                                               carte[(xMario)+2][11-(yMario)]=2;
                                               carte[(xMario)+1][11-(yMario)]=1;
                                              
                                               xMario++;
                                       
                                               stateTime1 = Gdx.graphics.getDeltaTime(); 
                                        break;
                                        case 3:
                                               carte[(xMario)+2][11-(yMario)]=4;
                                               carte[(xMario)+1][11-(yMario)]=1;
                                               xMario++;
                                               stateTime1 = Gdx.graphics.getDeltaTime(); 
                                        break;
                                              
                                   default :break;
                                        }
                                        }
                                       
                                  }
                           break;
                           case 4 :
                                  if(xMario < 10)
                                  {
                                        stateTime1 += Gdx.graphics.getDeltaTime();
                                        if( stateTime1 > 0.008)
                                        {
                                      switch(carte[(xMario)+2][11-(yMario)]){
                                        case 1:
                                               carte[(xMario)+2][11-(yMario)]=2;
                                               carte[(xMario)+1][11-(yMario)]=3;
                                               xMario++;
                                               stateTime1 = Gdx.graphics.getDeltaTime(); 
                                        break;
                                        case 3:
                                               carte[(xMario)+2][11-(yMario)]=4;
                                               carte[(xMario)+1][11-(yMario)]=3;
                                               xMario++;
                                               stateTime1 = Gdx.graphics.getDeltaTime(); 
                                        break;
                                              
                                   default :break;
                                        }
                                        }
                                       
                                  }
                                 
                           }
                           }
                          
                           spriteMario = new Sprite(textureMariod, 0, 0,32, 32);
                    }
       // Gerer deplacement mario vers la gauche
       if(xDoight>8 && xDoight<70 && yDoight>384 && yDoight<480 && maintenu)
                    { // si le doit est posé sur la flèche gauche faire :
             maintenu =false;
      
                           if(xMario > 0)
                           {
                           switch(carte[(xMario)-1][11-(yMario)]){
                           case 0 :
                                  break;
                           case 1 :
                           xMario--;
                                  break;
                           case 3 :
                                  xMario--;
                                  break;
                           case 2 :
                                  if(xMario>1)
                                  {
                                   stateTime1 += Gdx.graphics.getDeltaTime();
                                  if( stateTime1 > 0.008)
                                  {
                               switch(carte[(xMario)-2][11-(yMario)]){
                                  case 1:
                                        carte[(xMario)-2][11-(yMario)]=2;
                                        carte[(xMario)-1][11-(yMario)]=1;
                                        xMario--;
                                        stateTime1 = Gdx.graphics.getDeltaTime();  
                                  break;
                                  case 3:
                                        carte[(xMario)-2][11-(yMario)]=4;
                                        carte[(xMario)-1][11-(yMario)]=1;
                                        xMario--;
                                        stateTime1 = Gdx.graphics.getDeltaTime(); 
                                  break;
                               default :break;
                                  }
                                  }
                                  }
                           break;
                           case 4 :
                                  if(xMario>1)
                                  {
                                   stateTime1 += Gdx.graphics.getDeltaTime();
            
                                  if( stateTime1 > 0.008)
                                  {
            
                               switch(carte[(xMario)-2][11-(yMario)]){
                                  case 1:
                                        carte[(xMario)-2][11-(yMario)]=2;
                                        carte[(xMario)-1][11-(yMario)]=3;
                                        xMario--;
                                        stateTime1 = Gdx.graphics.getDeltaTime();  
                                  break;
                                  case 3:
                                        carte[(xMario)-2][11-(yMario)]=4;
                                        carte[(xMario)-1][11-(yMario)]=3;
                                        xMario--;
                                        stateTime1 = Gdx.graphics.getDeltaTime(); 
                                  break;
                               default :break;
                                  }
                                  }
                                  }
                           }
                           }
                           spriteMario = new Sprite(textureMariog, 0, 0,32, 32);
                    }
             }
// ************************** Gérer la fin d'un niveau ***********************************//
public boolean partieFini(){
       int cpt = 0;
       for( int i = 0 ; i<=11 ; i++)
       {
             for(int j= 0 ; j<=9 ; j++)
             if(carte[j][i] == 3)
             {
                    cpt++;
             }
       }
       if(cpt ==0)
           return true;
       else
             return false;
}
//**************************** Gerer le Rechargement d'un niveau ***************************/
public void rechargerNiveau()
{
       gestionDesEntrees();

       if(yDoight<384)
             try {
                    chargerCarte(niveauPartie);
                    chercherMario();
             } catch (IOException e) {
                    e.printStackTrace();
             }
}
/*******************************************************************************************/
       @Override
       public void render() {
             Gdx.gl.glClearColor(1, 1, 1, 0);
             Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
             if(!jeuTermine)
       {
              batch.begin();

              chargerCarteGraphique();
              spriteMario.setPosition(xMario*32, yMario*32 + 96);
              spriteMario.draw(batch);

              batch.end();
              
              DeplacementMario();
              rechargerNiveau();
            
              if(partieFini())
              {
                     niveauPartie ++;
                     if(niveauPartie <=4)
                     {
                     try {
                           chargerCarte(niveauPartie);
                           chercherMario();
                     } catch (IOException e) {
                           e.printStackTrace();
                    }
                     }else
                       jeuTermine = true;
              }
             }
             else
             {
                    batch.begin();
                    batch.draw(textureBravo, 40, 100);
                    batch.end();
             }
       }

       @Override
       public void resize(int arg0, int arg1) {
       }

       @Override
       public void resume() {
       }
}

* La partie Desktop : elle contient le code lanceur de l’application sous Desktop
package my.works.LibgdxMarioSokobane;

import com.badlogic.gdx.backends.jogl.JoglApplication;

public class Lanceur {

       public static void main(String[] args) {
        new JoglApplication (new JeuMario(),"Mario Sokobane",320,480,false);
       }

}

* La partie Android : elle contient le code lanceur de l’application sous Android
package my.works.LibgdxMarioSokobaneAndroid;

import com.badlogic.gdx.backends.android.AndroidApplication;
import my.works.LibgdxMarioSokobane.JeuMario;
import android.os.Bundle;

public class Main extends AndroidApplication {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initialize(new JeuMario(), false);
    }
}

La partie logique se trouve dans le projet desktop avec le lanceur de l’application, contrairement au lanceur Android qui se trouve dans un projet appart. Ceci a été déjà bien expliqué dans un tutoriel précédant.

* Voici le résultat sous le Desktop






















* Et voilà quelques captures du jeu que je l’ai lancé à travers mon Smartphone





















Vous pouvez aussi télécharger le code source ici

Conclusion

Bon, voilà la fin de ce tutoriel ! Mais sachez qu’il  reste pas mal de chose à explorer avec Libgdx et ce n’est que le début, et je répète encore une fois l’important avec ce tutoriel c’est d’essayer de coder puis voir et comprendre la solution si vous n’y arrivez pas.
Si vous avez des remarques ou des questions n’hésitez pas à les poster en commentaire. Merci pour votre lecture.


6 commentaires:

  1. Bonjour, j'aurais une question. Je n'ai pas vraiment compris la phrase "Les fichiers textes représentent les cartes de chaque niveau, et chaque fichier représentant un niveau contient des chiffres qui représentent une image de la carte", donc je ne sais pas comment faire ces cartes. Pourriez vous être plus précis dans la façon de les faire ?

    RépondreSupprimer
  2. Les fichiers ne sont plus disponibles. Pouvez vous les réuploader s'il vous plait.

    RépondreSupprimer
  3. Merci pour avoir remis les images. Par contre le code source distribué sur packupload n'est toujours pas disponible :(

    RépondreSupprimer
  4. Bonjour,

    J'ai essayé tes sources pour voir le résultat et je ne sais pas si cela est normal mais une fois exécuté sur mon Nexus 7, la cartede ton sokoban à la taille d'un 3310 et les évènements sur les boutons ne fonctionnent pas...

    RépondreSupprimer
  5. Serait-il possible de ré-uploader le code source ce super tuto ? ( dropbox, mega , drive ... )
    Merci d'avance

    RépondreSupprimer
  6. BONJOUR MONSIEUR merci pour ce tuto il est bien tres interessant mais mon probleme que le jeux reste bloqhant il ne bouge pas pas de deplacement et merci

    RépondreSupprimer