
Big Tuto ANDROID
Chapitre 5 : L’écran de jeu, partie 2 : Le Code
Tutoriel présenté par : Stéphane Barthélémy (Stephantasy)
Date d'écriture : 10 septembre 2017
Date de révision : -
1. Introduction
Ok, nous allons mettre l’interface de côté pour le moment et nous attaquer au code. ![]()
Nous avons précédemment créé la base de notre jeu en construisant une interface graphique rudimentaire.
À présent, nous allons ajouter le code du jeu Tic-Tac-Toe et nous verrons comment créer l’interaction avec notre interface. ![]()
L’application est téléchargeable sur Google Play ! Vous aurez ainsi un aperçu du projet fini. ![]()
2. Renommage
Avant de commencer, nous allons renommer la classe de notre activité. En effet, à la fin du projet, il y aura une quinzaine de classe. Pour retrouver rapidement les classes d’activités, nous allons simplement ajouter le préfixe « Activity ».
Pour renommer une classe, dans l’arborescence du projet, faites un clic droit sur la classe concernée et choisissez « Refactor > Rename… ». Entrez le nouveau nom « ActivityGameScreen » et validez en cliquant sur « Refactor ».

3. La grille de jeu (Java)
Nous allons à présent nous attaquer à la deuxième partie d’une activité : son code Java. Le code permet de donner vie à notre application. On pourrait diviser le code Java en deux parties : le Java classique, c’est-à-dire le code du jeu Tic-Tac-Toe, et le Java propre à Android.
En ce qui concerne Java, je ne m’étendrai pas. Pour ceux qui ne connaissent pas le langage ou ceux qui ne sont pas familiers avec la POO (Programmation Orientée Objet), ça peut piquer un peu…
Néanmoins, le code est suffisamment commenté pour permettre de s’y retrouver. ![]()
Aussi, le code du jeu Tic-Tac-Toe ne sera que survolé, ce n’est pas le but de ce tutoriel ! Bien sûr, pour ce qui est du code relatif à l’application Android, j’expliquerai son fonctionnement plus en détail. ![]()
A. Le code du jeu
Le code du jeu Tic Tac Toe, ainsi que le projet Anroid Studio, vous sont fournis ici :
i. Composition
Nous allons commencer par intégrer le code du jeu. ![]()
Voici les éléments qui le composent :
Pour la partie exclusivement réservée au jeu, nous avons une interface nommée « TicTacToe », qui contient les méthodes abstraites du jeu. La classe « Jeu » implémente cette interface. Nous avons également un énumérateur, nommé « Player », qui liste les joueurs.
Ensuite nous avons une classe qui va gérer notre jeu. Elle se nomme, sans grande surprise, « GameManager » !
Cette classe s’interfère entre l’activité et le jeu. Elle ne parait pas indispensable de premier abord, car on aurait pu directement contrôler le jeu depuis l’activité !
Cependant, l’utilité de cette architecture sera révélée dans le chapitre traitant de la persistance des données. ![]()
Enfin, nous avons un énumérateur « AiResult » qui liste les différents états de l’intelligence artificielle du jeu. ![]()
ii. Intégration
Pour insérer des fichiers existants dans un projet, il suffit de les glisser depuis le dossier où ils se trouvent (le dossier Ch4_Code-du-jeu dans l'archive téléchargeable ci-dessus
) vers « java > com.android.meruvia.mylittletictactoe » en pressant la touche « Ctrl ». Cela permet de « copier » les fichiers, plutôt que de les déplacer. ![]()

De plus, en les copiant, Android Studio va automatiquement ajouter le nom du Package dans les fichiers Java ! ![]()

B. Le code de l’activité
Que les choses sérieuses commencent ! ![]()
À toute activité est associée une classe Java. C’est cette dernière qui va démarrer l’activité et qui contiendra le code permettant sa gestion.
Ouvrez le fichier Java de notre activité « GameScreen » qui se trouve dans « app > java > com.android.meruvia.mylittletictactoe ».
Cette classe doit obligatoirement dériver de « AppCompatActivity ». Lors du démarrage d’une activité, la méthode « onCreate » est appelée automatiquement et c’est elle qui lance l’interface associée avec la commande suivante :
setContentView(R.layout.activity_game_screen);
C’est ce que nous avons vu précédemment lors de l’exécution de notre activité avec l’émulateur. ![]()
i. Contrôle d’un élément graphique
À présent, nous allons appeler le code du jeu depuis notre activité et créer une interaction avec l’interface graphique. Pour cela, il va nous falloir prendre le contrôle des différents éléments la composant. En général, c’est principalement ce qu’on fait dans la fonction « onCreate ».
Nous allons avoir besoin :
- De chaque case de la grille,
- Du texte affichant le résultat de la partie,
- Du bouton de remise à zéro de la partie.
Et puisque nous allons nous en servir dans plusieurs fonctions, nous allons créer des variables globales du type de l’objet cible, soit :
private List<Button> listButton; (Une liste de Button) private TextView tvGameResult; (Un TextView) private Button btNewGame; (Un Button)
Ajoutez ces 3 lignes au-dessus de la fonction « onCreate » et constatez qu’Android Studio affiche « Button » et « TextView » en rouge. La raison est qu’il faut importer les classes associées. Pour cela, cliquez n’importe où dans le code, sauf sur les noms en rouge ! Un Pop-up devrait apparaitre pour vous permettre d’insérer ce qu’il faut :

