source: trunk/doc/src/examples/rogue.qdoc@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 9.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \example statemachine/rogue
44 \title Rogue Example
45
46 The Rogue example shows how to use the Qt state machine for event
47 handling.
48
49 \image rogue-example.png
50
51 This example implements a simple text based game. Do you see the
52 \c{@} in the screenshot? That's you, the rogue. The \c{#}
53 characters are walls, and the dots represent floor. In a real
54 game, other ASCII characters would represent all kinds of objects
55 and creatures, for instance, ancient dragons (\c{D}s) or food
56 rations (\c{%}s). But let's not get carried away. In this game,
57 the rogue is simply running around in an empty room.
58
59 The rogue is moved with the keypad (2, 4, 8, 6). That aside, we
60 have implemented a \c quit command that triggers if the player
61 types \c {q}. The player is then asked if he/she really wants to
62 quit.
63
64 Most games have commands that need more than one key press (we
65 think of consecutive presses, i.e., not of several keys being
66 pressed at the same time). In this game, only the \c quit command
67 falls under this category, but for the sake of argument, let's
68 imagine a fully-fledged game with a rich set of commands. If we
69 were to implement these by catching key events in
70 \l{QWidget::}{keyPressEvent()}, we would have to keep a lot of
71 class member variables to track the sequence of keys already typed
72 (or find some other way of deducing the current state of a
73 command). This can easily lead to spaghetti, which is--as we all
74 well know, I'm sure--unpleasant. With a state machine, on the
75 other hand, separate states can wait for a single key press, and
76 that makes our lives a lot simpler.
77
78 The example consists of two classes:
79
80 \list
81 \o \c Window draws the text display of the game and sets
82 up the state machine. The window also has a status bar
83 above the area in which the rouge moves.
84 \o \c MovementTransition is a transition that carries out
85 a single move of the rogue.
86 \endlist
87
88 Before we embark on a code walkthrough, it is necessary to take a
89 closer look at the design of the machine. Here is a state chart
90 that shows what we want to achieve:
91
92 \image rogue-statechart.png
93
94 The input state waits for a key press to start a new command.
95 When receiving a key it recognizes, it transitions to one of the
96 two commands of the game; though, as we will see, movement is
97 handled by the transition itself. The quit state waits for the
98 player to answer yes or no (by typing \c y or \c n) when asked
99 whether he/she really wants to quit the game.
100
101 The chart demonstrates how we use one state to wait for a single
102 key press. The press received may trigger one of the transitions
103 connected to the state.
104
105 \section1 Window Class Definition
106
107 The \c Window class is a widget that draws the text display of the
108 game. It also sets up the state machine, i.e., creates and
109 connects the states in the machine. It is the key events from this
110 widget that are used by the machine.
111
112 \snippet examples/statemachine/rogue/window.h 0
113
114 \c Direction specifies the direction in which the rogue is to
115 move. We use this in \c movePlayer(), which moves the rogue and
116 repaints the window. The game has a status line above the area in
117 which the rogue moves. The \c status property contains the text of
118 this line. We use a property because the QState class allows
119 setting any Qt \l{Qt's Property System}{property} when entered.
120 More on this later.
121
122 \snippet examples/statemachine/rogue/window.h 1
123
124 The \c map is an array with the characters that are currently
125 displayed. We set up the array in \c setupMap(), and update it
126 when the rogue is moved. \c pX and \c pY is the current position
127 of the rogue. \c WIDTH and \c HEIGHT are macros specifying the
128 dimensions of the map.
129
130 The \c paintEvent() function is left out of this walkthrough. We
131 also do not discuss other code that does not concern the state
132 machine (the \c setupMap(), \c status(), \c setStatus(), \c
133 movePlayer(), and \c sizeHint() functions). If you wish to take a
134 look at the code, click on the link for the \c window.cpp file at
135 the top of this page.
136
137 \section1 Window Class Implementation
138
139 Here is the constructor of \c Window:
140
141 \snippet examples/statemachine/rogue/window.cpp 0
142 \dots
143 \snippet examples/statemachine/rogue/window.cpp 1
144
145 The player starts off at position (5, 5). We then set up the map
146 and statemachine. Let's proceed with the \c buildMachine()
147 function:
148
149 \snippet examples/statemachine/rogue/window.cpp 2
150
151 We enter \c inputState when the machine is started and from the \c
152 quitState if the user wants to continue playing. We then set the
153 status to a helpful reminder of how to play the game.
154
155 First, the \c Movement transition is added to the input state.
156 This will enable the rogue to be moved with the keypad. Notice
157 that we don't set a target state for the movement transition. This
158 will cause the transition to be triggered (and the
159 \l{QAbstractTransition::}{onTransition()} function to be invoked),
160 but the machine will not leave the \c inputState. If we had set \c
161 inputState as the target state, we would first have left and then
162 entered the \c inputState again.
163
164 \snippet examples/statemachine/rogue/window.cpp 3
165
166 When we enter \c quitState, we update the status bar of the
167 window.
168
169 \c QKeyEventTransition is a utility class that removes the hassle
170 of implementing transitions for \l{QKeyEvent}s. We simply need to
171 specify the key on which the transition should trigger and the
172 target state of the transition.
173
174 \snippet examples/statemachine/rogue/window.cpp 4
175
176 The transition from \c inputState allows triggering the quit state
177 when the player types \c {q}.
178
179 \snippet examples/statemachine/rogue/window.cpp 5
180
181 The machine is set up, so it's time to start it.
182
183 \section1 The MovementTransition Class
184
185 \c MovementTransition is triggered when the player request the
186 rogue to be moved (by typing 2, 4, 6, or 8) when the machine is in
187 the \c inputState.
188
189 \snippet examples/statemachine/rogue/movementtransition.h 0
190
191 In the constructor, we tell QEventTransition to only send
192 \l{QEvent::}{KeyPress} events to the
193 \l{QAbstractTransition::}{eventTest()} function:
194
195 \snippet examples/statemachine/rogue/movementtransition.h 1
196
197 The KeyPress events come wrapped in \l{QStateMachine::WrappedEvent}s. \c event
198 must be confirmed to be a wrapped event because Qt uses other
199 events internally. After that, it is simply a matter of checking
200 which key has been pressed.
201
202 Let's move on to the \c onTransition() function:
203
204 \snippet examples/statemachine/rogue/movementtransition.h 2
205
206 When \c onTransition() is invoked, we know that we have a
207 \l{QEvent::}{KeyPress} event with 2, 4, 6, or 8, i.e., the event
208 is already unwrapped.
209
210 \section1 The Roguelike Tradition
211
212 You might have been wondering why the game features a rogue. Well,
213 these kinds of text based dungeon exploration games date back to a
214 game called, yes, "Rogue". Although outflanked by the technology
215 of modern 3D computer games, roguelikes have a solid community of
216 hard-core, devoted followers.
217
218 Playing these games can be surprisingly addictive (despite the
219 lack of graphics). Angband, the perhaps most well-known rougelike,
220 is found here: \l{http://rephial.org/}.
221*/
222
Note: See TracBrowser for help on using the repository browser.