IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Viadeo Twitter Facebook Share on Google+   
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Toutes les fonctions  ·  Vues d'ensemble  · 

Tutoriel QML avancé, troisième partie - implémenter la logique du jeu

Fichiers :

Rendre le jeu jouable

Maintenant que l'on a tous les composants du jeu, on peut ajouter la logique du jeu, c'est elle qui guidera les interactions du joueur avec les blocs tout au long de la partie.

Afin de faire cela, on va ajouter les fonctions suivantes au fichier samegame.js :

  • handleClick(x,y) ;
  • floodFill(xIdx,yIdx,type) ;
  • shuffleDown() ;
  • victoryCheck() ;
  • floodMoveCheck(xIdx, yIdx, type).

Comme ce tutoriel concerne plus le QML que la création d'un jeu, on va seulement s'intéresser aux fonctions handleClick() et victoryCheck(), car elles interagissent directement avec les éléments QML. Notez que, même si la logique du jeu est ici écrite en JavaScript, elle aurait pu être écrite en C++ puis exposée au QML.

Activer les interactions aux clics de souris

Pour faciliter l'interfaçage du code JavaScript avec les éléments QML, on a ajouté un élément appelé gameCanvas au fichier samegame.qml. Il s'insère dans le fond et contient les blocs. Il accepte les interactions de l'utilisateur avec la souris. En voici le code :

         Item {
             id: gameCanvas
 
             property int score: 0
             property int blockSize: 40
 
             width: parent.width - (parent.width % blockSize)
             height: parent.height - (parent.height % blockSize)
             anchors.centerIn: parent
 
             MouseArea {
                 anchors.fill: parent
                 onClicked: SameGame.handleClick(mouse.x, mouse.y)
             }
         }

L'élément gameCanvas a la taille exacte de la zone de jeu et possède une propriété score et une MouseArea pour gérer les clics de la souris. Les blocs sont maintenant créés comme enfants de cet élément et leur dimension est utilisée pour déterminer la taille de la zone de jeu. Ainsi, l'application se calque sur l'espace de l'écran. Comme la taille est liée à un multiple de blockSize, la propriété a été déplacée du fichier samegame.js à samegame.qml. Notez que celle-ci peut toujours être accédée depuis le script.

Lors d'un clic, la MouseArea appelle la fonction handleClick() du fichier samegame.js, qui détermine si le clic du joueur provoque la suppression des blocs et met à jour gameCanvas.score avec le nouveau score. Voici le code de la fonction handleClick() :

 function handleClick(xPos, yPos) {
     var column = Math.floor(xPos / gameCanvas.blockSize);
     var row = Math.floor(yPos / gameCanvas.blockSize);
     if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
         return;
     if (board[index(column, row)] == null)
         return;
 
     // Si c'est un bloc valide, on le supprime ainsi que ceux connectés (ne fait rien s'il n'est pas connecté)
     floodFill(column, row, -1);
     if (fillFound <= 0)
         return;
     gameCanvas.score += (fillFound - 1) * (fillFound - 1);
     shuffleDown();
     victoryCheck();
 }

Notez que, si score avait été une variable globale dans le fichier samegame.js, on n'aurait pas pu la lier : on ne peut lier que des propriétés QML.

Mettre à jour le score

Lorsque le joueur clique sur un bloc et déclenche la fonction handleClick(), elle appelle la fonction victoryCheck() pour mettre à jour le score et vérifier si le joueur a fini la partie. Voici le code de la fonction victoryCheck() :

 function victoryCheck() {
     // Récompense s'il n'y a plus aucun bloc
     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;
 
     // Vérifie si le jeu est terminé
     if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1)))
         dialog.show("Game Over. Your score is " + gameCanvas.score);
 }

Cela met à jour la valeur de gameCanvas.score et affiche une boîte de dialogue « Game Over » si la partie est terminée.