Puis faites « Alt + Entrée », et Android Studio ajoute les éléments manquants :

À présent, nous pouvons associer nos variables aux objets graphiques. Pour cela, une seule fonction : « findViewById() ». On l’utilise en « castant » le type de l’objet cible et en passant son « Id » en paramètre. Ce qui donne pour le TextView :
tvGameResult = (TextView)findViewById(R.id.tv_result);
Lors de la compilation, Android Studio crée une seule classe contenant tout le code de l’application : c’est la classe « R ». Tous les éléments sont associés à un identifiant qui se retrouve dans cette classe. Ainsi, pour trouver l’identifiant de notre TextView, on fait appel à « R », suivi de « id » (qui contient tous les identifiants), suivi de l’Id recherché (celui déclaré dans « activity_game_screen.xml »).
On fait la même chose pour le bouton, cette fois en castant « Button » :
btNewGame = (Button)findViewById(R.id.bt_new_game);
Pour des raisons pratiques, les boutons de la grille sont placés dans une « List » et on procède de la même manière pour chacun des boutons :
listButton = new ArrayList<>(); listButton.add((Button)findViewById(R.id.bt_case_0)); listButton.add((Button)findViewById(R.id.bt_case_1)); listButton.add((Button)findViewById(R.id.bt_case_2)); listButton.add((Button)findViewById(R.id.bt_case_3)); listButton.add((Button)findViewById(R.id.bt_case_4)); listButton.add((Button)findViewById(R.id.bt_case_5)); listButton.add((Button)findViewById(R.id.bt_case_6)); listButton.add((Button)findViewById(R.id.bt_case_7)); listButton.add((Button)findViewById(R.id.bt_case_8));
Android Studio est assez performant avec la « complétion automatique » (ou auto-completion en anglais). Par exemple, tapez « f » : « findViewById() » est le premier élément de la liste. Appuyez sur « Entrée » et le nom de la fonction est écrit directement !
Avec l’habitude, on crée rapidement du code avec cette méthode. ![]()
Maintenant que nous avons nos variables, tapez-en une au hasard, suivit d’un point et faites « Ctrl + Espace ». Voyez la longue liste de contrôles qui nous est offerte !
Évidemment, la liste diffère en fonction de l’objet.

ii. Remplissage du TextView
Lorsqu’on lance notre application avec l’émulateur, notre grille contient des tirets, notre TextView affiche « Result » et notre bouton affiche « NEW GAME » (et il ne se passe rien quand on clique dessus).
Nous allons modifier le texte du TextView au démarrage de l’application en lui affectant de nouveaux caractères. Cela est aussi simple que :
tvGameResult.setText("Nouveau texte");
Et voilà, ce n’est pas plus compliqué !
Relancez l’application pour voir le nouveau texte s’afficher. ![]()
C’est une bonne idée de tester régulièrement son application avec l’émulateur, surtout au début, lorsque l’on ne connait pas encore bien le fonctionnement d’Android. Faites-le après chaque tâche spécifique, cela vous évitera d’avoir un cumul de bugs ! ![]()
iii. Événement du bouton
Maintenant, faisons quelque chose lorsqu’on appuie sur le bouton « New Game ».
En fait, il existe 5 méthodes différentes pour récupérer l’événement « clic » d’un bouton… Nous n’en verrons que 2 :
- En utilisant une classe anonyme,
- En pointant une méthode.
a) Classe anonyme
Nous allons ajouter un écouteur à notre bouton. Tapez le nom de la variable « btNewGame », suivi d’un point, puis sélectionnez « setOnClickListener » dans la liste (commencez à taper le nom de la méthode pour l’afficher plus rapidement).
En paramètre de cette méthode, on doit passer l’interface « OnClickListener » (disponible dans la classe « View ») et en redéfinir sa méthode « onClick ». Ce qui donne :
btNewGame.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { initialize(); } } );
Voilà, c’est fait !
Dès lors, chaque fois que l’on va cliquer sur le bouton, ce qui se trouve dans « onClick » sera exécuté. Quoi ?!
Ah mais oui, il n’y a rien dans la méthode ! ![]()
Et bien dans ce cas, modifions le TextView tiens !
Il suffit d’y insérer :
tvGameResult.setText("Nouvelle partie !");
Faites le test ! Au démarrage de l’application, le TextView contient « Nouveau texte » et lorsqu’on clique sur le bouton, le texte est remplacé par « Nouvelle partie ! ». ![]()
b) Pointer une méthode
Utilisons l’autre façon de procéder pour la grille. Nous allons donc associer une méthode à l’événement « clic » des boutons. Pour commencer, ajoutez la méthode suivante dans la classe « GameScreen » :
public void action_grille(View v){
String leTexte = "Id de la case : " + v.getId();
tvGameResult.setText(leTexte);
}
À noter que pour associer une méthode à un objet, la signature de la méthode sera toujours identique à celle-là ! Il est obligatoire d’avoir pour seul paramètre « View ». De plus, elle doit être publique et ne rien retourner. La raison est que l’objet va se passer lui-même en paramètre et nous permettra de savoir qui a appelé cette méthode ! ![]()
À savoir également que tous les objets graphiques héritent de « View ».
Ensuite, il faut retourner dans « activity_game_screen.xml » et associer notre méthode à la propriété « onClick » de chaque bouton de la grille. Pour cela, 2 méthodes déjà évoquée :
- Depuis le mode « Design »

