Libgdx Game

dimanche 28 avril 2013

Manipuler la camera 2D avec libgdx #10


Introduction

Libgdx possède une camera 2d qu’on peut facilement la manipuler pour l’utiliser dans des jeux et même des applications. La caméra 2d fournissent plusieurs fonctionnalité on va voir quelques une dans ce tutoriel

Pour quoi une caméra ?

Une Caméra parce qu’on peut la manipuler comme une vrai camera c’est ç dire la faire bouger dans toutes directions et aussi ‘effectuer des rotations et de zoomer et dézoomer.

Besoin d’une camera

L’utilisation d’une caméra est très pratique pour la réalisation d’un jeu ou bien une application dont celle-ci a besoin de la fonctionnalité du zoom, exemple : Une application qui vous permet de visualiser des photos et de faire un zoom sur ces photos, Un jeu RPG qui possède une grande carte qu’on peut se déplacer là-dedans.

Opérations principales

-          Bouger la camera
-          Zoomer et dézoomer
-          Rotation

Othographic camera

* Initialiser position de la camera 
camera = new OrthographicCamera(largeur_Ecran,hauteur_Ecran);
camera.position.set(largeur_Ecran*0.5f, hauteur_Ecran*0.5f, 0);
* pour qu’on puisse prendre en considération la modification sur camera
camera.update();
* pour lier la camera au spriteBatch.
batch.setProjectionMatrix(camera.combined);

* Définir le cadre de la camera :
GL10 gl = Gdx.graphics.getGL10(); 
gl.glViewport(0,0,largeur_Ecran,hauteur_Ecran);
camera.apply(gl);         

* Déplacer la camera
Vers le haut :
camera.translate(0, +1);
Ou aussi :
camera.position.y-- ;
Vers le bas :
camera.translate(0, -1);
Ou aussi :
camera.position.y-- ;
Vers la droite :
camera.translate(1, 0);
Ou aussi :
camera.position.x++ ;
Vers gauche :
camera.translate(-1, 0);
Ou aussi :
camera.position.x-- ;
* Zoom camera :
En avant :
camera.zoom-=0.1f;
En arrière :
camera.zoom-=0.1f;
* Rotation camera :
Vers la droite :     
camera.rotate(-0.05f);
vers la gauche :
camera.rotate(0.05f);
Exemple pratique
Dans cet exemple on va manipuler une caméra en la déplaçant dans tous les sens, faire des rotations, zoomer sur l’écran.
J’ai choisi une carte qui représente un terrain d’un jeu pour effectuer l’exemple. ici pour télécharger la carte


Manipulation de la camera :

Pour manipuler la camera sous le Desktop on utilise le clavier : les touches haut, bas, droite, gauche, pour bouger la camera dans tous les sens et la touche ‘z’ et la touche ‘e’ pour zoomer en avant et en arrière.
Pour manipuler la camera sous Android on utilise les gestes tactiles tels que le pinch, zoom, pan … pour implémenter ces gestes on fait appel au listener GestureListener qui peut détecter ces gestes (voir tutoriel précédant).
Ou encore on peut l’implémenter nous-même grâce à la classe InputListener par exemple le zoom c’est deux doigt qui se rapproche l’un deux l’autre donc pour détecter un tel geste on calcule la distance entre les coordonnés du premier doigt et les coordonnés du deuxième doigt.
D = (x0 – x1)2  + (y0-y1)2
Puis on compare ce résultat avec la prochaine distance calculée
* Voici le code source nous permettons d’effectuer quelques fonctionnalités de la camera 2D Libgdx
package my.works.Article;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;


public class CameraExemple1 implements ApplicationListener{

      
       public static float vitesse_zoom = 0.02f;
       public static float vitesse_deplacement_camera = 2;

       public static float max_zoom = 1f;    // maximum qu'on peut zoomer
       public static float min_zoom = 0.5f;  // minimum qu'on peut zoomer
        
       private int limite_image_maxHauteur// limite déplacement camera
       private int limite_image_maxLargeur// limite déplacement camera
       public static int limite_image_minHauteur = 0;    // limite déplacement camera
       public static int limite_image_minLargeur = 0 ;   // limite déplacement camera
      
      
       private int largeur_Ecran ;
       private int hauteur_Ecran ;
      
       private SpriteBatch batch;
       private Texture mapTexture;
       private OrthographicCamera camera;
      
       int x0,y0,x1,y1// position du premier et deuxième doigt
      
