Libgdx Game

lundi 6 août 2012

Graphique avec Libgdx #6


---> Introduction
---> Le haut et le bas niveau
---> Les ressources graphiques
---> OpenGL avec Libgdx
---> Graphique 2D :
  - Insérer une image
  - Afficher du texte
  - Dessiner avec Libgdx


Introduction
Vous êtes arrivé à la 6eme étape de mon tutoriel félicitation ! J’ai décidé d’entamer le module graphique de Libgdx avant de présenter la deuxième partie de la manipulation des entrées.
Vous allez voir les fonctionnalités que possède Libgdx grâce à son module Graphique ainsi que la manière avec laquelle cette bibliothèque arrive à gérer les différences entre les deux plateformes Android et Desktop. Let’s GO !!

L’un des modules déjà vu précédemment est le module graphique. Le module graphique de Libgdx fournit des informations sur l’écran de l’appareil et la fenêtre de l’application qu’on pourra bien évidemment la manipuler ainsi que plein d’autres données graphiques grâce aux méthodes de la classe Gdx.

Le haut et le bas niveau
Ce qui est merveilleux avec ce module c’est la capacité d’accéder aux fonctionnalités de bas niveau à chaque fois que le haut niveau ne suffit pas.

Le module graphique  cache la complexité de la programmation graphique avec l'API OpenGL ES. Ce module fournit des méthodes pratiques pour obtenir des instances de fonctions OpenGL ES indépendamment de la plateforme. Il est également livré avec un ensemble de méthodes utiles pour obtenir des informations sur l'écran, telles que la résolution, la densité, l'orientation et aussi, la mesure de performance.

Le module graphique ne se limite pas aux fonctionnalités mentionnées ci-dessus, il est beaucoup plus grand que ça. Il contient une collection de classes qui rendent le développement des graphismes extrêmement facile. Il facilite les graphismes en 2D et 3D et ceci grâce à aux fonctionnalités de haut et de bas niveau qu’il possède et aussi grâce à l’implémentation des classes les plus utilisées en programmation des jeux.
Voici quelques fonctionnalités propres au module graphique de libgdx :

2D

  • Le rendu Sprite
  • Les polices Bitmap
  • Les systèmes de particules
  • La manipulation Bitmap
  • Bibliothèque de manipulation de Bitmap

3D

  • Orthographique et la caméra point de vue
  • Key-cadre et l'animation du squelette
  • Chargeurs de modèles 3D (OBJ, MD5)

Classe Commune et bas niveau

 ·         Textures
 ·         Texture atlas
 ·         Vertex arrays  
 ·         Vertex buffer objects (VBO)
 ·         Frame buffer objects (FBO)
 ·         Shaders
 ·         La gestion du contexte OpenGL.


Les ressources graphiques
L'interface Graphique fournit des méthodes pour créer une gamme de ressources graphiques soit dépendante de la plateforme soit indépendante de la plateforme. 

On va d'abord jeter un œil sur les ressources qui sont créés par le biais de l'interface graphique :
  • Pixmap encapsule des données (image) résidantes dans la mémoire. les Pixmaps peuvent être créés à partir d'un fichier ou en spécifiant  la largeur, la hauteur et le format pixel.  L’utilisation la plus fréquente est la préparation d’une image pour la télécharger sur le GPU (processeur graphique) et cela en l’enveloppant dans une texture par exemple.
Pixmap est compatible avec OpenGL ES 1.0, 1.1 et 2.0. 
  • Texture est essentiellement un Pixmap résidant dans la mémoire. Les textures peuvent être créées à partir de Pixmaps, en spécifiant la largeur, la hauteur et le format de pixel ou en spécifiant un fichier.
Texture est compatible avec OpenGL ES 1.0, 1.1 et 2.0. 
  • Font (police) peut être chargée à partir d'un fichier ou être spécifiée via un nom de police. Une police possède bien évidemment une taille ainsi qu'un style, tels que normal, gras, italique…
