I. L'article original

Cet article est la traduction de My First QML App.

II. Comment j'ai créé un jeu en JavaScript avec Qt Creator

Image non disponible

Le framework de développement pour MeeGo est nommé Qt (prononcez « cute »). Qt provient du monde de Symbian, de Nokia, et correspond à un framework de développement passionnant, permettant de mettre en place rapidement des applications multiplateformes utilisant soit du C++, soit du JavaScript. Les outils de Nokia sont plutôt cools. On peut générer une application Qt en utilisant Linux, Windows ou Mac.

III. L'EDI du cœur de MeeGo est Qt Creator

Qt Creator est l'EDI gratuit qui vient avec le SDK de Qt et qui est distribué avec celui de MeeGo. Qt Creator vous permet de générer un projet C++, QML (JavaScript) ou encore un projet d'application portable. Qt Creator va émuler un grand nombre d'appareils, incluant des téléphones de Nokia, vous permettant de développer et de tester vos applications sans avoir besoin d'un accès au matériel. Pour les applications QML, cette version bêta du SDK ne permet pas de compiler l'application, mais il reste possible de lancer l'application sur votre Windows, Mac ou Linux via l'application Qt Viewer.

Pour ma première application, j'ai utilisé QML parce que je suis plus à l'aise avec le JavaScript qu'avec le C++. QML est un framework pour le développement d'applications utilisant le JavaScript. Pour les développeurs Web (ou pour les ex-développeurs Web), c'est plutôt sympathique. De plus, il est possible de prendre en main QML assez rapidement et de générer des applications cibles pour téléphone portable. En effet, on a accès aux objets Qt et aux bibliothèques, ce qui est relativement pratique pour obtenir un bel ensemble d'objets pour portable et de bibliothèques facilement manipulables avec le JavaScript.

Par souci d'objectivité, il est bon de préciser que mon application n'est pas réellement MON application. J'ai suivi un tutoriel qui m'a mené à une application que j'ai modifiée ; il n'en est pas moins que le cœur du code reste basé sur celui du tutoriel appelé SameGame. Ce cœur est le centre de tout développement d'application QML, d'où le fait que nous allons commencer par du code de référence, puis continuer à partir de là.

Tutoriel de SameGameTutoriel de SameGame

Image non disponible

SameGame est un jeu basique. Un nombre donné de balles colorées remplissent une petite fenêtre. Vous pouvez faire éclater et ainsi retirer de l'écran deux balles ou plus de la même couleur qui se touchent. Il y a quelques petites choses intéressantes ici, y compris un effet de particules plutôt cool utilisé quand les balles explosent. Dans SameGame, il y a trois couleurs et la partie se termine dès qu'on ne peut plus faire de coup ou bien dès que l'écran est vide. À la fin, le score est ajouté à un tableau de statistiques où le top dix des scores est affiché.

IV. Création du PopFruit

PopFruit - de trois à six fruits, progressant sur trois niveaux
PopFruit - de trois à six fruits, progressant sur trois niveaux

Pour ma version du SameGame, appelé PopFruit, j'ai changé l'application pour convenir à un écran de netbook, j'ai remplacé les couleurs par des fruits et j'ai ajouté des niveaux dans lesquels de nouveaux fruits apparaissent dans l'espace du jeu, rendant plus ardue la tâche de l'épuration de l'écran.

V. Les fichiers du projet

Image non disponible

Le projet QML : ces fichiers présentent la totalité des fichiers utilisés par mon application. En lançant le fichier sélectionné dans Qt Creator, j'ai obtenu tous les fichiers nécessaires à la création et à la gestion du programme.

Les fichiers QML : similaires aux feuilles de style d'une page Web. Ces fichiers détaillent la structure de l'application. Pour PopFruit, nous avons un fichier QML principal pour l'espace du jeu et d'autres pour les blocs, pour les boutons et les boîtes de dialogue.

Le fichier JavaScript : l'endroit où toute la partie logique du jeu est placée. C'est là que l'on crée nos variables, que nous créons nos fonctions et notre logique conditionnelle.

Le dossier shared : le projet contient un dossier nommé shared où tous les éléments graphiques du jeu sont stockés.

VI. Changement du jeu

La première chose que je voulais faire était d'ajouter plus de balles et des niveaux de jeu à l'espace du jeu. Je ne savais pas combien j'en voulais, j'ai donc décidé de créer une variable pour les balles et les niveaux. Au début, j'ai pensé qu'il pourrait y avoir le niveau de jeu et le nombre de balles dans la même variable, mais, finalement, il m'est venu à l'idée que je pourrais créer des niveaux possédant autant ou moins de balles que le niveau précédent, d'où la séparation des deux.

Image non disponible