- Depuis le mode « Text »

Une fois les neuf boutons faits, relancez l’application dans l’émulateur et appuyez sur chacun d’entre eux pour voir l’identifiant du bouton s’afficher.
Vous aurez peut-être remarqué au passage que, lorsque le texte s’affiche, le bouton « New Game » s’agrandit !
(Cliquez sur ce bouton et voyez également que le texte n’est pas centré.) Prenez note que nous devrons corriger cette bizarrerie lorsqu’on retournera finir notre interface ! ![]()
iv. Fin des tests
Maintenant que nous avons vu comment cela fonctionne, nous allons supprimer le code de test et ajouter ce dont on a besoin pour faire fonctionner notre jeu. ![]()
Dans la méthode « onClick » de « btNewGame », remplacer le code qui s’y trouve par : « initialize(); ». Ensuite, créez cette méthode privée dans laquelle on va :
- Vider la grille
- Vider « tvGameResult »
- Initialiser le jeu
Ce qui donne :
private void initialize(){ // On vide de la grille for( Button b : listButton){ b.setForeground(null); b.setText(""); } // On vide le message de fin de partie tvGameResult.setText(""); // On initialise le jeu gameManager.initialiser(); }
Ah oui !
Pour l’initialisation du jeu, nous avons besoin d’un objet, instance de la classe « GameManager ». Il faut donc ajouter cette déclaration avec les variables globales :
GameManager gameManager = new GameManager();
On ajoute également un appel à la méthode « initialize() » dans « onCreate », afin d’initialiser le jeu au démarrage de l’application (n’oubliez pas que cette méthode est appelée lorsqu’on lance l’application, avant que l’interface ne s’affiche
).
Pour finir, supprimez le contenu du la méthode « action_grille », nous allons y insérer l’appel à la logique du jeu ! ![]()
C. Appel du code du jeu
La méthode « action_grille » contient le code qui fait le lien entre l’activité et la logique du jeu.
Cela se résume à peu de chose !
Lorsqu’on appuie sur un bouton dans la grille, on lui affecte un « X ». Ensuite, c’est au tour du jeu de jouer (« O »).
a) Logique
Le joueur « X » (vous) commence toujours. Puis c’est au tour de l’IA (« O »). Après que le joueur « O » ait joué, on vérifie le résultat de la partie et on se retrouve avec 5 possibilités :
- La partie n’est pas finie, le joueur « O » vient de jouer, on met un « O » dans la case,
- La partie est finie, match nul, on affiche le résultat,
- La partie est finie, « X » a gagné, on affiche le résultat,
- La partie est finie, « O » a gagné, on affiche le résultat,
- La partie est finie, le résultat est déjà affiché, donc on ne fait rien.
Pour que l’IA sache ce qu’il en est de la partie, elle a besoin de connaitre la position du bouton dans la grille qui vient d’être pressé, selon ce schéma :
0 1 2
3 4 5
6 7 8
b) Ajout d’un « tag »
Lorsque nous appuyons sur un bouton, nous devons indiquer à l’IA l’indice correspondant : soit un chiffre de 0 à 8.
Nous allons donc affecter un « tag » à chacun de nos boutons dans l’interface graphique. Pour cela, retournons dans le fichier « activity_game_screen.xml » et ajoutons cette ligne à chaque bouton, où « i » est le chiffre correspondant à la position :
android:tag="i"
Ce qui donne pour le premier bouton, en haut à gauche :
<Button android:id="@+id/bt_case_0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="action_grille" android:tag="0" android:text="@string/case_tiret" />
La propriété « tag » sert à donner une information supplémentaire à un objet. L’IA utilise une matrice avec les chiffres de 0 à 8, ainsi, grâce au tag, on évite d’avoir à utiliser une quelconque mécanique permettant d’associer le bon chiffre au bon bouton ! ![]()
c) Lecture du « tag »
Tel que nous l’avons vu précédemment, chaque bouton appelle la fonction « action_grille » en se passant en paramètre. Nous savons donc quel bouton a créé l’événement. Pour récupérer le « tag » associé, nous allons utiliser la méthode « getTag() », tout simplement ! ![]()
Button bt = (Button)v; // "v" est le paramètre passé à la fonction int buttonPosition = Integer.parseInt(bt.getTag().toString());
Étant donné qu’on reçoit un View en paramètre, il nous faut d’abord le Caster pour en faire un bouton. Ensuite, puisque le Tag est une String, nous devons le transformer en Integer, car c’est ce que prend en paramètre l’IA ; c’est ce que fait « Integer.parseInt ».
Voici le code de la méthode « action_grille » au complet :
public void action_grille(View v){ Button bt = (Button)v; int buttonPosition = Integer.parseInt(bt.getTag().toString()); // On s'assure que la case est libre if(!gameManager.isFinished() && bt.getText().toString().equals("")){ // Placement du joueur X bt.setText("X"); // On interroge l'IA pour connaitre la suite des événements aiResult = gameManager.ia(buttonPosition); switch(aiResult){ // O a joué case AI_O_PLAYED: // On affiche le O sur la grille listButton.get(gameManager.getOLastShot()).setText("O"); break; // Partie nulle case AI_DRAW: // On affiche que la partie est nulle tvGameResult.setText(getResources().getString(R.string.result_draw)); break; // X a gagné case AI_X_WON: // On affiche que le joueur a gagné tvGameResult.setText(getResources().getString(R.string.result_win)); break; // O a gagné case AI_O_WON: // On affiche d'abord le O sur la grille listButton.get(gameManager.getOLastShot()).setText("O"); // Puis, on affiche que le joueur a perdu tvGameResult.setText(getResources().getString(R.string.result_lose)); break; // Rien de spécial case AI_NOTHING: default: break; } } }
Voyez qu’il n’y a rien de sorcier dans ce code. La seule nouveauté est la suivante :
getResources().getString(R.string.result_draw)
Ceci permet d’aller cherche une chaine de caractère dans le fichier « string.xml ». À bien y regarder, cette commande ressemble un peu à celle qui permet de récupérer l’identifiant d’un objet, souvenez-vous :
btNewGame = (Button)findViewById(R.id.bt_new_game);
Sauf qu’ici, on ne veut pas un Id, mais une String ! Et tout comme on le fait pour un objet, on récupère une chaine de caractères en précisant son identifiant (celui déclaré dans le fichier XML).
En passant, il ne faut pas oublier d’ajouter les 3 textes suivants dans le fichier « string.xml » :
<string name="result_draw">Draw...</string> <string name="result_win">You Win!</string> <string name="result_lose">You Lose!</string>
D. Test final
Et voilà, il ne vous reste plus qu’à tester tout ça avec l’émulateur ! ![]()
À noter que l’IA ne vous permet pas de gagner…
Eh oui, désolé !
Au mieux, vous pouvez faire match nul. Nous verrons dans un chapitre ultérieur comment ajouter un niveau de difficulté. ![]()
E. Conclusion
Ça y est, nous avons une application fonctionnelle !
On pourrait s’arrêter là, mais il y a encore de nombreuses choses que l’on peut améliorer. (Si, si, je vous assure !
)
Nous allons commencer par la rendre un peu plus présentable en corrigeant le problème du bouton qui se redimensionne. Ensuite, nous allons centrer le texte du résultat. Rien de bien méchant ici.
Ensuite, nous allons parer notre (hideuse) interface avec de jolies couleurs !
Nous mettrons également en lumière la combinaison gagnante en lui appliquant une couleur différente lorsque la partie a été gagnée. ![]()
Voilà le programme du prochain chapitre ! ![]()
F. Plus tard…
Suite à cela, ne vous croyez pas à l’abri des problèmes, car il y en a encore !
Un exemple ?
Lancez l’émulateur et jouez un coup ou deux. À présent, tournez l’appareil avec un des boutons appropriés (« Rotate left » ou « Rotate right ») :

Oh ! Tout a disparu ! On a perdu la partie en cours… ![]()
Nous reviendrons sur cet élément crucial du développement d’une application Android ! ![]()
A bientôt pour le chapitre 5 ! ![]()

English
Français 
