summaryrefslogtreecommitdiffstats
path: root/doc/html/tutorial1-13.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/html/tutorial1-13.html')
-rw-r--r--doc/html/tutorial1-13.html396
1 files changed, 396 insertions, 0 deletions
diff --git a/doc/html/tutorial1-13.html b/doc/html/tutorial1-13.html
new file mode 100644
index 0000000..d2d9da3
--- /dev/null
+++ b/doc/html/tutorial1-13.html
@@ -0,0 +1,396 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/doc/tutorial.doc:2032 -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>Qt Tutorial - Chapter 13: Game Over</title>
+<style type="text/css"><!--
+fn { margin-left: 1cm; text-indent: -1cm; }
+a:link { color: #004faf; text-decoration: none }
+a:visited { color: #672967; text-decoration: none }
+body { background: #ffffff; color: black; }
+--></style>
+</head>
+<body>
+
+<table border="0" cellpadding="0" cellspacing="0" width="100%">
+<tr bgcolor="#E5E5E5">
+<td valign=center>
+ <a href="index.html">
+<font color="#004faf">Home</font></a>
+ | <a href="classes.html">
+<font color="#004faf">All&nbsp;Classes</font></a>
+ | <a href="mainclasses.html">
+<font color="#004faf">Main&nbsp;Classes</font></a>
+ | <a href="annotated.html">
+<font color="#004faf">Annotated</font></a>
+ | <a href="groups.html">
+<font color="#004faf">Grouped&nbsp;Classes</font></a>
+ | <a href="functions.html">
+<font color="#004faf">Functions</font></a>
+</td>
+<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>
+
+
+<p> <center><img src="t13.png" alt="Screenshot of tutorial thirteen"></center>
+<p> In this example we start to approach a real playable game with a
+score. We give MyWidget a new name (GameBoard) and add some slots.
+<p> We put the definition in gamebrd.h and the implementation in gamebrd.cpp.
+<p> The CannonField now has a game over state.
+<p> The layout problems in LCDRange are fixed.
+<p> <ul>
+<li> <a href="t13-lcdrange-h.html">t13/lcdrange.h</a> contains the LCDRange
+class definition.
+<li> <a href="t13-lcdrange-cpp.html">t13/lcdrange.cpp</a> contains the LCDRange
+implementation.
+<li> <a href="t13-cannon-h.html">t13/cannon.h</a> contains the CannonField class
+definition
+<li> <a href="t13-cannon-cpp.html">t13/cannon.cpp</a> contains the CannonField
+implementation.
+<li> <a href="t13-gamebrd-h.html">t13/gamebrd.h</a> contains the GameBoard
+class definition.
+<li> <a href="t13-gamebrd-cpp.html">t13/gamebrd.cpp</a> contains the GameBoard
+implementation.
+<li> <a href="t13-main-cpp.html">t13/main.cpp</a> contains MyWidget and main.
+</ul>
+<p> <h2> Line-by-line Walkthrough
+</h2>
+<a name="1"></a><p> <h3> <a href="t13-lcdrange-h.html">t13/lcdrange.h</a>
+</h3>
+<a name="1-1"></a><p>
+
+<p> <pre> #include &lt;<a href="qwidget-h.html">qwidget.h</a>&gt;
+
+ class QSlider;
+ class QLabel;
+
+ class LCDRange : public <a href="qwidget.html">QWidget</a>
+</pre>
+<p> We inherit <a href="qwidget.html">QWidget</a> rather than <a href="qvbox.html">QVBox</a>. QVBox is very easy to use, but
+again it showed its limitations so we switch to the more powerful and
+slightly harder to use <a href="qvboxlayout.html">QVBoxLayout</a>. (As you remember, QVBoxLayout is
+not a widget, it manages one.)
+<p> <h3> <a href="t13-lcdrange-cpp.html">t13/lcdrange.cpp</a>
+</h3>
+<a name="1-2"></a><p>
+
+<p> <pre> #include &lt;<a href="qlayout-h.html">qlayout.h</a>&gt;
+</pre>
+<p> We need to include qlayout.h now to get the other layout management
+API.
+<p> <pre> LCDRange::LCDRange( <a href="qwidget.html">QWidget</a> *parent, const char *name )
+ : <a href="qwidget.html">QWidget</a>( parent, name )
+</pre>
+<p> We inherit QWidget in the usual way.
+<p> The other constructor has the same change. init() is unchanged,
+except that we've added some lines at the end:
+<p> <pre> <a href="qvboxlayout.html">QVBoxLayout</a> * l = new <a href="qvboxlayout.html">QVBoxLayout</a>( this );
+</pre>
+<p> We create a QVBoxLayout with all the default values, managing this
+widget's children.
+<p> <pre> <a name="x2401"></a> l-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( lcd, 1 );
+</pre>
+<p> At the top we add the <a href="qlcdnumber.html">QLCDNumber</a> with a non-zero stretch.
+<p> <pre> l-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( slider );
+ l-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( label );
+</pre>
+<p> Then we add the other two, both with the default zero stretch.
+<p> This stretch control is something <a href="qvboxlayout.html">QVBoxLayout</a> (and <a href="qhboxlayout.html">QHBoxLayout</a>, and
+<a href="qgridlayout.html">QGridLayout</a>) offers but classes like <a href="qvbox.html">QVBox</a> do not. In this case
+we're saying that the QLCDNumber should stretch and the others should
+not.
+<p> <h3> <a href="t13-cannon-h.html">t13/cannon.h</a>
+</h3>
+<a name="1-3"></a><p> The CannonField now has a game over state and a few new functions.
+<p>
+
+<p> <pre> bool gameOver() const { return gameEnded; }
+</pre>
+<p> This function returns TRUE if the game is over or FALSE if a game
+is going on.
+<p> <pre> void setGameOver();
+ void restartGame();
+</pre>
+<p> Here are two new slots: setGameOver() and restartGame().
+<p> <pre> void canShoot( bool );
+</pre>
+<p> This new signal indicates that the CannonField is in a state where the
+shoot() slot makes sense. We'll use it below to enable/disable the
+Shoot button.
+<p> <pre> bool gameEnded;
+</pre>
+<p> This private variable contains the game state. TRUE means that the
+game is over, and FALSE means that a game is going on.
+<p> <h3> <a href="t13-cannon-cpp.html">t13/cannon.cpp</a>
+</h3>
+<a name="1-4"></a><p>
+
+<p> <pre> gameEnded = FALSE;
+</pre>
+<p> This line has been added to the constructor. Initially, the game is not
+over (luckily for the player :-).
+<p> <pre> void CannonField::shoot()
+ {
+ if ( isShooting() )
+ return;
+ timerCount = 0;
+ shoot_ang = ang;
+ shoot_f = f;
+ <a name="x2407"></a> autoShootTimer-&gt;<a href="qtimer.html#start">start</a>( 50 );
+ emit canShoot( FALSE );
+ }
+</pre>
+<p> We added a new isShooting() function, so shoot() uses it instead of
+testing directly. Also, shoot tells the world that the CannonField
+cannot shoot now.
+<p> <pre> void CannonField::setGameOver()
+ {
+ if ( gameEnded )
+ return;
+ if ( isShooting() )
+ autoShootTimer-&gt;<a href="qtimer.html#stop">stop</a>();
+ gameEnded = TRUE;
+ <a href="qwidget.html#repaint">repaint</a>();
+ }
+</pre>
+<p> This slot ends the game. It must be called from outside CannonField,
+because this widget does not know when to end the game. This is an
+important design principle in component programming. We choose to
+make the component as flexible as possible to make it usable with
+different rules (for example, a multi-player version of this in which the
+first player to hit ten times wins could use the CannonField unchanged).
+<p> If the game has already been ended we return immediately. If a game is
+going on we stop the shot, set the game over flag, and repaint the entire
+widget.
+<p> <pre> void CannonField::restartGame()
+ {
+ if ( isShooting() )
+ <a name="x2408"></a> autoShootTimer-&gt;<a href="qtimer.html#stop">stop</a>();
+ gameEnded = FALSE;
+ <a href="qwidget.html#repaint">repaint</a>();
+ emit canShoot( TRUE );
+ }
+</pre>
+<p> This slot starts a new game. If a shot is in the air, we stop shooting.
+We then reset the <tt>gameEnded</tt> variable and repaint the widget.
+<p> moveShot() too emits the new canShoot(TRUE) signal at the same time as
+either hit() or miss().
+<p> Modifications in CannonField::paintEvent():
+<p> <pre> void CannonField::<a href="qwidget.html#paintEvent">paintEvent</a>( <a href="qpaintevent.html">QPaintEvent</a> *e )
+ {
+ <a name="x2405"></a> <a href="qrect.html">QRect</a> updateR = e-&gt;<a href="qpaintevent.html#rect">rect</a>();
+ <a href="qpainter.html">QPainter</a> p( this );
+
+ if ( gameEnded ) {
+ p.<a href="qpainter.html#setPen">setPen</a>( black );
+ <a name="x2403"></a> p.<a href="qpainter.html#setFont">setFont</a>( QFont( "Courier", 48, QFont::Bold ) );
+ p.<a href="qpainter.html#drawText">drawText</a>( <a href="qwidget.html#rect">rect</a>(), AlignCenter, "Game Over" );
+ }
+</pre>
+<p> The paint event has been enhanced to display the text "Game Over" if
+the game is over, i.e., <tt>gameEnded</tt> is TRUE. We don't bother to
+check the update rectangle here because speed is not critical when
+the game is over.
+<p> To draw the text we first set a black pen; the pen color is used
+when drawing text. Next we choose a 48 point bold font from the
+Courier family. Finally we draw the text centered in the widget's
+rectangle. Unfortunately, on some systems (especially X servers with
+Unicode fonts) it can take a while to load such a large font. Because
+Qt caches fonts, you will notice this only the first time the font is
+used.
+<p> <pre> <a name="x2406"></a> if ( updateR.<a href="qrect.html#intersects">intersects</a>( cannonRect() ) )
+ paintCannon( &amp;p );
+ if ( isShooting() &amp;&amp; updateR.<a href="qrect.html#intersects">intersects</a>( shotRect() ) )
+ paintShot( &amp;p );
+ if ( !gameEnded &amp;&amp; updateR.<a href="qrect.html#intersects">intersects</a>( targetRect() ) )
+ paintTarget( &amp;p );
+ }
+</pre>
+<p> We draw the shot only when shooting and the target only when playing
+(that is, when the game is not ended).
+<p> <h3> <a href="t13-gamebrd-h.html">t13/gamebrd.h</a>
+</h3>
+<a name="1-5"></a><p> This file is new. It contains the definition of the GameBoard class,
+which was last seen as MyWidget.
+<p>
+
+<p> <pre> class QPushButton;
+ class LCDRange;
+ class QLCDNumber;
+ class CannonField;
+
+ #include "lcdrange.h"
+ #include "cannon.h"
+
+ class GameBoard : public <a href="qwidget.html">QWidget</a>
+ {
+ <a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a>
+ public:
+ GameBoard( <a href="qwidget.html">QWidget</a> *parent=0, const char *name=0 );
+
+ protected slots:
+ void fire();
+ void hit();
+ void missed();
+ void newGame();
+
+ private:
+ <a href="qlcdnumber.html">QLCDNumber</a> *hits;
+ <a href="qlcdnumber.html">QLCDNumber</a> *shotsLeft;
+ CannonField *cannonField;
+ };
+</pre>
+<p> We have now added four slots. These are protected and are used internally.
+We have also added two QLCDNumbers (<tt>hits</tt> and <tt>shotsLeft</tt>) which display
+the game status.
+<p> <h3> <a href="t13-gamebrd-cpp.html">t13/gamebrd.cpp</a>
+</h3>
+<a name="1-6"></a><p> This file is new. It contains the implementation of the GameBoard
+class, which was last seen as MyWidget.
+<p>
+
+<p> We have made some changes in the GameBoard constructor.
+<p> <pre> cannonField = new CannonField( this, "cannonField" );
+</pre>
+<p> <tt>cannonField</tt> is now a member variable, so we carefully change the
+constructor to use it. (The <em>good</em> programmers at Trolltech never
+forget this, but I do. Caveat programmor - if "programmor" is Latin,
+at least. Anyway, back to the code.)
+<p> <pre> <a href="qobject.html#connect">connect</a>( cannonField, SIGNAL(hit()),
+ this, SLOT(hit()) );
+ <a href="qobject.html#connect">connect</a>( cannonField, SIGNAL(missed()),
+ this, SLOT(missed()) );
+</pre>
+<p> This time we want to do something when the shot has hit or missed the
+target. Thus we connect the hit() and missed() signals of the
+CannonField to two protected slots with the same names in this class.
+<p> <pre> <a href="qobject.html#connect">connect</a>( shoot, SIGNAL(<a href="qbutton.html#clicked">clicked</a>()), SLOT(fire()) );
+</pre>
+<p> Previously we connected the Shoot button's clicked() signal directly
+to the CannonField's shoot() slot. This time we want to keep track of
+the number of shots fired, so we connect it to a protected slot in
+this class instead.
+<p> Notice how easy it is to change the behavior of a program when you are
+working with self-contained components.
+<p> <pre> <a href="qobject.html#connect">connect</a>( cannonField, SIGNAL(canShoot(bool)),
+ <a name="x2416"></a> shoot, SLOT(<a href="qwidget.html#setEnabled">setEnabled</a>(bool)) );
+</pre>
+<p> We also use the cannonField's canShoot() signal to enable or disable
+the Shoot button appropriately.
+<p> <pre> QPushButton *restart
+ = new <a href="qpushbutton.html">QPushButton</a>( "&amp;New Game", this, "newgame" );
+ restart-&gt;setFont( QFont( "Times", 18, QFont::Bold ) );
+
+ <a href="qobject.html#connect">connect</a>( restart, SIGNAL(clicked()), this, SLOT(newGame()) );
+</pre>
+<p> We create, set up, and connect the New Game button as we have done
+with the other buttons. Clicking this button will activate the
+newGame() slot in this widget.
+<p> <pre> hits = new <a href="qlcdnumber.html">QLCDNumber</a>( 2, this, "hits" );
+ shotsLeft = new <a href="qlcdnumber.html">QLCDNumber</a>( 2, this, "shotsleft" );
+ <a href="qlabel.html">QLabel</a> *hitsL = new <a href="qlabel.html">QLabel</a>( "HITS", this, "hitsLabel" );
+ QLabel *shotsLeftL
+ = new <a href="qlabel.html">QLabel</a>( "SHOTS LEFT", this, "shotsleftLabel" );
+</pre>
+<p> We create four new widgets. Note that we don't bother to keep the
+pointers to the <a href="qlabel.html">QLabel</a> widgets in the GameBoard class because there's
+nothing much we want to do with them. Qt will delete them when the
+GameBoard widget is destroyed, and the layout classes will resize them
+appropriately.
+<p> <pre> <a href="qhboxlayout.html">QHBoxLayout</a> *topBox = new <a href="qhboxlayout.html">QHBoxLayout</a>;
+ <a name="x2413"></a> grid-&gt;<a href="qgridlayout.html#addLayout">addLayout</a>( topBox, 0, 1 );
+ topBox-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( shoot );
+ topBox-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( hits );
+ topBox-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( hitsL );
+ topBox-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( shotsLeft );
+ topBox-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( shotsLeftL );
+ <a name="x2410"></a> topBox-&gt;<a href="qboxlayout.html#addStretch">addStretch</a>( 1 );
+ <a name="x2411"></a> topBox-&gt;<a href="qboxlayout.html#addWidget">addWidget</a>( restart );
+</pre>
+<p> The number of widgets in the top-right cell is getting large. Once it
+was empty; now it's full enough that we group together the layout
+setting for better overview.
+<p> Notice that we let all the widgets have their preferred sizes, instead
+putting the stretch just to the left of the New Game button.
+<p> <pre> newGame();
+ }
+</pre>
+<p> We're all done constructing the GameBoard, so we start it all using
+newGame(). (NewGame() is a slot, but as we said, slots can be used as
+ordinary functions, too.)
+<p> <pre> void GameBoard::fire()
+ {
+ if ( cannonField-&gt;gameOver() || cannonField-&gt;isShooting() )
+ return;
+ shotsLeft-&gt;<a href="qlcdnumber.html#display">display</a>( shotsLeft-&gt;<a href="qlcdnumber.html#intValue">intValue</a>() - 1 );
+ cannonField-&gt;shoot();
+ }
+</pre>
+<p> This function fires a shot. If the game is over or if there is a shot in the
+air, we return immediately. We decrement the number of shots left and tell
+the cannon to shoot.
+<p> <pre> void GameBoard::hit()
+ {
+ hits-&gt;<a href="qlcdnumber.html#display">display</a>( hits-&gt;<a href="qlcdnumber.html#intValue">intValue</a>() + 1 );
+ if ( shotsLeft-&gt;<a href="qlcdnumber.html#intValue">intValue</a>() == 0 )
+ cannonField-&gt;setGameOver();
+ else
+ cannonField-&gt;newTarget();
+ }
+</pre>
+<p> This slot is activated when a shot has hit the target. We increment the
+number of hits. If there are no shots left, the game is over. Otherwise,
+we make the CannonField generate a new target.
+<p> <pre> void GameBoard::missed()
+ {
+ <a name="x2415"></a> if ( shotsLeft-&gt;<a href="qlcdnumber.html#intValue">intValue</a>() == 0 )
+ cannonField-&gt;setGameOver();
+ }
+</pre>
+<p> This slot is activated when a shot has missed the target. If there are no
+shots left, the game is over.
+<p> <pre> void GameBoard::newGame()
+ {
+ <a name="x2414"></a> shotsLeft-&gt;<a href="qlcdnumber.html#display">display</a>( 15 );
+ hits-&gt;<a href="qlcdnumber.html#display">display</a>( 0 );
+ cannonField-&gt;restartGame();
+ cannonField-&gt;newTarget();
+ }
+</pre>
+<p> This slot is activated when the user clicks the Restart button. It is
+also called from the constructor. First it sets the number of shots
+to 15. Note that this is the only place in the program where we set
+the number of shots. Change it to whatever you like to change the
+game rules. Next we reset the number of hits, restart the game, and
+generate a new target.
+<p> <h3> <a href="t13-main-cpp.html">t13/main.cpp</a>
+</h3>
+<a name="1-7"></a><p> This file has just been on a diet. MyWidget is gone, and the only
+thing left is the main() function, unchanged except for the name
+change.
+<p> <h2> Behavior
+</h2>
+<a name="2"></a><p> The cannon can shoot at a target; a new target is automatically created
+when one has been hit.
+<p> Hits and shots left are displayed and the program keeps track of them.
+The game can end, and there's a button to start a new game.
+<p> (See <a href="tutorial1-07.html#compiling">Compiling</a> for how to create a
+makefile and build the application.)
+<p> <h2> Exercises
+</h2>
+<a name="3"></a><p> Add a random wind factor and show it to the user.
+<p> Make some splatter effects when the shot hits the target.
+<p> Implement multiple targets.
+<p> You're now ready for <a href="tutorial1-14.html">Chapter 14.</a>
+<p> [<a href="tutorial1-12.html">Previous tutorial</a>]
+[<a href="tutorial1-14.html">Next tutorial</a>]
+[<a href="tutorial.html">Main tutorial page</a>]
+<p>
+<!-- eof -->
+<p><address><hr><div align=center>
+<table width=100% cellspacing=0 border=0><tr>
+<td>Copyright &copy; 2007
+<a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
+<td align=right><div align=right>Qt 3.3.8</div>
+</table></div></address></body>
+</html>