Sophie

Sophie

distrib > Mageia > 7 > i586 > media > core-updates > by-pkgid > 6e2327ca1c896c6d674ae53117299f21 > files > 1809

qtdeclarative5-doc-5.12.6-1.mga7.noarch.rpm

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- advtutorial.qdoc -->
  <title>QML Advanced Tutorial 3 - Implementing the Game Logic | Qt Quick 5.12.6</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td >Qt 5.12</td><td ><a href="qtquick-index.html">Qt Quick</a></td><td >QML Advanced Tutorial 3 - Implementing the Game Logic</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtquick-index.html">Qt 5.12.6 Reference Documentation</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
  <link rel="prev" href="qtquick-tutorials-samegame-samegame2-example.html" />
  <link rel="next" href="qtquick-tutorials-samegame-samegame4-example.html" />
<p class="naviNextPrevious headerNavi">
<a class="prevPage" href="qtquick-tutorials-samegame-samegame2-example.html">QML Advanced Tutorial 2 - Populating the Game Canvas</a>
<span class="naviSeparator">  &#9702;  </span>
<a class="nextPage" href="qtquick-tutorials-samegame-samegame4-example.html">QML Advanced Tutorial 4 - Finishing Touches</a>
</p><p/>
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level2"><a href="#making-a-playable-game">Making a Playable Game</a></li>
<li class="level2"><a href="#a-working-game">A Working Game</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">QML Advanced Tutorial 3 - Implementing the Game Logic</h1>
<span class="subtitle"></span>
<!-- $$$tutorials/samegame/samegame3-description -->
<div class="descr"> <a name="details"></a>
<a name="making-a-playable-game"></a>
<h3 id="making-a-playable-game">Making a Playable Game</h3>
<p>Now that we have all the game components, we can add the game logic that dictates how a player interacts with the blocks and plays the game until it is won or lost.</p>
<p>To do this, we have added the following functions to <code>samegame.js</code>:</p>
<ul>
<li><code>handleClick(x,y)</code></li>
<li><code>floodFill(xIdx,yIdx,type)</code></li>
<li><code>shuffleDown()</code></li>
<li><code>victoryCheck()</code></li>
<li><code>floodMoveCheck(xIdx, yIdx, type)</code></li>
</ul>
<p>As this is a tutorial about QML, not game design, we will only discuss <code>handleClick()</code> and <code>victoryCheck()</code> below since they interface directly with the QML types. Note that although the game logic here is written in JavaScript, it could have been written in C++ and then exposed to QML.</p>
<a name="enabling-mouse-click-interaction"></a>
<h4 id="enabling-mouse-click-interaction">Enabling Mouse Click Interaction</h4>
<p>To make it easier for the JavaScript code to interface with the QML types, we have added an Item called <code>gameCanvas</code> to <code>samegame.qml</code>. It replaces the background as the item which contains the blocks. It also accepts mouse input from the user. Here is the item code:</p>
<pre class="qml">

          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)
              }
          }

</pre>
<p>The <code>gameCanvas</code> item is the exact size of the board, and has a <code>score</code> property and a <a href="qml-qtquick-mousearea.html">MouseArea</a> to handle mouse clicks. The blocks are now created as its children, and its dimensions are used to determine the board size so that the application scales to the available screen size. Since its size is bound to a multiple of <code>blockSize</code>, <code>blockSize</code> was moved out of <code>samegame.js</code> and into <code>samegame.qml</code> as a QML property. Note that it can still be accessed from the script.</p>
<p>When clicked, the <a href="qml-qtquick-mousearea.html">MouseArea</a> calls <code>handleClick()</code> in <code>samegame.js</code>, which determines whether the player's click should cause any blocks to be removed, and updates <code>gameCanvas.score</code> with the current score if necessary. Here is the <code>handleClick()</code> function:</p>
<pre class="js">

  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;
      //If it's a valid block, remove it and all connected (does nothing if it's not connected)
      floodFill(column, row, -1);
      if (fillFound <= 0)
          return;
      gameCanvas.score += (fillFound - 1) * (fillFound - 1);
      shuffleDown();
      victoryCheck();
  }

</pre>
<p>Note that if <code>score</code> was a global variable in the <code>samegame.js</code> file you would not be able to bind to it. You can only bind to QML properties.</p>
<a name="updating-the-score"></a>
<h4 id="updating-the-score">Updating the Score</h4>
<p>When the player clicks a block and triggers <code>handleClick()</code>, <code>handleClick()</code> also calls <code>victoryCheck()</code> to update the score and to check whether the player has completed the game. Here is the <code>victoryCheck()</code> code:</p>
<pre class="js">

  function victoryCheck() {
      //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;

      //Check whether game has finished
      if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1)))
          dialog.show("Game Over. Your score is " + gameCanvas.score);
  }

</pre>
<p>This updates the <code>gameCanvas.score</code> value and displays a &quot;Game Over&quot; dialog if the game is finished.</p>
<p>The Game Over dialog is created using a <code>Dialog</code> type that is defined in <code>Dialog.qml</code>. Here is the <code>Dialog.qml</code> code. Notice how it is designed to be usable imperatively from the script file, via the functions and signals:</p>
<pre class="qml">

  import QtQuick 2.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();
      }
  }

</pre>
<p>And this is how it is used in the main <code>samegame.qml</code> file:</p>
<pre class="qml">

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

</pre>
<p>We give the dialog a <a href="qml-qtquick-item.html#z-prop">z</a> value of 100 to ensure it is displayed on top of our other components. The default <code>z</code> value for an item is 0.</p>
<a name="a-dash-of-color"></a>
<h4 id="a-dash-of-color">A Dash of Color</h4>
<p>It's not much fun to play Same Game if all the blocks are the same color, so we've modified the <code>createBlock()</code> function in <code>samegame.js</code> to randomly create a different type of block (for either red, green or blue) each time it is called. <code>Block.qml</code> has also changed so that each block contains a different image depending on its type:</p>
<pre class="qml">

  import QtQuick 2.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";
          }
      }
  }

</pre>
<a name="a-working-game"></a>
<h3 id="a-working-game">A Working Game</h3>
<p>Now we now have a working game! The blocks can be clicked, the player can score, and the game can end (and then you can start a new one). Here is a screenshot of what has been accomplished so far:</p>
<p class="centerAlign"><img src="images/declarative-adv-tutorial3.png" alt="" /></p><p>This is what <code>samegame.qml</code> looks like now:</p>
<pre class="qml">

  import QtQuick 2.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?"
          }
      }
  }

</pre>
<p>The game works, but it's a little boring right now. Where are the smooth animated transitions? Where are the high scores? If you were a QML expert you could have written these in the first iteration, but in this tutorial they've been saved until the next chapter - where your application becomes alive!</p>
<p>Files:</p>
<ul>
<li><a href="qtquick-tutorials-samegame-samegame3-block-qml.html">tutorials/samegame/samegame3/Block.qml</a></li>
<li><a href="qtquick-tutorials-samegame-samegame3-button-qml.html">tutorials/samegame/samegame3/Button.qml</a></li>
<li><a href="qtquick-tutorials-samegame-samegame3-dialog-qml.html">tutorials/samegame/samegame3/Dialog.qml</a></li>
<li><a href="qtquick-tutorials-samegame-samegame3-samegame-js.html">tutorials/samegame/samegame3/samegame.js</a></li>
<li><a href="qtquick-tutorials-samegame-samegame3-samegame-qml.html">tutorials/samegame/samegame3/samegame.qml</a></li>
<li><a href="qtquick-tutorials-samegame-samegame3-samegame3-qmlproject.html">tutorials/samegame/samegame3/samegame3.qmlproject</a></li>
</ul>
</div>
<!-- @@@tutorials/samegame/samegame3 -->
<p class="naviNextPrevious footerNavi">
<a class="prevPage" href="qtquick-tutorials-samegame-samegame2-example.html">QML Advanced Tutorial 2 - Populating the Game Canvas</a>
<span class="naviSeparator">  &#9702;  </span>
<a class="nextPage" href="qtquick-tutorials-samegame-samegame4-example.html">QML Advanced Tutorial 4 - Finishing Touches</a>
</p>
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2019 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>