Si j'étais sur le point d'avoir de nouvelles balles, je devais en faire des fruits. Je devais donc faire des changements graphiques et au bout du compte éditer mon jeu. Pour faire cela, j'ai utilisé GIMP pour éditer les images en remplaçant l'image redstone.png avec l'image d'une pomme rouge, bluestone.png par celle d'une baie bleue et greenstone.png par celle d'un citron vert. Cela donnait le même jeu mais avec des fruits rouges, bleus et verts. J'ai alors copié le fichier greenstar.png (l'effet d'éclat étoilé) pour faire l'éclat violet et un éclat jaune avec GIMP. Puis j'ai créé les images yellowstone.png et purplestone.png, j'en ai fait une banane et une prune. Pour ajouter ces deux images dans le jeu, j'ai trouvé deux endroits où les images sont appelées dans le code et j'ai ajouté deux conditions de plus pour inclure le fruit jaune et le fruit violet.

Code de SameCode dans BoomBlock.QML

 
Sélectionnez
if (type==0)
  return "../../share/pics/redstone.png";
else if (type == 1)
  return "../../share/pics/bluestone.png";
else 
  return "../../share/pics/greenstone.png";

Code du PopFruit

 
Sélectionnez
if (type==0)
  return "../../share/pics/redstone.png";
else if (type == 1)
  return "../../share/pics/bluestone.png";
else if (type == 2)
  return "../../share/pics/greenstone.png";
else if (type == 3)
  return "../../share/pics/yellowstone.png";
else
  return "../../share/pics/purplestone.png";

J'ai répété l'opération pour la section de code traitant des images des effets d'éclats étoilés.

Image non disponible

Cela n'ajouta pas plus de fruits au jeu qui, à ce moment-là, avait toujours trois couleurs de fruits. Pour fixer ce problème, j'ai édité la fonction CreateBlock dans le JavaScript en changeant DynamicObject.type=Math.floor(Math.random() * 3) par DynamicObject.type=Math.floor(Math.random() * 6).

Cela me donna tous les fruits mais, pour faire marcher cela de manière à ce que j'aie plus de fruits à chaque niveau, j'avais besoin d'une variable plutôt que d'un multiplicateur statique. J'ai donc changé le multiplicateur par ma variable ballcolors définie plus tôt : DynamicObject.type=Math.floor(Math.random() * ballcolors).

Parce que le jeu n'avait qu'un niveau, ce dernier se terminait quand il n'y avait plus aucun coup possible. Je devais donc trouver un moyen d'éviter la fin du jeu au moment où toutes les balles avaient explosé. J'ai finalement déterminé ce qui, selon moi, était la meilleure façon de procéder : changer ma variable de niveau et ajouter un autre fruit dans un nouveau niveau. Alors, si la variable de niveau atteignait le niveau maximum, le jeu pouvait se terminer après la disparition du dernier fruit. Et pour mettre en place une certaine convivialité, il manquait une nouvelle boîte de dialogue entre la fin d'un niveau et le début d'un nouveau, l'annonçant.

Pour faire tout cela, j'ai dans un premier temps lié la variable ballcolors aux niveaux de jeu dans une nouvelle fonction, nommée startNewGame. Ainsi, si je démarrais une nouvelle partie (c'est-à-dire si gamelevel == 1), le nombre de fruits devrait être de trois et, si j'atteignais le troisième niveau, ce nombre devrait être à cinq, si, à chaque niveau, un unique fruit était ajouté au jeu. Par conséquent, le nombre de fruits, ballcolors, équivaudrait au niveau plus deux. À cet effet, c'était plus ou moins en ordre, même si j'aurais pu créer une fonction plus appropriée, cela fonctionnait.

Image non disponible

Avant que cela puisse fonctionner, j'ai dû définir le nouveau niveau de jeu lorsqu'il n'y avait plus aucun coup possible. En étudiant la portion de code qui vérifiait si le jeu permettait la réalisation ou non de plus de coups, j'ai vu que, à la place de finir la partie, cela définissait une variable pour la boîte de dialogue à l'écran. En réalité, cette portion était composée de deux parties, correspondant au fait que l'écran soit complètement nettoyé ou bien à ce qu'il n'y ait plus de coup possible. Dans le premier cas, le texte de la boîte de dialogue se verrait suivi d'un message disant qu'on a gagné cinq cents points, eux-mêmes ajoutés au score. Dans le second cas, un message de game over serait donné.

Je ne voulais pas appeler la même boîte de dialogue entre les niveaux. Je me suis alors rendu compte que j'avais besoin de cette fenêtre quand la partie était susceptible de se terminer ; j'ai donc entrepris la mise en place d'une nouvelle boîte de dialogue pour afficher les différents niveaux.