Font est compatible avec OpenGL ES 1.0, 1.1 et 2.0. 
Maintenant voici d'autres ressources graphiques qu’on peut instancier sans l'interface graphique:
  • Mesh (maillage) est responsable de la tenue d'une série de points, lignes ou triangles sous la forme de sommets. Résidants soit en VRAM sous forme de VBO(Vertex Buffer Objects)  ou dans la RAM sous forme de tableaux de vertex. Tout ce qui est dessiné dans Libgdx sera transformé en une mesh et transféré au processeur graphique. 
Mesh est compatible avec OpenGL ES 1.0, 1.1 et 2.0. 
  • SpriteBatch est la meilleure méthode pour générer d’une façon simple le rendu d’objet de 2D, tels que les sprites et les textes. Dans le cas de sprites on précise simplement la texture qui détient l'image du sprite ainsi qu’'un ensemble d'attributs tels que la position des sprites ou l'orientation.et dans le cas du texte on doit simplement spécifier la police à utiliser pour le rendu du texte.
Le SpriteBatch est une classe incroyablement rapide et efficace, et elle est  compatible avec OpenGL ES 1.0, 1.1 et 2.0. 
  • BitmapFont est un autre moyen d’écrire du texte. Au lieu de charger une police système ou une police TTF fourni à partir d'un fichier, BitmapFont travaille avec les polices de bitmap AngleCode. Vous pouvez créer ces polices avec l'éditeur de thème TWL ou un outil appelé Hiéron . 
  • ShaderProgram enveloppe shaders d’OpenGL ES 2.0. C'est une classe de convenance qui allège la gestion des shaders en OpenGL ES. 
ShaderProgram est uniquement disponibles lorsqu’OpenGL ES 2.0 est utilisé.
  • FrameBuffer enveloppe les objets FrameBuffer d’OpenGL ES 2.  Il s'agit d'une classe d'aide simple qui devrait couvrir la plupart des utilisations FBO (frame buffer object). Les ressources sont gérées avec une perte de contenu dans le cas de perte du contexte. 
FrameBuffer est uniquement disponibles lorsqu’OpenGL ES 2.0 est utilisé.


L’OpenGL avec Libgdx
Une utilisation particulière de ce module concerne un accès plus direct au contexte OpenGL pour un niveau inférieur de manipulation de données graphiques
Le module graphique possède des méthodes de lecture qui vous retourneront une implémentation de l'une des interfaces suivantes :
  • GL10 , offre tous les fonctions d’OpenGL ES 1.0
  • GL11 , offre tous les fonctions OpenGL ES 1.1. Il est effectivement dérivé de GL10, donc, vous pouvez également appeler des fonctions OpenGL ES 1.0 via cette interface.
  • GL20 , offre tous les fonctions OpenGL ES 2.0. 
  • GLCommon , regroupe toutes les fonctions que OpenGL ES 1.x et OpenGL ES 2.0 partagent entre eux.