       int lastx0 ;      // précédente position du 1er doigt
       int lasty0 ;      // précédente position du 1er doigt
      
       int lastx1 ;      // précédente position du 2eme doigt posé sur l'écran
       int lasty1 ;      // précédente position du 2eme doigt posé sur l'écran
      
      
       @Override
       public void create() {

           largeur_Ecran = Gdx.graphics.getWidth();
           hauteur_Ecran = Gdx.graphics.getHeight();
            
      batch = new SpriteBatch();
            
           mapTexture = new Texture(Gdx.files.internal("map.png"));
          
             camera = new OrthographicCamera(largeur_Ecran,hauteur_Ecran);
             camera.position.set(largeur_Ecran*0.5f, hauteur_Ecran*0.5f, 0);
             camera.update();
            
             limite_image_maxHauteur = mapTexture.getHeight() /2;
             limite_image_maxLargeur = mapTexture.getWidth() /2;
            
             limite_image_minHauteur = hauteur_Ecran/2;
             limite_image_minLargeur = largeur_Ecran/2;
              }

       @Override
       public void dispose() {
       }

       @Override
       public void pause() {
       }

       @Override
       public void render() {
        
         GL10 gl = Gdx.graphics.getGL10(); 
         gl.glClear(GL10.GL_COLOR_BUFFER_BIT);  
   
         gl.glViewport(0,0,largeur_Ecran,hauteur_Ecran);
         camera.apply(gl);         
         camera.update();   
        
         manipulerCameraDesktop();
         manipulerCameraAndroid();
        
         batch.setProjectionMatrix(camera.combined);
      
         batch.begin();
         batch.draw(mapTexture, 0, 0);
         batch.end();
       }

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

//*********************** Manipuler la camera*******************************//

public void manipulerCameraDesktop()
{
       if(Gdx.input.isKeyPressed(Keys.UP))  // si on appuie sur la touche haut
       {
             if(camera.position.y<limite_image_maxHauteur) // limiter déplacement vers haut
             camera.translate(0, +1);
       }
       if(Gdx.input.isKeyPressed(Keys.DOWN))  // si on appuie sur la touche bas
       {
             if(camera.position.y>limite_image_minHauteur// limiter déplacement vers bas
             camera.position.y--;
                   
       }
       if(Gdx.input.isKeyPressed(Keys.RIGHT))  // si on appuie sur la touche droite
       {
         if(camera.position.x<limite_image_maxLargeur// limiter déplacement vers droite
          camera.position.x++;
       }
       if(Gdx.input.isKeyPressed(Keys.LEFT))  // si on appuie sur la touche gauche
       {
             if(camera.position.x>limite_image_minLargeur// limiter déplacement vers gauche
             camera.position.x--;
       }
       if(Gdx.input.isKeyPressed(Keys.Z))  // si on appuie sur la touche Z
       {
             if(camera.zoom<max_zoom// limiter le zoom arrière
             camera.zoom+=vitesse_zoom;
       }
       if(Gdx.input.isKeyPressed(Keys.E))// si on appuie sur la touche E
       {
             if(camera.zoom>min_zoom// limiter le zoom avant
             camera.zoom-=vitesse_zoom;
       }
       if(Gdx.input.isKeyPressed(Keys.R))// si on appuie sur la touche R
       {
             camera.rotate(0.05f);   // rotation vers la gauche
       }
       if(Gdx.input.isKeyPressed(Keys.A))// si on appuie sur la touche A
       {
             camera.rotate(-0.05f); //  rotation vers la droite
       }
       if(Gdx.input.isKeyPressed(Keys.M))// si on appuie sur la touche M
       {
             if(camera.viewportWidth<1024)
             camera.viewportWidth++;
       }
       if(Gdx.input.isKeyPressed(Keys.K))// si on appuie sur la touche K
       {
             if(camera.viewportWidth>320)
             camera.viewportWidth--;
       }
       if(Gdx.input.isKeyPressed(Keys.O))// si on appuie sur la touche O
       {
             if(camera.viewportHeight<512)
             camera.viewportHeight++;
       }
       if(Gdx.input.isKeyPressed(Keys.L))// si on appuie sur la touche L
       {
             if(camera.viewportHeight>320)
             camera.viewportHeight--;
       }
                   
       }

       public void manipulerCameraAndroid()
       {
             Gdx.input.setInputProcessor(new InputProcessor() {
                   
                    @Override
                    public boolean touchUp(int x, int y, int pointer, int bouton) {
                   
                           return false;
                    }
                   
                    @Override
                    public boolean touchDown(int x, int y, int pointer, int bouton) {
                   
                           return false;
                    }
                   
                    @Override
                    public boolean touchDragged(int x, int y, int pointer) {
                   
                   
             // ************** Saisir les coordonnées actuelles    ********************/
                           if(pointer==1) // Pour le 2eme doigt
                           {
                                  x1=x;
                                  y1=y;
                           }
                           if(pointer==0) // Pour le 1er doigt
                           {
                                  x0=x;
                                  y0=y;
                           }
                          
             /*********** Opération : Zoom sur carte *******************************/
      
             if(Gdx.input.isTouched(1)) // si deux doigt sont posés sur l'écran                                   {
       // Comparer entre la distance actuelle (entre les 2 doigts) et la distance précédente
       if(Math.pow(x0-x1,2)+Math.pow(y0-y1,2)>Math.pow(lastx0-lastx1,2)+Math.pow(lasty0-lasty1,2))
       {
             if(camera.zoom>min_zoom// limite du zoom avant
             camera.zoom-=vitesse_zoom;
       }
       else
       {
             if(camera.zoom<max_zoom// limite du zoom arrière
             camera.zoom+=vitesse_zoom;
       }
       }     
                          
             /********** Operation : Déplacer camera avec un doigt ******************/
                   
       if(!Gdx.input.isTouched(1))             // si un seul doigt est posé sur l'écran
       {
            
             // les quatres directions principales :
             //-------------------------------------
       if(y0-lasty0>0 && x0-lastx0<5 &&  x0-lastx0>-5 )  // si drag vers haut avec tolérance sur x
       {
              if(camera.position.y<limite_image_maxHauteur) // limite de la camera
             {
                    camera.translate(0, vitesse_deplacement_camera);
             }
       }
       else
       {
             if(y0-lasty0<0 && x0-lastx0<5 &&  x0-lastx0>-5)   // Si drag vers bas
             {
                if(camera.position.y>limite_image_minHauteur) // Limite de la camera en bas
                {
                    camera.translate(0, -vitesse_deplacement_camera);
                }
             }
       }
       if(x0-lastx0<0 && y0-lasty0>-5 && y0-lasty0<5)    // Si drag vers droite
       {
             if(camera.position.x<limite_image_maxLargeur) // Limite de la camera a droite
             {
                    camera.translate(vitesse_deplacement_camera, 0);
             }
       }
       else
       {
             if(x0-lastx0>0 && y0-lasty0>-5 && y0-lasty0<5)     // Si drag vers gauche
             {
                    if(camera.position.x>limite_image_minLargeur// Limite de la camera à gauche
                    {
                           camera.translate(-vitesse_deplacement_camera, 0);
                    }
             }
       }
       }
                          
       // ********* Sauvgarder les coordonnées ****************************/
                          
                           if(pointer==1) //  2eme doigt
                           {
                                 lastx1 = x1;
                                  lasty1 = y1;
                           }
                           if(pointer==0)//   1er doigt
                           {
                                  lastx0 = x0;
                                  lasty0 = y0;
                           }
                           return false;
                    }
                   
                    @Override
                    public boolean scrolled(int arg0) {
                           // TODO Auto-generated method stub
                           return false;
                    }
                   
                    @Override
                    public boolean mouseMoved(int arg0, int arg1) {
                           // TODO Auto-generated method stub
                           return false;
                    }
                   
                    @Override
                    public boolean keyUp(int arg0) {
                           // TODO Auto-generated method stub
                           return false;
                    }
                   
                    @Override
                    public boolean keyTyped(char arg0) {
                           // TODO Auto-generated method stub
                           return false;
                    }
                   
                    @Override
                    public boolean keyDown(int arg0) {
                           // TODO Auto-generated method stub
                           return false;
                    }
             });
      
            
       }

}


* Voici le résultat sous desktop
Bien sûr, il faut la classe lanceur pour lancer l’application sous Desktop voir précédant tutoriel



Conclusion

La camera est très pratique est son utilisation ne se limite pas aux exemples vus dans ce tutoriel. Si vous avez des remarques ou des questions n’hésitez pas à les poster en commentaire. Merci pour votre lecture.

9 commentaires:

  1. Un grand merci pour tout le mal que tu te donnes pour nous faire des tutoriels toujours aussi excellents.
    Tu es le seul proposant des tuto en langue française ! Libgdx est déjà un challenge pour le novice que je suis mais devoir se dépatouiller avec des tuto anglais c'est mission impossible, heureusement tu es la ;)
    Encore merci, j’attends la suite avec impatience XD

    RépondreSupprimer
  2. tout le plaisir est pour moi !

    RépondreSupprimer
  3. Une idée me viens, pourquoi ne crées-tu pas un forum ? Ce serrai intéressant de pouvoir partager nos expériences avec Libgdx, de créer une communauté francophone (il n'en existe pas encore à ma connaissance).

    RépondreSupprimer
  4. bonjour , je veux vous dire d'abord merci pour ce blog qui m'aide vraiment beaucoup !
    je voudrais vous poser une question : si mon jeux comporte une grande carte et que je veux l'afficher au fur et a mesure que le personnage avance vers le haut , comment dois je faire , est ce en utilisant le camera , et si oui , comment ?
    merci d'avance !

    RépondreSupprimer
    Réponses
    1. Ouais tu peux utiliser cette camera. Par exemple lorsque tu décides que ton personnage peut avancer vers le haut, tu peux faire:

      yPosPerso+=vitesse_perso;
      positionYPixel+=vitesse_perso;
      if(camera.position.y<limite_image_maxHauteur)
      camera.translate(0, +vitesse_perso);

      Supprimer
  5. Bonjour, merci d'abord pour ces tutoriels qui m'ont beaucoup appris.
    J'ai également une question à propos du système de caméra : j'aimerai savoir si il est possible de dissocier les coordonnées en x et y du jeu à celle de windows. Je m'explique : quand je clique sur une image dans ma fenêtre de jeu, je peut récupérer une coordoonées en x et y, cependant si je réalise un zoom ou une translation de caméra mon objet va changer de position par rapport à l'écran et quand je voudrai récupérer ses coordonnées à l'aide d'un clique elles seront différentes de celle initiale. Savez-vous comment éviter ce problème? Merci d'avance .

    RépondreSupprimer
    Réponses
    1. Bonjour ;
      J'ai bien compris votre problème en attendant a ce que je fasse un petit tuto là-dessus je vous explique rapidement comment moi je fais les choses
      Quand on zoom dans un écran sur un objet ça position change le principe ici c’est de convertir cette position avec une formule mathématique pour qu’elle reste toujours la même position première (la position avec non zoom [camera.zoom =1]).
      Par exemple les coordonné d’un objet placé dans un écran est x= 200 y = 300 quand on zoom de x2 l’écran (camera.zoom =2 )ça position devient (par exemple )x= 400 y = 500
      Le principe c’est de mettre en considération que 400 et 500 de zoom x2 sont respectivement 200 et 300 de zoom x1 et cela on le convertant
      200= XFromule (400) plus générale ( xPosition non zoom ) = xFormule ( xPosition avec zoom)
      Voici les formules que j’utilise
      public float xzunit(float x)
      {
      float resultat = 0;
      if(x<largeur_ecran * 0.5f)
      resultat= (int) ((x - (largeur_ecran - largeur_ecran/camera.zoom))*0.5f)*camera.zoom);
      else
      resultat= (int) (((x-largeur_ecran+ ((largeur_ecran-(largeur_ecran/camera.zoom))*0.5f))*camera.zoom)+largeur_ecran);

      return resultat;
      }
      public float yzunit(float y)
      {
      float resultat = 0;
      if(y<hauteur_ecran * 0.5f)
      resultat= (int) ((y - (hauteur_ecran - (hauteur_ecran/camera.zoom))*0.5f)*camera.zoom);
      else
      resultat= (int) (((y-hauteur_ecran+ ((hauteur_ecran-(hauteur_ecran/camera.zoom))*0.5f))*camera.zoom)+hauteur_ecran);

      return resultat;
      }

      Vous n’avez qu’ à utiliser ses deux fonction
      X = Xzunit (x) ;
      Y = Yzunit (z) ;
      Attention ceci marche que pour le zoom par rapport au centre de l’écran
      N’hésitez pas si vous avez plus de question
      Bonne continuation

      Supprimer
    2. Merci beaucoup pour cette réponse ! J'avais trouvé une solution similaire pour la translation de caméra mais je n'avais pas pensé à cela pour le zoom. Merci encore !

      Supprimer
  6. Tu ne fais plus de tutoriels ? ._.
    Pourrais tu en faire un sur le module audio ? =)
    Sinon, merci, vraiment du bon boulot ;)

    RépondreSupprimer