La fonction victoryCheck dans mon fichier JavaScript détermine s'il reste des coups. J'ai donc pris compte de la nécessité de définir que, si aucun coup de plus ne pouvait être réalisé ou bien si l'écran était vierge, le nombre correspondant au niveau de jeu serait incrémenté et que le message de fin de niveau serait envoyé.

Pour m'occuper de cette alerte au milieu de la fonction victoryCheck et de mon nouveau niveau, j'ai aussi créé un nouvel objet Dialog, avec l'ID newlevelDialogue dans mon fichier QML principal. Cet objet héritait donc de propriétés de Dialog. Le fichier QML fait en sorte que la boîte de dialogue soit fermée tant que son texte n'est pas défini. Je lui ai alors ajouté un argument onClosed qui appelle la fonction startNewGame dans mon fichier JavaScript.

Code de la fonction victoryCheck pour ajouter le bonus et pour définir un nouveau texte pour alerter de la progression dans les niveaux

 
Sélectionnez
function victoryCheck() {
 
//![3]
 
//Award bonus points if no blocks left
var deservesBonus = true;
 
for(var column = maxColumn-1; column>=0; column--)
  if(board[index(column, maxRow-1)] != null)
    deservesBonus = false;
 
if(deservesBonus) {
  gameCanvas.score += 500;
  bonustext = "500pt Bonus!"
}
 
//![4]
 
//Check whether game has finished
if(deservesBonus || !(floodMoveCheck(0, maxRow-1, -1))) {
  gameDuration = newDate()-gameDuration;
  gamelevel = gamelevel+1
  newlevelDialog.show(gameCanvas.score + "pts" + bonustext + "NoMoreMoves.ClickToGoToLevel" + gamelevel)
  bonustext=""
}

La nouvelle boîte de dialogue ajoutée au fichier QML principal

 
Sélectionnez
Dialog {
  id:newlevelDialog
  border.color:"purple"
  border.width:10
  height:75
  color:"#f9f06e"
  width:500
  clip:false
  anchors.centerIn:parent
  radius:10
  z:100
  onClosed:SameGame.startNewGame(SameGame.gamelevel)
}
//![0]

Cela fait, j'ai pu tirer de ma fonction victoryCheck :

  • les bonus ;
  • l'incrémentation du niveau de jeu ;
  • la définition du message de dialogue ;
  • le redémarrage du jeu à la fermeture du message.

Et, puisque mon redémarrage du jeu définit le nombre de fruits à gamelevel +2, le compte de fruits est maintenant à quatre.

Cela continuerait d'arriver et de causer une erreur au quatrième niveau, après que le compte de fruits a atteint la valeur six, soit au moment où il n'y a plus d'image de fruit à charger. Alors, dans ma vérification de victoire, si le niveau atteint le niveau 4, j'ai dû réinsérer la boîte de dialogue originale de fin de partie, qui permet de plus d'informer d'un éventuel game over et d'enregistrer le score dans les statistiques.

 
Sélectionnez
if(deservesBonus || !(floodMoveCheck(0, maxRow-1, -1))) {
  gameDuration = newDate()-gameDuration;
  gamelevel = gamelevel+1
  if(gamelevel >= 4)
    nameInputDialog.showWithInput("GameOver! YourScore: " + gameCanvas.score + "pts. Add your name to record your score")
  else {
    newlevelDialog.show(gameCanvas.score + "pts" + bonustext + "No More Moves. Click To Go To Level" + gamelevel)
    bonustext = ""
  }
}

VII. Conclusion

Malgré tout cela, la génération du jeu était très facile. J'ai fait quelques petites choses en plus qui ne sont pas référencées dans cet article, mais, heureusement, vous avez pu voir à quel point il était facile de coder. Vous pouvez également utiliser la partie Qt Designer de Qt Creator pour éditer visuellement les objets de votre jeu. Les changements faits par le biais de Qt Designer sont directement traduits dans vos fichiers QML.

À vrai dire, ce n'est pas ma première expérience avec Qt Creator. Pour débuter et pour apprendre de vous-même, téléchargez le SDK de MeeGo, qui inclut Qt Creator, ou téléchargez le SDK de Qt beta 2.1 depuis le site de Qt. J'aimerais entendre parler de ce que vous avez appris ainsi que des projets que vous avez entrepris.

Ci-dessous se trouve une copie de mon projet QML PopFruitune copie de mon projet QML PopFruit avec laquelle vous pouvez jouer. N'hésitez pas à améliorer ce que j'ai fait, à ajouter des changements d'orientation, des sons ou à intégrer un lien Facebook ou Twitter pour partager les scores. Si cela vous tente, partagez votre travail !

VIII. Remerciements

Merci à Thibaut Cuvelier et à Claude Leloup pour leur relecture !