* Voici un exemple ou on accède au contexte OpenGL ES2 dans une application pour définir le Viewport ; effacer les tampons de trame et la profondeur.
Gdx.gl20.glViewport(0,0,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
Gdx.gl20.glClearColor(0,0,0,1);
Gdx.gl20.glClear( GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT );
Notez que l'utilisation du GL20 exige d’instruire la demande d'utiliser OpenGL ES2 lors du démarrage. Donc on doit la spécifier au niveau des classe lanceur d’application.

Il faut aussi savoir que OpenGL ES 1.x et 2.0 sont incompatible et peuvent être indisponible sur certain dispositif, c’est pour cela que l’interface graphique nous fournit des méthodes pour vérifier qu’OpenGL ES implémenté est disponible sur la plateforme sous laquelle est exécutée notre application/jeu.

Graphique 2D
On va se contenter de quelques fonctionnalités graphiques en 2D pour ce tutoriel :
- Insérer une image :
Pour l’insertion d’une image on aura besoin de ces classes : Texture, TextureRegionSpritebatch, Sprite.

Texture :
La classe texture décode un fichier image et le charge en mémoire GPU. Le fichier image doit être placé dans le dossier "assets", tel que c’est décrit dans un précédant tutoriel

Remarque :
La dimension de l'image doit être une puissance de deux (16x16, 64x256, etc.)

* Voici un exemple de code source :
private Texture texture;
texture = new Texture(Gdx.files.internal("image.png"));
L’image qui doit se trouver dans le dossier assets du projet est maintenant chargée en mémoire.

Il y a plusieurs méthodes qui nous permettent de dessiner une texture 
·     draw(Texture texture, float x, float y)
·     draw(Texture texture, float x, float y, int ecrX, int ecrY, int ecrLargeur, int ecrHauteur)
·   draw(Texture texture, float x, float y, float largeur, float hauteur, int ecrX, int ecrY, int ecrLargeur, int ecrHauteur, boolean flipX, boolean flipY)
·    draw(Texture texture, float x, float y, float origineX, float origineY, float largeur, float hauteur, float scaleX, float scaleY, float rotation, int ecrX, int ecrY, int ecrLargeur, int ecrHauteur, boolean flipX, boolean flipY)
·     draw(Texture texture, float x, float y, float largeur, float hauteur, float u, float v, float u2, float v2)
·     draw(Texture texture, float[] spriteVertices, int offset, int longueur)


SpriteBatch :
Une fois l’image chargée, pour l’insérer il faut faire appel au SpriteBatch qui va la dessiner sur l’écran de l’appareil selon les coordonnées paramétrées lors de l’insertion.

* Voici un exemple de code source
private SpriteBatch batch;

public void create () {
batch = new SpriteBatch();
      }

public void render () {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // Pour effacer l’écran

batch.begin();
 // l’insertion de l’image s’effectue ici
batch.end();
      }
Il faut savoir que lorsque la texture est dessinée sur l’écran, les parties translucides de cette texture sont fusionnés avec les pixels qui déjà sur l'écran à cet endroit. Cette fonction s’appelle le blending elle est activée par défaut. Mais lorsqu’on désactive le blending toute la place réservée pour la texture est remplacé par la texture.

* Voici les deux lignes de code qui désactive puis active le blending
public void render() {
                         
                        batch.begin();
                        batch.disableBlending();
                        // insertion s'effectue ici
                        batch.enableBlending();
                        batch.end();
            }

TextureRegion
On pourrait s’arrêter sur les deux premières classes si on se contente de charger une image et l’insérer, mais pour plus de fonctionnalité on fait appel à TextureRegion. Cette classe définie un rectangle à l’intérieure d’une texture ceci est utile pour dessiner une partie de la texture sur l’écran de l’appareil.

* Voici un exemple de code source :
private SpriteBatch batch;
private TextureRegion region;
private Texture texture;
           
public void create () {
            texture = new Texture(Gdx.files.internal("image.png"));
            region = new TextureRegion(texture, 50, 30, 60, 40);
}

public void render () {
            Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
           
            batch.begin();
            batch.draw(region, 10, 10);
            batch.end();
 }
Ici on a dessiné une partie de la l’image comme suite :
A gauche c’est le contenu de ma texture qui enveloppe « image » qui n’est qu’un fond en vert de la taille 128x256 (la puissance de 2 est obligatoire), et à droite on spécifie dans la texture la région qui va être dessiné selon le code source ci-dessus

 * Il y a une autre façon d’utiliser TextureRegion, dans le cas où on veut manipuler des régions de même hauteur et de même largeur voici comment il faut faire :
private Texture texture;
private SpriteBatch batch;
private TextureRegion region[][];
           
@Override
public void create() {
           
            batch =new SpriteBatch();
            texture = new Texture(Gdx.files.internal("image.png"));
            region = TextureRegion.split(texture, 32, 32);
           
            }
@Override
public void render() {
            Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
           
            batch.begin();
            batch.draw(region[0][0], 0, 0);
            batch.end();
            }
Ici on a dessiné la région de l’image comme suite :
A gauche vous avez la texture enveloppant « image » qui représente un ensemble de petites images de taille 32x32 chacune.
A droite on spécifie la région qui va être dessiné selon le code source ci-dessus.

Il y a plusieurs méthodes qui permettent de dessiner une région d’une texture.
  • draw(TextureRegion region, float x, float y) // celle qu’on a utilisé dans l’exemple
  • draw(TextureRegion region, float x, float y, float width, float height)
  • draw(TextureRegion region, float x, float y, float originX, float originY, float width, float    height, float scaleX, float scaleY, float rotation)

Sprite
La classe Sprite décrit à la fois une région de texture, sa géométrie ainsi que la couleur tout ça dans un seul et unique objet.

* Voici un exemple de code source :
 
private SpriteBatch batch;
private Texture texture;
private Sprite sprite;

           
public void create () {
            texture = new Texture(Gdx.files.internal("image.png"));
            sprite = new Sprite(texture, 50, 30, 60, 40);
            sprite.setPosition(10, 10);
            sprite.setRotation(45);

}

public void render () {
            Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
           
            batch.begin();
            sprite.draw(sprite, 10, 10);
            batch.end();
 }
Le résultat est semblable à celui de la TextureRegion sauf qu’ici il y a en plus la rotation.
A droite vous avez la texture, la même que l’exemple de TextureRegion
A droite on spécifie le sprite qui va être dessiné sur l’écran de l’appareil en position de 10px en hauteur en largeur et avec une rotation de 45 degrés

- Dessiner avec libgdx
Pixmap :
On a dit que Pixmap prépare une image pour être télécharger dans le GPU puis envelopper dans une texture ou seulement ranger pour une utilisation future.
Pixmaps peuvent être créés à partir d'un tableau d'octets contenant les données d'image codées en tant que JPEG , PNG ou BMP , un FileHandle , ou en spécifiant ses dimensions et son format. 
On va utiliser Pixmap pour dessiner des images.

* Voici un code source qui  crée un 64x64 32-bit RGBA Pixmap, qui dessine un cercle coloré en vert à l'intérieur, il l’enveloppe dans une texture, puis le dispose de la mémoire.

private Texture enveloppe;
private Pixmap pixmap;
private SpriteBatch batch;
           
@Override
public void create() {
           
            batch = new SpriteBatch();
            pixmap = new Pixmap( 64, 64, Format.RGBA8888 );
            pixmap.setColor( 0, 1, 0, 1 );
            pixmap.fillCircle( 32, 32, 32 );
            enveloppe = new Texture( pixmap );
            pixmap.dispose();
                       
            }
@Override
public void render() {
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
            batch.begin();
            batch.draw(enveloppe, 0, 0);
            batch.end();
            }

On pourra bien évidemment dessiner des lignes, des rectangles et même dessiner pixel par pixel

BitmapFont
On déjà vu comment afficher du texte dans les précédents tutoriels, c’est une opération très facile voici un exemple de code source :
private Texture texture;
private SpriteBatch batch;
private BitmapFont fontmessage ;
private String message;
           
@Override
public void create() {
            fontmessage = new BitmapFont();
            batch       = new SpriteBatch();
            message     = "Bonjour tous le monde";
            }
@Override
public void render() {
            Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
           
            batch.begin();
            fontmessage.draw(batch, message, 10, 30);  
            batch.end();
            }

Maintenant, et comme d’habitude on va récapituler avec un code source d’une petite application qui permet de dessiner sur un écran avec un crayon rouge et d’effacer en utilisant une gomme. 
Vous aurez besoin de ces deux fichiers qui sont deux images trouvées dans google et modifiées pour qu'ils aillent un fond transparent.


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 contiendra :
package my.works.TutorielBlog;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Pixmap.Format;

import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

import com.badlogic.gdx.utils.Array;

public class Graphique implements ApplicationListener {

private Texture  rectangleTexture;
private SpriteBatch batch;
private Pixmap rectanglePixmap;
private Sprite traitSprite;
private Array<Sprite> tabRectangelSprite ;

private Texture curseurTexture;
private float posCurseurX ;
private float posCurseurY ;
           
private int compteur = -1;
private boolean toucher = false ;

public static int largeur ;
public static int hauteur ;
public static int tailleTrait = 4 ;
           
@Override
public void create() {
                       
            batch = new SpriteBatch();
            tabRectangelSprite = new Array<Sprite>();
                       
            // Préparer le petit rectangle constituant le trait
            rectanglePixmap =new Pixmap(32,32,Format.RGB888);
            rectanglePixmap.setColor(Color.RED);
            rectanglePixmap.drawRectangle(0, 0, tailleTrait, tailleTrait);
            rectanglePixmap.fillRectangle(0, 0, tailleTrait, tailleTrait);
            // Mettre le petit rectangle dans une texture
            rectangleTexture = new Texture(rectanglePixmap,Format.RGB888,false);
                       
            // Initialement c'est le crayon qui est chargé tel que curseur
            curseurTexture = new Texture(Gdx.files.internal("crayon.png"));

           // on recupere la taille de l'écran qui
            // varie selon l'appareil
            largeur = Gdx.graphics.getWidth();
            hauteur = Gdx.graphics.getHeight();
            }

            @Override
public void dispose() {
            }

            @Override
            public void pause() {
            }
           
 // Dessiner le curseur qui est soit gomme soit crayon
public void dessinerCureur(){
            batch.begin();
            batch.draw(curseurTexture, posCurseurX -32, hauteur -posCurseurY - 32);
            batch.end();
            }
 // Dessiner le trait qui est ensemble de rectangle
public void dessinerTrait(boolean toucher){
                       
             if(toucher)
               {
                    batch.begin();
                    tabRectangelSprite.get(compteur).draw(batch);
                    for(int i = 0 ; i< tabRectangelSprite.size ; i++)
                          tabRectangelSprite.get(i).draw(batch);
                    batch.end();
                 }     
            }
           
@Override
public void render() {
    
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT );
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.input.setInputProcessor(new InputProcessor() {
                       
@Override
public boolean touchUp(int arg0, int arg1, int arg2, int arg3) {
            return false;
}
                       
@Override
public boolean touchMoved(int x, int y) {
// Récupérer la position du curseur
posCurseurX=x;
posCurseurY=y;
            return false;
}
                       
@Override
public boolean touchDragged(int x, int y, int pointeur) {
// Récupérer la position du curseur
posCurseurX=x;
posCurseurY=y;
// Commencer à dessiner sur l'écran
toucher = true ;
traitSprite = new Sprite(rectangleTexture,0,0,tailleTrait,tailleTrait);
traitSprite.setPosition(x - tailleTrait/2,(hauteur) - y - tailleTrait/2);
tabRectangelSprite.add(traitSprite) ;
// L’indice compteur du nombre de rectangle formant un trait
compteur++;
            return false;
}
           
@Override
public boolean touchDown(int arg0, int arg1, int arg2, int arg3) {
            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) {
            // Changement de curseur en gomme
            if(Gdx.input.isKeyPressed(Keys.G))
            {
                        // Recharger l'image du  curseur
                        curseurTexture = new Texture(Gdx.files.internal("gomme.png"));
                        // Recharger la couleur
                        rectanglePixmap.setColor(Color.WHITE);// La même couleur que l'écran
                        rectanglePixmap.fillRectangle(0, 0, tailleTrait, tailleTrait);
                        // Recharger la texture
                        rectangleTexture = new Texture(rectanglePixmap,Format.RGB888,false);
            }
            // Changement de curseur en crayon
            if(Gdx.input.isKeyPressed(Keys.C))
            {
                        // Recharger l'image du curseur
                        curseurTexture = new Texture(Gdx.files.internal("crayon.png"));
                        // Recharger la couleur
                        rectanglePixmap.setColor(Color.RED);// la couleur rouge
                        rectanglePixmap.fillRectangle(0, 0, tailleTrait, tailleTrait);
                        // Recharger la texture
                        rectangleTexture = new Texture(rectanglePixmap,Format.RGB888,false);
            }
            return false;
}
            });
       dessinerTrait(toucher);
       dessinerCureur();
     }
            @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.TutorielBlog;

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

public class Lanceur {
            public static void main(String[] args) {
                        new JoglApplication (new Graphique(),"Graphique",32*8, 32*14, false);
            }
}


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

import my.works.TutorielBlog.Graphique;
import com.badlogic.gdx.backends.android.AndroidApplication;
import android.os.Bundle;

public class main extends AndroidApplication {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        initialize(new Graphique(), 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. Nous avons déjà parlé de ça en détail dans un tutoriel précédant.

* Voici le résultat sur desktop :
























Si on appuie sur la touche G du clavier on aura une gomme à la place du stylo et on pourra commencer à effacer.





















* Maintenant le résultat sous Android (sous l’émulateur) :























Si on appuie sur la touche G du clavier on aura une gomme à la place du stylo et on pourra effacer ce qu’on a dessiné.

















Vous pouvez télécharger le projet Android ici

projet Android GraphiqueLibgdxAndroid

Conclusion
Le module graphique de Libgdx est vaste, et encore on a vu que les fonctionnalités graphiques en 2D, mais ne vous inquiétez pas si vous avez compris ce que nous avons dans ce tutoriel sachez que vous avez fait un grand pas. Si vous avez des remarques ou des questions n’hésitez pas à les poster en commentaire. Merci pour votre lecture.


11 commentaires:

  1. Bonjour, je voulais savoir si avec jogl il y a un moyen simple d'ajouter des boutons et voire meme faire un petit formulaire?
    D'avance merci

    RépondreSupprimer
  2. Bonjour far38, oui évidemment ceci est possible et c'est justement le sujet de mon prochain tutoriel,
    Tout le plaisir est pour moi!

    RépondreSupprimer
  3. "Remarque :
    La dimension de l'image doit être une puissance de deux (16x16, 64x256, etc.)"

    Avec OpenGL 2.0, il est possible d'utiliser des textures ayant des dimensions autre que des puissances de 2

    Merci pour l'article !

    RépondreSupprimer
    Réponses
    1. Pour éviter que la dimension de l'image soit une puissance de 2 tu peux utiliser dans la méthode create() de la classe game :

      Texture.setEnforcePotImages(false);

      Supprimer
  4. jai un probleme qui me dis au logcat package com.me.mydxgame has no certificates at entry assets/data/arriereplan.png et la meme chose pour tout les images :/

    RépondreSupprimer
  5. Ce commentaire a été supprimé par l'auteur.

    RépondreSupprimer
  6. Help !
    L'app crash sur android 4.4.2...
    Il "manque des acceurs" au niveau de :
    @Override
    public boolean touchUp(int arg0, int arg1, int arg2, int arg3) {
    return false;
    }

    @Override
    public boolean touchMoved(int x, int y) {
    // Récupérer la position du curseur
    posCurseurX=x;
    posCurseurY=y;
    return false;
    }

    Help...

    RépondreSupprimer
    Réponses
    1. Bonjour , je viens d'essayer l'app sur mon Galaxy S4 qui en version 4.3 et ça marche
      Je pense que ton problème est avec la version de libgdx sache que j'ai utilisé une version ancienne de la bib la 0.9.6 quelque méthode ont changer au niveau de InputProcessor

      Supprimer
  7. Ah, nickelll !
    Merci beaucoup !
    Tu pourrais m'envoyer un lien de ton projet ?
    Que je vois si j'ai pas merdé un truc avec la classpath ou autre ? ._.
    Un dropbox ou mega ^^
    (Ou skype ou mail comme tu veux ^^ )
    Merci en tout cas ! :)

    RépondreSupprimer
    Réponses
    1. acutalise la page tu trouvera le projet en bas de la page
      Bonne continuation !

      Supprimer
  8. Ce commentaire a été supprimé par l'auteur.

    RépondreSupprimer