1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
---|
2 | <!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/doc/tutorial.doc:2032 -->
|
---|
3 | <html>
|
---|
4 | <head>
|
---|
5 | <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
---|
6 | <title>Qt Tutorial - Chapter 13: Game Over</title>
|
---|
7 | <style type="text/css"><!--
|
---|
8 | fn { margin-left: 1cm; text-indent: -1cm; }
|
---|
9 | a:link { color: #004faf; text-decoration: none }
|
---|
10 | a:visited { color: #672967; text-decoration: none }
|
---|
11 | body { background: #ffffff; color: black; }
|
---|
12 | --></style>
|
---|
13 | </head>
|
---|
14 | <body>
|
---|
15 |
|
---|
16 | <table border="0" cellpadding="0" cellspacing="0" width="100%">
|
---|
17 | <tr bgcolor="#E5E5E5">
|
---|
18 | <td valign=center>
|
---|
19 | <a href="index.html">
|
---|
20 | <font color="#004faf">Home</font></a>
|
---|
21 | | <a href="classes.html">
|
---|
22 | <font color="#004faf">All Classes</font></a>
|
---|
23 | | <a href="mainclasses.html">
|
---|
24 | <font color="#004faf">Main Classes</font></a>
|
---|
25 | | <a href="annotated.html">
|
---|
26 | <font color="#004faf">Annotated</font></a>
|
---|
27 | | <a href="groups.html">
|
---|
28 | <font color="#004faf">Grouped Classes</font></a>
|
---|
29 | | <a href="functions.html">
|
---|
30 | <font color="#004faf">Functions</font></a>
|
---|
31 | </td>
|
---|
32 | <td align="right" valign="center"><img src="logo32.png" align="right" width="64" height="32" border="0"></td></tr></table><h1 align=center>Qt Tutorial - Chapter 13: Game Over</h1>
|
---|
33 |
|
---|
34 |
|
---|
35 | <p> <center><img src="t13.png" alt="Screenshot of tutorial thirteen"></center>
|
---|
36 | <p> In this example we start to approach a real playable game with a
|
---|
37 | score. We give MyWidget a new name (GameBoard) and add some slots.
|
---|
38 | <p> We put the definition in gamebrd.h and the implementation in gamebrd.cpp.
|
---|
39 | <p> The CannonField now has a game over state.
|
---|
40 | <p> The layout problems in LCDRange are fixed.
|
---|
41 | <p> <ul>
|
---|
42 | <li> <a href="t13-lcdrange-h.html">t13/lcdrange.h</a> contains the LCDRange
|
---|
43 | class definition.
|
---|
44 | <li> <a href="t13-lcdrange-cpp.html">t13/lcdrange.cpp</a> contains the LCDRange
|
---|
45 | implementation.
|
---|
46 | <li> <a href="t13-cannon-h.html">t13/cannon.h</a> contains the CannonField class
|
---|
47 | definition
|
---|
48 | <li> <a href="t13-cannon-cpp.html">t13/cannon.cpp</a> contains the CannonField
|
---|
49 | implementation.
|
---|
50 | <li> <a href="t13-gamebrd-h.html">t13/gamebrd.h</a> contains the GameBoard
|
---|
51 | class definition.
|
---|
52 | <li> <a href="t13-gamebrd-cpp.html">t13/gamebrd.cpp</a> contains the GameBoard
|
---|
53 | implementation.
|
---|
54 | <li> <a href="t13-main-cpp.html">t13/main.cpp</a> contains MyWidget and main.
|
---|
55 | </ul>
|
---|
56 | <p> <h2> Line-by-line Walkthrough
|
---|
57 | </h2>
|
---|
58 | <a name="1"></a><p> <h3> <a href="t13-lcdrange-h.html">t13/lcdrange.h</a>
|
---|
59 | </h3>
|
---|
60 | <a name="1-1"></a><p>
|
---|
61 |
|
---|
62 | <p> <pre> #include <<a href="qwidget-h.html">qwidget.h</a>>
|
---|
63 |
|
---|
64 | class QSlider;
|
---|
65 | class QLabel;
|
---|
66 |
|
---|
67 | class LCDRange : public <a href="qwidget.html">QWidget</a>
|
---|
68 | </pre>
|
---|
69 | <p> We inherit <a href="qwidget.html">QWidget</a> rather than <a href="qvbox.html">QVBox</a>. QVBox is very easy to use, but
|
---|
70 | again it showed its limitations so we switch to the more powerful and
|
---|
71 | slightly harder to use <a href="qvboxlayout.html">QVBoxLayout</a>. (As you remember, QVBoxLayout is
|
---|
72 | not a widget, it manages one.)
|
---|
73 | <p> <h3> <a href="t13-lcdrange-cpp.html">t13/lcdrange.cpp</a>
|
---|
74 | </h3>
|
---|
75 | <a name="1-2"></a><p>
|
---|
76 |
|
---|
77 | <p> <pre> #include <<a href="qlayout-h.html">qlayout.h</a>>
|
---|
78 | </pre>
|
---|
79 | <p> We need to include qlayout.h now to get the other layout management
|
---|
80 | API.
|
---|
81 | <p> <pre> LCDRange::LCDRange( <a href="qwidget.html">QWidget</a> *parent, const char *name )
|
---|
82 | : <a href="qwidget.html">QWidget</a>( parent, name )
|
---|
83 | </pre>
|
---|
84 | <p> We inherit QWidget in the usual way.
|
---|
85 | <p> The other constructor has the same change. init() is unchanged,
|
---|
86 | except that we've added some lines at the end:
|
---|
87 | <p> <pre> <a href="qvboxlayout.html">QVBoxLayout</a> * l = new <a href="qvboxlayout.html">QVBoxLayout</a>( this );
|
---|
88 | </pre>
|
---|
89 | <p> We create a QVBoxLayout with all the default values, managing this
|
---|
90 | widget's children.
|
---|
91 | <p> <pre> <a name="x2401"></a> l-><a href="qboxlayout.html#addWidget">addWidget</a>( lcd, 1 );
|
---|
92 | </pre>
|
---|
93 | <p> At the top we add the <a href="qlcdnumber.html">QLCDNumber</a> with a non-zero stretch.
|
---|
94 | <p> <pre> l-><a href="qboxlayout.html#addWidget">addWidget</a>( slider );
|
---|
95 | l-><a href="qboxlayout.html#addWidget">addWidget</a>( label );
|
---|
96 | </pre>
|
---|
97 | <p> Then we add the other two, both with the default zero stretch.
|
---|
98 | <p> This stretch control is something <a href="qvboxlayout.html">QVBoxLayout</a> (and <a href="qhboxlayout.html">QHBoxLayout</a>, and
|
---|
99 | <a href="qgridlayout.html">QGridLayout</a>) offers but classes like <a href="qvbox.html">QVBox</a> do not. In this case
|
---|
100 | we're saying that the QLCDNumber should stretch and the others should
|
---|
101 | not.
|
---|
102 | <p> <h3> <a href="t13-cannon-h.html">t13/cannon.h</a>
|
---|
103 | </h3>
|
---|
104 | <a name="1-3"></a><p> The CannonField now has a game over state and a few new functions.
|
---|
105 | <p>
|
---|
106 |
|
---|
107 | <p> <pre> bool gameOver() const { return gameEnded; }
|
---|
108 | </pre>
|
---|
109 | <p> This function returns TRUE if the game is over or FALSE if a game
|
---|
110 | is going on.
|
---|
111 | <p> <pre> void setGameOver();
|
---|
112 | void restartGame();
|
---|
113 | </pre>
|
---|
114 | <p> Here are two new slots: setGameOver() and restartGame().
|
---|
115 | <p> <pre> void canShoot( bool );
|
---|
116 | </pre>
|
---|
117 | <p> This new signal indicates that the CannonField is in a state where the
|
---|
118 | shoot() slot makes sense. We'll use it below to enable/disable the
|
---|
119 | Shoot button.
|
---|
120 | <p> <pre> bool gameEnded;
|
---|
121 | </pre>
|
---|
122 | <p> This private variable contains the game state. TRUE means that the
|
---|
123 | game is over, and FALSE means that a game is going on.
|
---|
124 | <p> <h3> <a href="t13-cannon-cpp.html">t13/cannon.cpp</a>
|
---|
125 | </h3>
|
---|
126 | <a name="1-4"></a><p>
|
---|
127 |
|
---|
128 | <p> <pre> gameEnded = FALSE;
|
---|
129 | </pre>
|
---|
130 | <p> This line has been added to the constructor. Initially, the game is not
|
---|
131 | over (luckily for the player :-).
|
---|
132 | <p> <pre> void CannonField::shoot()
|
---|
133 | {
|
---|
134 | if ( isShooting() )
|
---|
135 | return;
|
---|
136 | timerCount = 0;
|
---|
137 | shoot_ang = ang;
|
---|
138 | shoot_f = f;
|
---|
139 | <a name="x2407"></a> autoShootTimer-><a href="qtimer.html#start">start</a>( 50 );
|
---|
140 | emit canShoot( FALSE );
|
---|
141 | }
|
---|
142 | </pre>
|
---|
143 | <p> We added a new isShooting() function, so shoot() uses it instead of
|
---|
144 | testing directly. Also, shoot tells the world that the CannonField
|
---|
145 | cannot shoot now.
|
---|
146 | <p> <pre> void CannonField::setGameOver()
|
---|
147 | {
|
---|
148 | if ( gameEnded )
|
---|
149 | return;
|
---|
150 | if ( isShooting() )
|
---|
151 | autoShootTimer-><a href="qtimer.html#stop">stop</a>();
|
---|
152 | gameEnded = TRUE;
|
---|
153 | <a href="qwidget.html#repaint">repaint</a>();
|
---|
154 | }
|
---|
155 | </pre>
|
---|
156 | <p> This slot ends the game. It must be called from outside CannonField,
|
---|
157 | because this widget does not know when to end the game. This is an
|
---|
158 | important design principle in component programming. We choose to
|
---|
159 | make the component as flexible as possible to make it usable with
|
---|
160 | different rules (for example, a multi-player version of this in which the
|
---|
161 | first player to hit ten times wins could use the CannonField unchanged).
|
---|
162 | <p> If the game has already been ended we return immediately. If a game is
|
---|
163 | going on we stop the shot, set the game over flag, and repaint the entire
|
---|
164 | widget.
|
---|
165 | <p> <pre> void CannonField::restartGame()
|
---|
166 | {
|
---|
167 | if ( isShooting() )
|
---|
168 | <a name="x2408"></a> autoShootTimer-><a href="qtimer.html#stop">stop</a>();
|
---|
169 | gameEnded = FALSE;
|
---|
170 | <a href="qwidget.html#repaint">repaint</a>();
|
---|
171 | emit canShoot( TRUE );
|
---|
172 | }
|
---|
173 | </pre>
|
---|
174 | <p> This slot starts a new game. If a shot is in the air, we stop shooting.
|
---|
175 | We then reset the <tt>gameEnded</tt> variable and repaint the widget.
|
---|
176 | <p> moveShot() too emits the new canShoot(TRUE) signal at the same time as
|
---|
177 | either hit() or miss().
|
---|
178 | <p> Modifications in CannonField::paintEvent():
|
---|
179 | <p> <pre> void CannonField::<a href="qwidget.html#paintEvent">paintEvent</a>( <a href="qpaintevent.html">QPaintEvent</a> *e )
|
---|
180 | {
|
---|
181 | <a name="x2405"></a> <a href="qrect.html">QRect</a> updateR = e-><a href="qpaintevent.html#rect">rect</a>();
|
---|
182 | <a href="qpainter.html">QPainter</a> p( this );
|
---|
183 |
|
---|
184 | if ( gameEnded ) {
|
---|
185 | p.<a href="qpainter.html#setPen">setPen</a>( black );
|
---|
186 | <a name="x2403"></a> p.<a href="qpainter.html#setFont">setFont</a>( QFont( "Courier", 48, QFont::Bold ) );
|
---|
187 | p.<a href="qpainter.html#drawText">drawText</a>( <a href="qwidget.html#rect">rect</a>(), AlignCenter, "Game Over" );
|
---|
188 | }
|
---|
189 | </pre>
|
---|
190 | <p> The paint event has been enhanced to display the text "Game Over" if
|
---|
191 | the game is over, i.e., <tt>gameEnded</tt> is TRUE. We don't bother to
|
---|
192 | check the update rectangle here because speed is not critical when
|
---|
193 | the game is over.
|
---|
194 | <p> To draw the text we first set a black pen; the pen color is used
|
---|
195 | when drawing text. Next we choose a 48 point bold font from the
|
---|
196 | Courier family. Finally we draw the text centered in the widget's
|
---|
197 | rectangle. Unfortunately, on some systems (especially X servers with
|
---|
198 | Unicode fonts) it can take a while to load such a large font. Because
|
---|
199 | Qt caches fonts, you will notice this only the first time the font is
|
---|
200 | used.
|
---|
201 | <p> <pre> <a name="x2406"></a> if ( updateR.<a href="qrect.html#intersects">intersects</a>( cannonRect() ) )
|
---|
202 | paintCannon( &p );
|
---|
203 | if ( isShooting() && updateR.<a href="qrect.html#intersects">intersects</a>( shotRect() ) )
|
---|
204 | paintShot( &p );
|
---|
205 | if ( !gameEnded && updateR.<a href="qrect.html#intersects">intersects</a>( targetRect() ) )
|
---|
206 | paintTarget( &p );
|
---|
207 | }
|
---|
208 | </pre>
|
---|
209 | <p> We draw the shot only when shooting and the target only when playing
|
---|
210 | (that is, when the game is not ended).
|
---|
211 | <p> <h3> <a href="t13-gamebrd-h.html">t13/gamebrd.h</a>
|
---|
212 | </h3>
|
---|
213 | <a name="1-5"></a><p> This file is new. It contains the definition of the GameBoard class,
|
---|
214 | which was last seen as MyWidget.
|
---|
215 | <p>
|
---|
216 |
|
---|
217 | <p> <pre> class QPushButton;
|
---|
218 | class LCDRange;
|
---|
219 | class QLCDNumber;
|
---|
220 | class CannonField;
|
---|
221 |
|
---|
222 | #include "lcdrange.h"
|
---|
223 | #include "cannon.h"
|
---|
224 |
|
---|
225 | class GameBoard : public <a href="qwidget.html">QWidget</a>
|
---|
226 | {
|
---|
227 | <a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a>
|
---|
228 | public:
|
---|
229 | GameBoard( <a href="qwidget.html">QWidget</a> *parent=0, const char *name=0 );
|
---|
230 |
|
---|
231 | protected slots:
|
---|
232 | void fire();
|
---|
233 | void hit();
|
---|
234 | void missed();
|
---|
235 | void newGame();
|
---|
236 |
|
---|
237 | private:
|
---|
238 | <a href="qlcdnumber.html">QLCDNumber</a> *hits;
|
---|
239 | <a href="qlcdnumber.html">QLCDNumber</a> *shotsLeft;
|
---|
240 | CannonField *cannonField;
|
---|
241 | };
|
---|
242 | </pre>
|
---|
243 | <p> We have now added four slots. These are protected and are used internally.
|
---|
244 | We have also added two QLCDNumbers (<tt>hits</tt> and <tt>shotsLeft</tt>) which display
|
---|
245 | the game status.
|
---|
246 | <p> <h3> <a href="t13-gamebrd-cpp.html">t13/gamebrd.cpp</a>
|
---|
247 | </h3>
|
---|
248 | <a name="1-6"></a><p> This file is new. It contains the implementation of the GameBoard
|
---|
249 | class, which was last seen as MyWidget.
|
---|
250 | <p>
|
---|
251 |
|
---|
252 | <p> We have made some changes in the GameBoard constructor.
|
---|
253 | <p> <pre> cannonField = new CannonField( this, "cannonField" );
|
---|
254 | </pre>
|
---|
255 | <p> <tt>cannonField</tt> is now a member variable, so we carefully change the
|
---|
256 | constructor to use it. (The <em>good</em> programmers at Trolltech never
|
---|
257 | forget this, but I do. Caveat programmor - if "programmor" is Latin,
|
---|
258 | at least. Anyway, back to the code.)
|
---|
259 | <p> <pre> <a href="qobject.html#connect">connect</a>( cannonField, SIGNAL(hit()),
|
---|
260 | this, SLOT(hit()) );
|
---|
261 | <a href="qobject.html#connect">connect</a>( cannonField, SIGNAL(missed()),
|
---|
262 | this, SLOT(missed()) );
|
---|
263 | </pre>
|
---|
264 | <p> This time we want to do something when the shot has hit or missed the
|
---|
265 | target. Thus we connect the hit() and missed() signals of the
|
---|
266 | CannonField to two protected slots with the same names in this class.
|
---|
267 | <p> <pre> <a href="qobject.html#connect">connect</a>( shoot, SIGNAL(<a href="qbutton.html#clicked">clicked</a>()), SLOT(fire()) );
|
---|
268 | </pre>
|
---|
269 | <p> Previously we connected the Shoot button's clicked() signal directly
|
---|
270 | to the CannonField's shoot() slot. This time we want to keep track of
|
---|
271 | the number of shots fired, so we connect it to a protected slot in
|
---|
272 | this class instead.
|
---|
273 | <p> Notice how easy it is to change the behavior of a program when you are
|
---|
274 | working with self-contained components.
|
---|
275 | <p> <pre> <a href="qobject.html#connect">connect</a>( cannonField, SIGNAL(canShoot(bool)),
|
---|
276 | <a name="x2416"></a> shoot, SLOT(<a href="qwidget.html#setEnabled">setEnabled</a>(bool)) );
|
---|
277 | </pre>
|
---|
278 | <p> We also use the cannonField's canShoot() signal to enable or disable
|
---|
279 | the Shoot button appropriately.
|
---|
280 | <p> <pre> QPushButton *restart
|
---|
281 | = new <a href="qpushbutton.html">QPushButton</a>( "&New Game", this, "newgame" );
|
---|
282 | restart->setFont( QFont( "Times", 18, QFont::Bold ) );
|
---|
283 |
|
---|
284 | <a href="qobject.html#connect">connect</a>( restart, SIGNAL(clicked()), this, SLOT(newGame()) );
|
---|
285 | </pre>
|
---|
286 | <p> We create, set up, and connect the New Game button as we have done
|
---|
287 | with the other buttons. Clicking this button will activate the
|
---|
288 | newGame() slot in this widget.
|
---|
289 | <p> <pre> hits = new <a href="qlcdnumber.html">QLCDNumber</a>( 2, this, "hits" );
|
---|
290 | shotsLeft = new <a href="qlcdnumber.html">QLCDNumber</a>( 2, this, "shotsleft" );
|
---|
291 | <a href="qlabel.html">QLabel</a> *hitsL = new <a href="qlabel.html">QLabel</a>( "HITS", this, "hitsLabel" );
|
---|
292 | QLabel *shotsLeftL
|
---|
293 | = new <a href="qlabel.html">QLabel</a>( "SHOTS LEFT", this, "shotsleftLabel" );
|
---|
294 | </pre>
|
---|
295 | <p> We create four new widgets. Note that we don't bother to keep the
|
---|
296 | pointers to the <a href="qlabel.html">QLabel</a> widgets in the GameBoard class because there's
|
---|
297 | nothing much we want to do with them. Qt will delete them when the
|
---|
298 | GameBoard widget is destroyed, and the layout classes will resize them
|
---|
299 | appropriately.
|
---|
300 | <p> <pre> <a href="qhboxlayout.html">QHBoxLayout</a> *topBox = new <a href="qhboxlayout.html">QHBoxLayout</a>;
|
---|
301 | <a name="x2413"></a> grid-><a href="qgridlayout.html#addLayout">addLayout</a>( topBox, 0, 1 );
|
---|
302 | topBox-><a href="qboxlayout.html#addWidget">addWidget</a>( shoot );
|
---|
303 | topBox-><a href="qboxlayout.html#addWidget">addWidget</a>( hits );
|
---|
304 | topBox-><a href="qboxlayout.html#addWidget">addWidget</a>( hitsL );
|
---|
305 | topBox-><a href="qboxlayout.html#addWidget">addWidget</a>( shotsLeft );
|
---|
306 | topBox-><a href="qboxlayout.html#addWidget">addWidget</a>( shotsLeftL );
|
---|
307 | <a name="x2410"></a> topBox-><a href="qboxlayout.html#addStretch">addStretch</a>( 1 );
|
---|
308 | <a name="x2411"></a> topBox-><a href="qboxlayout.html#addWidget">addWidget</a>( restart );
|
---|
309 | </pre>
|
---|
310 | <p> The number of widgets in the top-right cell is getting large. Once it
|
---|
311 | was empty; now it's full enough that we group together the layout
|
---|
312 | setting for better overview.
|
---|
313 | <p> Notice that we let all the widgets have their preferred sizes, instead
|
---|
314 | putting the stretch just to the left of the New Game button.
|
---|
315 | <p> <pre> newGame();
|
---|
316 | }
|
---|
317 | </pre>
|
---|
318 | <p> We're all done constructing the GameBoard, so we start it all using
|
---|
319 | newGame(). (NewGame() is a slot, but as we said, slots can be used as
|
---|
320 | ordinary functions, too.)
|
---|
321 | <p> <pre> void GameBoard::fire()
|
---|
322 | {
|
---|
323 | if ( cannonField->gameOver() || cannonField->isShooting() )
|
---|
324 | return;
|
---|
325 | shotsLeft-><a href="qlcdnumber.html#display">display</a>( shotsLeft-><a href="qlcdnumber.html#intValue">intValue</a>() - 1 );
|
---|
326 | cannonField->shoot();
|
---|
327 | }
|
---|
328 | </pre>
|
---|
329 | <p> This function fires a shot. If the game is over or if there is a shot in the
|
---|
330 | air, we return immediately. We decrement the number of shots left and tell
|
---|
331 | the cannon to shoot.
|
---|
332 | <p> <pre> void GameBoard::hit()
|
---|
333 | {
|
---|
334 | hits-><a href="qlcdnumber.html#display">display</a>( hits-><a href="qlcdnumber.html#intValue">intValue</a>() + 1 );
|
---|
335 | if ( shotsLeft-><a href="qlcdnumber.html#intValue">intValue</a>() == 0 )
|
---|
336 | cannonField->setGameOver();
|
---|
337 | else
|
---|
338 | cannonField->newTarget();
|
---|
339 | }
|
---|
340 | </pre>
|
---|
341 | <p> This slot is activated when a shot has hit the target. We increment the
|
---|
342 | number of hits. If there are no shots left, the game is over. Otherwise,
|
---|
343 | we make the CannonField generate a new target.
|
---|
344 | <p> <pre> void GameBoard::missed()
|
---|
345 | {
|
---|
346 | <a name="x2415"></a> if ( shotsLeft-><a href="qlcdnumber.html#intValue">intValue</a>() == 0 )
|
---|
347 | cannonField->setGameOver();
|
---|
348 | }
|
---|
349 | </pre>
|
---|
350 | <p> This slot is activated when a shot has missed the target. If there are no
|
---|
351 | shots left, the game is over.
|
---|
352 | <p> <pre> void GameBoard::newGame()
|
---|
353 | {
|
---|
354 | <a name="x2414"></a> shotsLeft-><a href="qlcdnumber.html#display">display</a>( 15 );
|
---|
355 | hits-><a href="qlcdnumber.html#display">display</a>( 0 );
|
---|
356 | cannonField->restartGame();
|
---|
357 | cannonField->newTarget();
|
---|
358 | }
|
---|
359 | </pre>
|
---|
360 | <p> This slot is activated when the user clicks the Restart button. It is
|
---|
361 | also called from the constructor. First it sets the number of shots
|
---|
362 | to 15. Note that this is the only place in the program where we set
|
---|
363 | the number of shots. Change it to whatever you like to change the
|
---|
364 | game rules. Next we reset the number of hits, restart the game, and
|
---|
365 | generate a new target.
|
---|
366 | <p> <h3> <a href="t13-main-cpp.html">t13/main.cpp</a>
|
---|
367 | </h3>
|
---|
368 | <a name="1-7"></a><p> This file has just been on a diet. MyWidget is gone, and the only
|
---|
369 | thing left is the main() function, unchanged except for the name
|
---|
370 | change.
|
---|
371 | <p> <h2> Behavior
|
---|
372 | </h2>
|
---|
373 | <a name="2"></a><p> The cannon can shoot at a target; a new target is automatically created
|
---|
374 | when one has been hit.
|
---|
375 | <p> Hits and shots left are displayed and the program keeps track of them.
|
---|
376 | The game can end, and there's a button to start a new game.
|
---|
377 | <p> (See <a href="tutorial1-07.html#compiling">Compiling</a> for how to create a
|
---|
378 | makefile and build the application.)
|
---|
379 | <p> <h2> Exercises
|
---|
380 | </h2>
|
---|
381 | <a name="3"></a><p> Add a random wind factor and show it to the user.
|
---|
382 | <p> Make some splatter effects when the shot hits the target.
|
---|
383 | <p> Implement multiple targets.
|
---|
384 | <p> You're now ready for <a href="tutorial1-14.html">Chapter 14.</a>
|
---|
385 | <p> [<a href="tutorial1-12.html">Previous tutorial</a>]
|
---|
386 | [<a href="tutorial1-14.html">Next tutorial</a>]
|
---|
387 | [<a href="tutorial.html">Main tutorial page</a>]
|
---|
388 | <p>
|
---|
389 | <!-- eof -->
|
---|
390 | <p><address><hr><div align=center>
|
---|
391 | <table width=100% cellspacing=0 border=0><tr>
|
---|
392 | <td>Copyright © 2007
|
---|
393 | <a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
|
---|
394 | <td align=right><div align=right>Qt 3.3.8</div>
|
---|
395 | </table></div></address></body>
|
---|
396 | </html>
|
---|