Introduction
Ce n’est pas intéressant de savoir comment
déplacer Mario dans une carte et ne pas savoir comment faire un bouton, bien
que jouer avec Mario est plus rigolo que de taper sur des boutons !
Il y a plusieurs façons de faire un menu avec Libgdx,
on va présenter deux façons de faire, la première a travers cet article et la deuxième
à travers l’article qui le suivra.
1ère
méthode :
Cette 1ère méthode est basée sur le
fait de dessiner le menu qu’on veut réaliser puis de l’implémenter de A à Z, en
utilisant des images et des icônes de notre choix par exemple : Je dessine
des formes sous un éditeur tel que Paint ou Gimp puis je l’ai
charge sous forme de texture afin de les manipuler en tant que boutons et éléments
de menu
Cette façon de faire nous permet de réaliser un
menu d’un jeu ou d’une application qui correspond
exactement à ce qu’on veut faire sans être limiter par des formes ou par un
design bien précis c’est-à-dire, on peut dessiner notre menu puis le réaliser
telle qu’il est.
Je conseille cette façon de faire pour la
réalisation de petits menu qui contiennent quelques boutons et avec minimum
d’informations à afficher car créer un menu de cette façon nécessite de tout
prévoir et contrôler ce qui nous demande de cracher beaucoup de code source.
Suivez ses étapes et votre menu sera créer (comme
par magie !)
1er
Etape : Dessiner
le menu
Attention : Avant de dessiner il faut choisir la
taille repère c’est-à-dire la taille de l’écran sur lequel vous allez
dessiner votre menu. On va choisir pour cet exemple la taille 480x320 comme
taille repère.
Comme vous le savez surement, un menu d’un
Jeu/Application doit fonctionner sur plusieurs appareils
Voici des tailles de quelques écrans d’appareils
mobiles :
Smartphone
|
Taille en Pixels
|
Taille en Pouce
|
HTC Hero
|
320×480
|
3,2
|
Nokia N900
|
800×480
|
3,5
|
Galaxy Notes
|
1280×800
|
5,3
|
Galaxy Tab 10,1
|
1280×800
|
10,1
|
Un designer est le bienvenu pour effectuer
cette partie
Voici à quoi ressemble mon menu pour cet
exemple
Bon!, je suis loin d’être un designer.
2eme
Etape : Préparer
les éléments de menu
Les éléments des menus sont des textures
chacune à part. Une règle important pour charger ces textures c’est qu’ils
aient une taille sous la forme 2xx2y ,
donc il faut concevoir la taille de notre bouton comme ça nous chante puis
compléter avec un vide la taille de ce dernier pour qu’elle soit sous la forme
de 2xx2y
Par exemple la taille de mon bouton est 120x45,
il faut alors compléter l’image contenant ce bouton avec du vide en utilisant
un éditeur d’image pour qu’elle devient 128x64
si la taille de mon image est de 258x130 alors il faut la compléter avec
du vide pour qu’elle devienne 512x256 et ainsi de suite.
Si vous n’avez aucune notion sur l’utilisation
des éditeurs d’images, je vous conseille de voir ce petit tutoriel
qui contient seulement les notions nécessaires concernant l’éditeur GIMP et
Paint pour développer avec à l’aise avec Libgdx.
Voici les textures qui représentent les éléments
de mon menu
Boutons
J’ai choisi la forme nuage pour montrer qu’on peut
choisir n’importe qu’elle forme, on n’est pas limité par la forme rectangle
ici pour télécharger le
bouton
Bouton
cliqué
Il faut aussi préparer le bouton sur sa forme
cliqué c’est-à-dire sa couleur lorsque on lui clique dessus et on maintient le
clic
ici pour télécharger le
bouton cliqué
Arrière-Plan
Un arrière-plan qui correspond au contexte du
menu
ici pour télécharger l’arrière-plan
Bouton
retour
Un bouton qu’on clique dessus pour retourner au
menu principal
ici pour télécharger
3eme
étape : Cracher
du code source
On va expliquer les parties les plus
importants, si vous avez suivis les précédents tutoriels vous n’auriez aucun
mal à comprendre ce code sinon, je vous propose de voir ce tutorielpour le graphique ainsi que ce tutoriel pour la gestion des
entrées.
+ Gérer la
position des éléments du menu selon la taille d’écran :
Quand on veut placer un élément (exemple :
image, texte) dans notre écran il faut toujours
le référencer par rapport à la taille de celui-ci par exemple si on veut placer
notre bouton au milieu de l’écran sur un écran de résolution 480x320 comme le
montre cette image :
Il faut affecter la position de l’image comme
suite :
Position.x (sur l’axe X) = largeur écran /2
Position.x(sur l’axe y) = hauteur écran /2
Au lieu de faire :
Position.x = 240
Position.y = 160
Car ceci va poser un problème si la taille
de l’écran sur laquelle mon application va s’exécuter est différente de 480x320
comme le montre ce schéma :
Si je veux placer un élément dans un écran et
que le rapport de la position de cet élément et l’écran reste le même quel que
soit l’écran comme explique l’image ci-dessus :
Il suffit juste de faire :
Position.x = (60 x largeur_ecran_actuel )/largeur_ecran_repere
Position.y= (60 x hauteur_écran_actuel)/largeur_ecran_repere
Dans notre exemple
Position.x = (60 x largeur_ecran_actuel )/480
Position.y= (60 x hauteur_écran_actuel)/320
Ecran 480x320
|
Ecran 1024x768
|
Position.x = 60 x 480 /480 = 60
Position.y = 60 x320 /320 = 60
|
Position.x = 60 x 1024 /480 = 128
Position.y = 60 x 768 / 320 = 144
|
Puisque tout cela va se répéter pour toutes
positions d’éléments le mieux c’est de le mettre dans une fonction
* Voici la première fonction qui maintient la
proportion sur l’axe des X
private float xUnite(float x)
{
return x*largeur_ecran/480f;
}
* Voici la première fonction qui maintient la
proportion sur l’axe des Y
private float yUnite(float y)
{
return y*hauteur_ecran/320;
}
Pour placer notre bouton on fait :
xposBouton1 = xUnite(176);
yposBouton1 = yUnite(223);
+ Gérer la taille des éléments du menu selon la
taille de l’écran
Une fois la position de notre bouton est gérée
en s’intéresse à sa taille ce schéma donne plus d’explication :
Les deux fonctions définies au-dessus peuvent
être utilisées pour maintenir la proportion entre la taille de l’écran actuelle
et la taille de l’écran repère.
Taille.x = (128 x largeur_ecran_actuel )/480
Taille.y =(64 x hauteur_écran_actuel)/320
Ecran 480x320
|
Ecran 1024x768
|
taille.x = 128 x 480 /480 = 128
taille.y = 64 x320 /320 = 64
|
taille.x = 60 x 1024 /480 = 273
taille.y = 60 x 768 / 320 = 153
|
* Pour définir la taille de l’écran on
fait :
boutonSprite.setSize(xUnite(128),
yUnite(64));
+ Gérer le clic sur bouton et le bouton cliqué
L’astuce ici c’est de changer l’image lorsqu’on
clique sur le bouton par une image identique au bouton mais dont la couleur est
différente.
* pour savoir si un bouton est cliqué
public boolean touchDown(int x, int y, int pointer, int bouton) {
// si un doigt est sur
le bouton
if(x>xUnite(180)
&& x < xUnite(300) && y>yUnite(40) &&
y<yUnite(88) )
{
cliqueBouton1=true;
}
}
* Pour dessiner le bouton ou le bouton une fois
cliqué :
if(!cliqueBouton1)
{
boutonSprite.setPosition(xposBouton1, yposBouton1);
boutonSprite.draw(batch);
}else
{
boutonCliqueSprite.setPosition(xposBouton1, yposBouton1);
boutonCliqueSprite.draw(batch);
}
Vous remarquez qu’on utilise la classe Sprite
au lieu de Texture parce qu’elle possède plus de fonctionnalités :
préciser la taille, la position…
Si on relâche (déclique) le bouton alors que
notre doigt (la souris en Desktop) est positionner sur le bouton ça veut dire
qu’on a appuyé sur le bouton
Mais si on
relâche (déclique) le bouton alors que notre doigt (la souris en
Desktop) est positionner hors du bouton ça veut dire qu’on annuler notre clique
* Voici comment le faire
public boolean
touchUp(int x, int y, int
pointer, int bouton) {
// si lève le doigt du bouton
if(x>xUnite(180) && x < xUnite(300) && y<yUnite(88)
&& y> yUnite(40))
{
page=1; // on active la
page 1
}
cliqueBouton1 = false;
}
* Voici le code source complet de l’exemple
package my.works.Article;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class MenuMethode1 implements ApplicationListener{
private Sprite boutonSprite;
private Sprite boutonCliqueSprite;
private Sprite arrierePlanSprite;
private Sprite boutonRetourSprite;
private BitmapFont font;
private SpriteBatch batch;
private float largeur_ecran;
private float hauteur_ecran;
private float xposBouton1;
private float xposBouton2;
private float xposBouton3;
private float xposBoutonRetour;
private float yposBouton1;
private float yposBouton2;
private float yposBouton3;
private float yposBoutonRetour;
private boolean cliqueBouton1;
private boolean cliqueBouton2;
private boolean cliqueBouton3;
private float xDecalage;
private float yDecalage;
private int page;
private String texteBouton1;
private String texteBouton2;
private String texteBouton3;
// Fonction qui maintien
le rapport entre les positions Y
// vis-à-vis de la
taille de l'écran
private float xUnite(float x)
{
return x*largeur_ecran/480f;
}
// Fonction qui maintien
le rapport entre les positions Y
// vis-à-vis de la
taille de l'écran
private float yUnite(float y)
{
return y*hauteur_ecran/320;
}
@Override
public void create() {
// Obtenir la
taille de l'écran actuelle
largeur_ecran = Gdx.graphics.getWidth();
hauteur_ecran = Gdx.graphics.getHeight();
batch = new SpriteBatch();
// Charger Texture
dans Sprite
boutonSprite =new Sprite(new Texture(Gdx.files.internal("bouton.png"))) ;
boutonCliqueSprite = new Sprite(new Texture(Gdx.files.internal("boutonclique.png"))) ;
arrierePlanSprite = new Sprite(new Texture(Gdx.files.internal("arriereplan.png")));
boutonRetourSprite = new Sprite(new Texture(Gdx.files.internal("retour.png")));
boutonSprite.setSize(xUnite(128),
yUnite(64));
boutonCliqueSprite.setSize(xUnite(128),
yUnite(64));
arrierePlanSprite.setSize(xUnite(512),
yUnite(512));
boutonRetourSprite.setSize(xUnite(64),
yUnite(64));
// La police pour
le texte
font = new BitmapFont();
font.setColor(Color.DARK_GRAY);
font.setScale(xUnite(1),
yUnite(1)); // définir la taille du texte selon l'écran
xDecalage = xUnite(40); // pour gérer le
décalage de positionnement entre font et sprite
yDecalage = yUnite(40);
// Texte des boutons
1, bouton 2, bouton 3
texteBouton1 = "Start";
texteBouton2 = "Options";
texteBouton3 = "Bonnus";
xposBouton1 = xUnite(176); // Position du
bouton 'StartGame'
yposBouton1 = yUnite(223);
xposBouton2 = xUnite(176); // Position du
bouton 'Options'
yposBouton2 = yUnite(150);
xposBouton3 = xUnite(176); // Position du
bouton 'Bonus'
yposBouton3 = yUnite(74);
xposBoutonRetour = xUnite(0); // Position du bouton 'Retour'
yposBoutonRetour = yUnite(260);
boutonRetourSprite.setPosition(xposBoutonRetour, yposBoutonRetour);
}
public void manipulerMenu()
{
Gdx.input.setInputProcessor(new InputProcessor() {
@Override
public boolean touchUp(int x, int y, int pointer, int bouton) {
if(x>xUnite(180)
&& x < xUnite(300) && y<yUnite(88) && y>
yUnite(40))
{
// le bouton 1
(startGame) a été cliqué
page=1;
}
if(x>xUnite(180)
&& x < xUnite(300) && y>yUnite(115) &&
y<yUnite(160))
{
// le bouton 2
(Options) a été cliqué
page=2;
}
if(x>xUnite(180)
&& x < xUnite(300) && y>yUnite(190) &&
y<yUnite(235))
{
// le bouton 3
(Bonus) a été cliqué
page=3;
}
if(x>xUnite(0)
&& x<xUnite(64) && y>yUnite(0) &&
y<yUnite(64))
{
// le bouton retour
a été cliqué
page=0;
}
cliqueBouton1 = false;
cliqueBouton2 = false;
cliqueBouton3 = false;
return false;
}
@Override
public boolean touchDown(int x, int y, int pointer, int bouton) {
if(x>xUnite(180)
&& x < xUnite(300) && y>yUnite(40) &&
y<yUnite(88) )
{
cliqueBouton1=true;
}
if(x>xUnite(180)
&& x < xUnite(300) && y>yUnite(115) &&
y<yUnite(160))
{
cliqueBouton2=true;
}
if(x>xUnite(180)
&& x < xUnite(300) && y>yUnite(190) &&
y<yUnite(235))
{
cliqueBouton3=true;
}
return false;
}
@Override
public boolean touchDragged(int arg0, int arg1, int arg2) {
return false;
}
@Override
public boolean scrolled(int arg0) {
return false;
}
@Override
public boolean mouseMoved(int arg0, int arg1) {
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;
}
});
}
public void dessinerMenu() // dessiner le menu
{
batch.begin(); // obligatoire pour commencer un dessin sur
le SpriteBatch
// arrierePlan
arrierePlanSprite.draw(batch);
// bouton 1
if(!cliqueBouton1)
{
boutonSprite.setPosition(xposBouton1, yposBouton1);// fixer la
position
boutonSprite.draw(batch); // puis le dessiner
}else
{
boutonCliqueSprite.setPosition(xposBouton1, yposBouton1);
boutonCliqueSprite.draw(batch);
}
// bouton 2
if(!cliqueBouton2)
{
boutonSprite.setPosition(xposBouton2, yposBouton2);// fixer la
position
boutonSprite.draw(batch); // puis le dessiner
}else
{
boutonCliqueSprite.setPosition(xposBouton2, yposBouton2);
boutonCliqueSprite.draw(batch);
}
// bouton 3
if(!cliqueBouton3)
{
boutonSprite.setPosition(xposBouton3, yposBouton3); // fixer la
position
boutonSprite.draw(batch); // puis le dessiner
}else
{
boutonCliqueSprite.setPosition(xposBouton3, yposBouton3);
boutonCliqueSprite.draw(batch);
}
// texte du bouton1
font.draw(batch, ""+texteBouton1, xposBouton1+xDecalage, yposBouton1+yDecalage);
// texte du bouton2
font.draw(batch, ""+texteBouton2, xposBouton2+xDecalage, yposBouton2+yDecalage);
// texte du bouton3
font.draw(batch, ""+texteBouton3, xposBouton3+xDecalage, yposBouton3+yDecalage);
batch.end(); // obligatoire pour finir le dessin sur un
SpriteBatch
}
public void dessinerPage(int page)
{
batch.begin();
if(page == 1) // si on est à la page Game
font.draw(batch, "The
Game",
xUnite(200), yUnite(320)); // dessiner le
titre de la page 1
if(page == 2) // si on est à la page Options
font.draw(batch, "Options", xUnite(200),
yUnite(320)); // dessiner le titre de la page 2
if(page == 3) // si on est à la page Bonus
font.draw(batch, "Bonus", xUnite(220),
yUnite(320)); // dessiner le titre de la page 3
boutonRetourSprite.draw(batch);
batch.end();
}
@Override
public void dispose() {
font.dispose();
batch.dispose();
}
@Override
public void pause() {
}
@Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(1, 1,
1, 1);
manipulerMenu(); // gestion des input
switch(page) // dans quelle page je me situe ?
{
case 0: // Contenu de la page menu
dessinerMenu();
break;
case 1: // Contenu de la page Game
dessinerPage(1);
break;
case 2: // Contenu de la page Options
dessinerPage(2);
break;
case 3: // Contenu de la page Bonus
dessinerPage(3);
break;
}
}
@Override
public void resize(int arg0, int arg1) {
}
@Override
public void resume() {
}
}
Conclusion
On a vu dans ce tutoriel une façon de
faire un petit menu pour une application ou un jeu et comment se déplacer à
travers les pages de ceci. Dans un prochain article on va voir une autre façon
de faire des boutons et des menus. Si vous avez des remarques, des propositions
ou des questions n’hésitez pas à les poster en commentaire. Merci pour votre
lecture.