La boite de dialogue Game Over est créée en utilisant l'élément Dialog, défini dans le fichier Dialog.qml, dont voici le code. Notez la façon dont elle est implémentée pour être utilisable en impératif à partir du fichier script, via les fonctions et signaux :

 import QtQuick 1.0
 
 Rectangle {
     id: container
 
     function show(text) {
         dialogText.text = text;
         container.opacity = 1;
     }
 
     function hide() {
         container.opacity = 0;
     }
 
     width: dialogText.width + 20
     height: dialogText.height + 20
     opacity: 0
 
     Text {
         id: dialogText
         anchors.centerIn: parent
         text: ""
     }
 
     MouseArea {
         anchors.fill: parent
         onClicked: hide();
     }
 }

Et voici comment elle est utilisée dans le fichier principal samegame.qml :

     Dialog {
         id: dialog
         anchors.centerIn: parent
         z: 100
     }

On donne à la boîte de dialogue une valeur de 100 à z pour s'assurer qu'elle est affichée au-dessus de tous les autres composants. La valeur par défaut de z pour un élément est 0.

Un brin de couleur

Il n'est pas très amusant de jouer à Same Game si tous les blocs sont de la même couleur, on a donc modifié la fonction createBlock() du fichier samegame.js pour créer aléatoirement différents types de blocs (en rouge, vert ou bleu) chaque fois que la fonction est appelée. Le fichier Block.qml a aussi été modifié pour que chaque bloc contienne une image différente selon son type :

 import QtQuick 1.0
 
 Item {
     id: block
 
     property int type: 0
 
     Image {
         id: img
 
         anchors.fill: parent
         source: {
             if (type == 0)
                 return "../shared/pics/redStone.png";
             else if (type == 1)
                 return "../shared/pics/blueStone.png";
             else
                 return "../shared/pics/greenStone.png";
         }
     }
 }

Un jeu fonctionnel

Maintenant, on a un jeu fonctionnel ! Les blocs peuvent être actionnés, le joueur peut marquer des points et la partie peut se conclure (et on peut en démarrer une autre). Voici une capture d'écran de ce qui est fait jusqu'à présent :

image

Le contenu actuel du fichier samegame.qml :

 import QtQuick 1.0
 import "samegame.js" as SameGame
 
 Rectangle {
     id: screen
 
     width: 490; height: 720
 
     SystemPalette { id: activePalette }
 
     Item {
         width: parent.width
         anchors { top: parent.top; bottom: toolBar.top }
 
         Image {
             id: background
             anchors.fill: parent
             source: "../shared/pics/background.jpg"
             fillMode: Image.PreserveAspectCrop
         }
 
         Item {
             id: gameCanvas
 
             property int score: 0
             property int blockSize: 40
 
             width: parent.width - (parent.width % blockSize)
             height: parent.height - (parent.height % blockSize)
             anchors.centerIn: parent
 
             MouseArea {
                 anchors.fill: parent
                 onClicked: SameGame.handleClick(mouse.x, mouse.y)
             }
         }
     }
 
     Dialog {
         id: dialog
         anchors.centerIn: parent
         z: 100
     }
 
     Rectangle {
         id: toolBar
         width: parent.width; height: 30
         color: activePalette.window
         anchors.bottom: screen.bottom
 
         Button {
             anchors { left: parent.left; verticalCenter: parent.verticalCenter }
             text: "New Game"
             onClicked: SameGame.startNewGame()
         }
 
         Text {
             id: score
             anchors { right: parent.right; verticalCenter: parent.verticalCenter }
             text: "Score: Who knows?"
         }
     }
 }

Le jeu fonctionne, mais il est un peu ennuyant. Où sont les transitions animées ? Où sont les meilleurs scores ? Si vous étiez un expert QML, vous auriez écrit ces éléments dès la première itération, mais ce tutoriel les réserve pour le chapitre suivant - là où l'application devient vivante !

[ Précédent : tutoriel QML avancé, deuxième partie - peupler le canevas du jeu ] [ Suivant : tutoriel QML avancé, quatrième partie - finalisation ]

Remerciements

Merci à Alexandre Laurent pour la traduction ainsi qu'à Thibaut Cuvelier, Jonathan Courtois et Claude Leloup pour leur relecture !

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.7
Copyright © 2021 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur, une redirection cassée ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !