File: declarative-tutorials-samegame-samegame3.html

package info (click to toggle)
qt4-x11 4%3A4.8.2%2Bdfsg-11
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 701,696 kB
  • sloc: cpp: 2,686,179; ansic: 375,485; python: 25,859; sh: 19,349; xml: 17,091; perl: 14,765; yacc: 5,383; asm: 5,038; makefile: 1,259; lex: 555; ruby: 526; objc: 347; cs: 112; pascal: 112; php: 54; sed: 34
file content (280 lines) | stat: -rw-r--r-- 22,591 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- advtutorial.qdoc -->
  <title>Qt 4.8: QML Advanced Tutorial 3 - Implementing the Game Logic</title>
  <link rel="stylesheet" type="text/css" href="style/offline.css" />
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="content"> 
    <a href="index.html" class="qtref"><span>Qt Reference Documentation</span></a>
  </div>
  <div class="breadcrumb toolblock">
    <ul>
      <li class="first"><a href="index.html">Home</a></li>
      <!--  Breadcrumbs go here -->
<li><a href="all-examples.html">Examples</a></li>
<li>QML Examples &amp; Demos</li>
<li>QML Advanced Tutorial 3 - Implementing the Game Logic</li>
    </ul>
  </div>
</div>
<div class="content mainContent">
  <link rel="prev" href="declarative-tutorials-samegame-samegame2.html" />
  <link rel="next" href="declarative-tutorials-samegame-samegame4.html" />
<p class="naviNextPrevious headerNavi">
<a class="prevPage" href="declarative-tutorials-samegame-samegame2.html">QML Advanced Tutorial 2 - Populating the Game Canvas</a>
<a class="nextPage" href="declarative-tutorials-samegame-samegame4.html">QML Advanced Tutorial 4 - Finishing Touches</a>
</p><p/>
<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="level3"><a href="#enabling-mouse-click-interaction">Enabling mouse click interaction</a></li>
<li class="level3"><a href="#updating-the-score">Updating the score</a></li>
<li class="level3"><a href="#a-dash-of-color">A dash of color</a></li>
<li class="level2"><a href="#a-working-game">A working game</a></li>
</ul>
</div>
<h1 class="title">QML Advanced Tutorial 3 - Implementing the Game Logic</h1>
<span class="subtitle"></span>
<!-- $$$declarative/tutorials/samegame/samegame3-description -->
<div class="descr"> <a name="details"></a>
<p>Files:</p>
<ul>
<li><a href="declarative-tutorials-samegame-samegame3-block-qml.html">declarative/tutorials/samegame/samegame3/Block.qml</a></li>
<li><a href="declarative-tutorials-samegame-samegame3-button-qml.html">declarative/tutorials/samegame/samegame3/Button.qml</a></li>
<li><a href="declarative-tutorials-samegame-samegame3-dialog-qml.html">declarative/tutorials/samegame/samegame3/Dialog.qml</a></li>
<li><a href="declarative-tutorials-samegame-samegame3-samegame-js.html">declarative/tutorials/samegame/samegame3/samegame.js</a></li>
<li><a href="declarative-tutorials-samegame-samegame3-samegame-qml.html">declarative/tutorials/samegame/samegame3/samegame.qml</a></li>
<li><a href="declarative-tutorials-samegame-samegame3-samegame3-qmlproject.html">declarative/tutorials/samegame/samegame3/samegame3.qmlproject</a></li>
</ul>
<a name="making-a-playable-game"></a>
<h3>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 <tt>samegame.js</tt>:</p>
<ul>
<li><tt>handleClick(x,y)</tt></li>
<li><tt>floodFill(xIdx,yIdx,type)</tt></li>
<li><tt>shuffleDown()</tt></li>
<li><tt>victoryCheck()</tt></li>
<li><tt>floodMoveCheck(xIdx, yIdx, type)</tt></li>
</ul>
<p>As this is a tutorial about QML, not game design, we will only discuss <tt>handleClick()</tt> and <tt>victoryCheck()</tt> below since they interface directly with the QML elements. 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>Enabling mouse click interaction</h4>
<p>To make it easier for the JavaScript code to interface with the QML elements, we have added an Item called <tt>gameCanvas</tt> to <tt>samegame.qml</tt>. 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">         <span class="type"><a href="qml-item.html">Item</a></span> {
             <span class="name">id</span>: <span class="name">gameCanvas</span>

             property <span class="type">int</span> <span class="name">score</span>: <span class="number">0</span>
             property <span class="type">int</span> <span class="name">blockSize</span>: <span class="number">40</span>

             <span class="name">width</span>: <span class="name">parent</span>.<span class="name">width</span> <span class="operator">-</span> (<span class="name">parent</span>.<span class="name">width</span> <span class="operator">%</span> <span class="name">blockSize</span>)
             <span class="name">height</span>: <span class="name">parent</span>.<span class="name">height</span> <span class="operator">-</span> (<span class="name">parent</span>.<span class="name">height</span> <span class="operator">%</span> <span class="name">blockSize</span>)
             <span class="name">anchors</span>.centerIn: <span class="name">parent</span>

             <span class="type"><a href="qml-mousearea.html">MouseArea</a></span> {
                 <span class="name">anchors</span>.fill: <span class="name">parent</span>
                 <span class="name">onClicked</span>: <span class="name">SameGame</span>.<span class="name">handleClick</span>(<span class="name">mouse</span>.<span class="name">x</span>, <span class="name">mouse</span>.<span class="name">y</span>)
             }
         }</pre>
<p>The <tt>gameCanvas</tt> item is the exact size of the board, and has a <tt>score</tt> property and a <a href="qml-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 <tt>blockSize</tt>, <tt>blockSize</tt> was moved out of <tt>samegame.js</tt> and into <tt>samegame.qml</tt> as a QML property. Note that it can still be accessed from the script.</p>
<p>When clicked, the <a href="qml-mousearea.html">MouseArea</a> calls <tt>handleClick()</tt> in <tt>samegame.js</tt>, which determines whether the player's click should cause any blocks to be removed, and updates <tt>gameCanvas.score</tt> with the current score if necessary. Here is the <tt>handleClick()</tt> function:</p>
<pre class="js"> <span class="keyword">function</span> <span class="name">handleClick</span>(<span class="name">xPos</span>, yPos) {
     var <span class="name">column</span> = <span class="name">Math</span>.<span class="name">floor</span>(<span class="name">xPos</span> <span class="operator">/</span> <span class="name">gameCanvas</span>.<span class="name">blockSize</span>);
     var <span class="name">row</span> = <span class="name">Math</span>.<span class="name">floor</span>(<span class="name">yPos</span> <span class="operator">/</span> <span class="name">gameCanvas</span>.<span class="name">blockSize</span>);
     <span class="keyword">if</span> (<span class="name">column</span> <span class="operator">&gt;=</span> <span class="name">maxColumn</span> <span class="operator">||</span> <span class="name">column</span> <span class="operator">&lt;</span> <span class="number">0</span> <span class="operator">||</span> <span class="name">row</span> <span class="operator">&gt;=</span> <span class="name">maxRow</span> <span class="operator">||</span> <span class="name">row</span> <span class="operator">&lt;</span> <span class="number">0</span>)
         <span class="keyword">return</span>;
     <span class="keyword">if</span> (<span class="name">board</span>[<span class="name">index</span>(<span class="name">column</span>, <span class="name">row</span>)] <span class="operator">==</span> <span class="number">null</span>)
         <span class="keyword">return</span>;
     <span class="comment">//If it's a valid block, remove it and all connected (does nothing if it's not connected)</span>
     <span class="name">floodFill</span>(<span class="name">column</span>, <span class="name">row</span>, -<span class="number">1</span>);
     <span class="keyword">if</span> (<span class="name">fillFound</span> <span class="operator">&lt;=</span> <span class="number">0</span>)
         <span class="keyword">return</span>;
     <span class="name">gameCanvas</span>.<span class="name">score</span> <span class="operator">+=</span> (<span class="name">fillFound</span> <span class="operator">-</span> <span class="number">1</span>) <span class="operator">*</span> (<span class="name">fillFound</span> <span class="operator">-</span> <span class="number">1</span>);
     <span class="name">shuffleDown</span>();
     <span class="name">victoryCheck</span>();
 }</pre>
<p>Note that if <tt>score</tt> was a global variable in the <tt>samegame.js</tt> 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>Updating the score</h4>
<p>When the player clicks a block and triggers <tt>handleClick()</tt>, <tt>handleClick()</tt> also calls <tt>victoryCheck()</tt> to update the score and to check whether the player has completed the game. Here is the <tt>victoryCheck()</tt> code:</p>
<pre class="js"> <span class="keyword">function</span> <span class="name">victoryCheck</span>() {
     <span class="comment">//Award bonus points if no blocks left</span>
     var <span class="name">deservesBonus</span> = <span class="number">true</span>;
     <span class="keyword">for</span> (<span class="keyword">var</span> <span class="name">column</span> = <span class="name">maxColumn</span> <span class="operator">-</span> <span class="number">1</span>; <span class="name">column</span> <span class="operator">&gt;=</span> <span class="number">0</span>; column--)
         <span class="keyword">if</span> (<span class="name">board</span>[<span class="name">index</span>(<span class="name">column</span>, <span class="name">maxRow</span> <span class="operator">-</span> <span class="number">1</span>)] <span class="operator">!=</span> <span class="number">null</span>)
         <span class="name">deservesBonus</span> <span class="operator">=</span> <span class="number">false</span>;
     <span class="keyword">if</span> (<span class="name">deservesBonus</span>)
         <span class="name">gameCanvas</span>.<span class="name">score</span> <span class="operator">+=</span> <span class="number">500</span>;

     <span class="comment">//Check whether game has finished</span>
     <span class="keyword">if</span> (<span class="name">deservesBonus</span> <span class="operator">||</span> !(<span class="name">floodMoveCheck</span>(<span class="number">0</span>, <span class="name">maxRow</span> <span class="operator">-</span> <span class="number">1</span>, -<span class="number">1</span>)))
         <span class="name">dialog</span>.<span class="name">show</span>(<span class="string">&quot;Game Over. Your score is &quot;</span> <span class="operator">+</span> <span class="name">gameCanvas</span>.<span class="name">score</span>);
 }</pre>
<p>This updates the <tt>gameCanvas.score</tt> value and displays a &quot;Game Over&quot; dialog if the game is finished.</p>
<p>The Game Over dialog is created using a <tt>Dialog</tt> element that is defined in <tt>Dialog.qml</tt>. Here is the <tt>Dialog.qml</tt> 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 1.0

 <span class="type"><a href="qml-rectangle.html">Rectangle</a></span> {
     <span class="name">id</span>: <span class="name">container</span>

     <span class="keyword">function</span> <span class="name">show</span>(<span class="name">text</span>) {
         <span class="name">dialogText</span>.<span class="name">text</span> <span class="operator">=</span> <span class="name">text</span>;
         <span class="name">container</span>.<span class="name">opacity</span> <span class="operator">=</span> <span class="number">1</span>;
     }

     <span class="keyword">function</span> <span class="name">hide</span>() {
         <span class="name">container</span>.<span class="name">opacity</span> <span class="operator">=</span> <span class="number">0</span>;
     }

     <span class="name">width</span>: <span class="name">dialogText</span>.<span class="name">width</span> <span class="operator">+</span> <span class="number">20</span>
     <span class="name">height</span>: <span class="name">dialogText</span>.<span class="name">height</span> <span class="operator">+</span> <span class="number">20</span>
     <span class="name">opacity</span>: <span class="number">0</span>

     <span class="type"><a href="qml-text.html">Text</a></span> {
         <span class="name">id</span>: <span class="name">dialogText</span>
         <span class="name">anchors</span>.centerIn: <span class="name">parent</span>
         <span class="name">text</span>: <span class="string">&quot;&quot;</span>
     }

     <span class="type"><a href="qml-mousearea.html">MouseArea</a></span> {
         <span class="name">anchors</span>.fill: <span class="name">parent</span>
         <span class="name">onClicked</span>: <span class="name">hide</span>();
     }
 }</pre>
<p>And this is how it is used in the main <tt>samegame.qml</tt> file:</p>
<pre class="qml">     <span class="type">Dialog</span> {
         <span class="name">id</span>: <span class="name">dialog</span>
         <span class="name">anchors</span>.centerIn: <span class="name">parent</span>
         <span class="name">z</span>: <span class="number">100</span>
     }</pre>
<p>We give the dialog a <a href="qml-item.html#z-prop">z</a> value of 100 to ensure it is displayed on top of our other components. The default <tt>z</tt> value for an item is 0.</p>
<a name="a-dash-of-color"></a>
<h4>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 <tt>createBlock()</tt> function in <tt>samegame.js</tt> to randomly create a different type of block (for either red, green or blue) each time it is called. <tt>Block.qml</tt> has also changed so that each block contains a different image depending on its type:</p>
<pre class="qml"> import QtQuick 1.0

 <span class="type"><a href="qml-item.html">Item</a></span> {
     <span class="name">id</span>: <span class="name">block</span>

     property <span class="type">int</span> <span class="name">type</span>: <span class="number">0</span>

     <span class="type"><a href="qml-image.html">Image</a></span> {
         <span class="name">id</span>: <span class="name">img</span>

         <span class="name">anchors</span>.fill: <span class="name">parent</span>
         <span class="name">source</span>: {
             <span class="keyword">if</span> (<span class="name">type</span> <span class="operator">==</span> <span class="number">0</span>)
                 <span class="keyword">return</span> <span class="string">&quot;../shared/pics/redStone.png&quot;</span>;
             else <span class="keyword">if</span> (<span class="name">type</span> <span class="operator">==</span> <span class="number">1</span>)
                 <span class="keyword">return</span> <span class="string">&quot;../shared/pics/blueStone.png&quot;</span>;
             else
                 <span class="keyword">return</span> <span class="string">&quot;../shared/pics/greenStone.png&quot;</span>;
         }
     }
 }</pre>
<a name="a-working-game"></a>
<h3>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 <tt>samegame.qml</tt> looks like now:</p>
<pre class="qml"> import QtQuick 1.0
 import &quot;samegame.js&quot; as SameGame

 <span class="type"><a href="qml-rectangle.html">Rectangle</a></span> {
     <span class="name">id</span>: <span class="name">screen</span>

     <span class="name">width</span>: <span class="number">490</span>; <span class="name">height</span>: <span class="number">720</span>

     <span class="type"><a href="qml-systempalette.html">SystemPalette</a></span> { <span class="name">id</span>: <span class="name">activePalette</span> }

     <span class="type"><a href="qml-item.html">Item</a></span> {
         <span class="name">width</span>: <span class="name">parent</span>.<span class="name">width</span>
         <span class="type">anchors</span> { <span class="name">top</span>: <span class="name">parent</span>.<span class="name">top</span>; <span class="name">bottom</span>: <span class="name">toolBar</span>.<span class="name">top</span> }

         <span class="type"><a href="qml-image.html">Image</a></span> {
             <span class="name">id</span>: <span class="name">background</span>
             <span class="name">anchors</span>.fill: <span class="name">parent</span>
             <span class="name">source</span>: <span class="string">&quot;../shared/pics/background.jpg&quot;</span>
             <span class="name">fillMode</span>: <span class="name">Image</span>.<span class="name">PreserveAspectCrop</span>
         }

         <span class="type"><a href="qml-item.html">Item</a></span> {
             <span class="name">id</span>: <span class="name">gameCanvas</span>

             property <span class="type">int</span> <span class="name">score</span>: <span class="number">0</span>
             property <span class="type">int</span> <span class="name">blockSize</span>: <span class="number">40</span>

             <span class="name">width</span>: <span class="name">parent</span>.<span class="name">width</span> <span class="operator">-</span> (<span class="name">parent</span>.<span class="name">width</span> <span class="operator">%</span> <span class="name">blockSize</span>)
             <span class="name">height</span>: <span class="name">parent</span>.<span class="name">height</span> <span class="operator">-</span> (<span class="name">parent</span>.<span class="name">height</span> <span class="operator">%</span> <span class="name">blockSize</span>)
             <span class="name">anchors</span>.centerIn: <span class="name">parent</span>

             <span class="type"><a href="qml-mousearea.html">MouseArea</a></span> {
                 <span class="name">anchors</span>.fill: <span class="name">parent</span>
                 <span class="name">onClicked</span>: <span class="name">SameGame</span>.<span class="name">handleClick</span>(<span class="name">mouse</span>.<span class="name">x</span>, <span class="name">mouse</span>.<span class="name">y</span>)
             }
         }
     }

     <span class="type">Dialog</span> {
         <span class="name">id</span>: <span class="name">dialog</span>
         <span class="name">anchors</span>.centerIn: <span class="name">parent</span>
         <span class="name">z</span>: <span class="number">100</span>
     }

     <span class="type"><a href="qml-rectangle.html">Rectangle</a></span> {
         <span class="name">id</span>: <span class="name">toolBar</span>
         <span class="name">width</span>: <span class="name">parent</span>.<span class="name">width</span>; <span class="name">height</span>: <span class="number">30</span>
         <span class="name">color</span>: <span class="name">activePalette</span>.<span class="name">window</span>
         <span class="name">anchors</span>.bottom: <span class="name">screen</span>.<span class="name">bottom</span>

         <span class="type">Button</span> {
             <span class="type">anchors</span> { <span class="name">left</span>: <span class="name">parent</span>.<span class="name">left</span>; <span class="name">verticalCenter</span>: <span class="name">parent</span>.<span class="name">verticalCenter</span> }
             <span class="name">text</span>: <span class="string">&quot;New Game&quot;</span>
             <span class="name">onClicked</span>: <span class="name">SameGame</span>.<span class="name">startNewGame</span>()
         }

         <span class="type"><a href="qml-text.html">Text</a></span> {
             <span class="name">id</span>: <span class="name">score</span>
             <span class="type">anchors</span> { <span class="name">right</span>: <span class="name">parent</span>.<span class="name">right</span>; <span class="name">verticalCenter</span>: <span class="name">parent</span>.<span class="name">verticalCenter</span> }
             <span class="name">text</span>: <span class="string">&quot;Score: Who knows?&quot;</span>
         }
     }
 }</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>
</div>
<!-- @@@declarative/tutorials/samegame/samegame3 -->
<p class="naviNextPrevious footerNavi">
<a class="prevPage" href="declarative-tutorials-samegame-samegame2.html">QML Advanced Tutorial 2 - Populating the Game Canvas</a>
<a class="nextPage" href="declarative-tutorials-samegame-samegame4.html">QML Advanced Tutorial 4 - Finishing Touches</a>
</p>
  <div class="ft">
    <span></span>
  </div>
</div> 
<div class="footer">
    <p>
      <acronym title="Copyright">&copy;</acronym> 2012 Nokia Corporation and/or its
      subsidiaries. Documentation contributions included herein are the copyrights of
      their respective owners.</p>
    <br />
    <p>
      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.</p>
    <p>
      Documentation sources may be obtained from <a href="http://www.qt-project.org">
      www.qt-project.org</a>.</p>
    <br />
    <p>
      Nokia, Qt and their respective logos are trademarks of Nokia Corporation 
      in Finland and/or other countries worldwide. All other trademarks are property
      of their respective owners. <a title="Privacy Policy"
      href="http://en.gitorious.org/privacy_policy/">Privacy Policy</a></p>
</div>
</body>
</html>