~ubuntu-branches/ubuntu/feisty/pygame/feisty

« back to all changes in this revision

Viewing changes to docs/tut/tom/games4.html

  • Committer: Bazaar Package Importer
  • Author(s): Ed Boraas
  • Date: 2004-08-08 00:10:10 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040808001010-nts9g4z69jf1ryb1
Tags: 1.6-2
* Actually build-depend on python (for dh_python)
  * Closes: #264086

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 
2
<HTML
 
3
><HEAD
 
4
><TITLE
 
5
>Game object classes</TITLE
 
6
><META
 
7
NAME="GENERATOR"
 
8
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
 
9
REL="HOME"
 
10
HREF="MakeGames.html"><LINK
 
11
REL="PREVIOUS"
 
12
TITLE="Kicking things off"
 
13
HREF="games3.html"><LINK
 
14
REL="NEXT"
 
15
TITLE="User-controllable objects"
 
16
HREF="games5.html"> <style type="text/stylesheet">
 
17
        <!--
 
18
        PRE.PROGRAMLISTING      { background-color: #EEEEEE; border-color: #333333; border-style: solid; border-width: thin }   -->
 
19
 </style></HEAD
 
20
><BODY
 
21
CLASS="SECT1"
 
22
BGCOLOR="#FFFFFF"
 
23
TEXT="#000000"
 
24
LINK="#0000FF"
 
25
VLINK="#840084"
 
26
ALINK="#0000FF"
 
27
>
 
28
 
 
29
<DIV
 
30
CLASS="NAVHEADER"
 
31
><TABLE
 
32
SUMMARY="Header navigation table"
 
33
WIDTH="100%"
 
34
BORDER="0"
 
35
CELLPADDING="0"
 
36
CELLSPACING="0"
 
37
><TR
 
38
><TH
 
39
COLSPAN="3"
 
40
ALIGN="center"
 
41
></TH
 
42
></TR
 
43
><TR
 
44
><TD
 
45
WIDTH="10%"
 
46
ALIGN="left"
 
47
VALIGN="bottom"
 
48
><A
 
49
HREF="games3.html"
 
50
ACCESSKEY="P"
 
51
>Prev</A
 
52
></TD
 
53
><TD
 
54
WIDTH="80%"
 
55
ALIGN="center"
 
56
VALIGN="bottom"
 
57
></TD
 
58
><TD
 
59
WIDTH="10%"
 
60
ALIGN="right"
 
61
VALIGN="bottom"
 
62
><A
 
63
HREF="games5.html"
 
64
ACCESSKEY="N"
 
65
>Next</A
 
66
></TD
 
67
></TR
 
68
></TABLE
 
69
><HR
 
70
ALIGN="LEFT"
 
71
WIDTH="100%"></DIV
 
72
><DIV
 
73
CLASS="SECT1"
 
74
><H1
 
75
CLASS="SECT1"
 
76
><A
 
77
NAME="AEN106"
 
78
></A
 
79
>4. Game object classes</H1
 
80
><P
 
81
>Once you've loaded your modules, and written your resource handling functions, you'll want to get on to writing some game objects.
 
82
The way this is done is fairly simple, though it can seem complex at first. You write a class for each type of object in the game,
 
83
and then create an instance of those classes for the objects. You can then use those classes' methods to manipulate the objects,
 
84
giving objects some motion and interactive capabilities. So your game, in pseudo-code, will look like this:</P
 
85
><PRE
 
86
CLASS="PROGRAMLISTING"
 
87
>#!/usr/bin/python
 
88
 
 
89
[load modules here]
 
90
 
 
91
[resource handling functions here]
 
92
 
 
93
class Ball:
 
94
        [ball functions (methods) here]
 
95
        [e.g. a function to calculate new position]
 
96
        [and a function to check if it hits the side]
 
97
 
 
98
def main:
 
99
        [initiate game environment here]
 
100
 
 
101
        [create new object as instance of ball class]
 
102
        ball = Ball()
 
103
 
 
104
        while 1:
 
105
                [check for user input]
 
106
 
 
107
                [call ball's update function]
 
108
                ball.update()</PRE
 
109
><P
 
110
>This is, of course, a very simple example, and you'd need to put in all the code, instead of those little bracketed comments. But
 
111
you should get the basic idea. You crate a class, into which you put all the functions for a ball, including <TT
 
112
CLASS="FUNCTION"
 
113
>__init__</TT
 
114
>,
 
115
which would create all the ball's attributes, and <TT
 
116
CLASS="FUNCTION"
 
117
>update</TT
 
118
>, which would move the ball to its new position, before blitting
 
119
it onto the screen in this position.</P
 
120
><P
 
121
>You can then create more classes for all of your other game objects, and then create instances of them so that you can handle them
 
122
easily in the <TT
 
123
CLASS="FUNCTION"
 
124
>main</TT
 
125
> function and the main program loop. Contrast this with initiating the ball in the <TT
 
126
CLASS="FUNCTION"
 
127
>main</TT
 
128
>
 
129
function, and then having lots of classless functions to manipulate a set ball object, and you'll hopefully see why using classes is
 
130
an advantage: It allows you to put all of the code for each object in one place; it makes using objects easier; it makes adding new
 
131
objects, and manipulating them, more flexible. Rather than adding more code for each new ball object, you could simply create new
 
132
instances of the <TT
 
133
CLASS="FUNCTION"
 
134
>Ball</TT
 
135
> class for each new ball object. Magic!</P
 
136
><DIV
 
137
CLASS="SECT2"
 
138
><H2
 
139
CLASS="SECT2"
 
140
><A
 
141
NAME="AEN117"
 
142
></A
 
143
>4.1. A simple ball class</H2
 
144
><P
 
145
>Here is a simple class with the functions necessary for creating a ball object that will, if the <TT
 
146
CLASS="FUNCTION"
 
147
>update</TT
 
148
> function is called
 
149
in the main loop, move across the screen:</P
 
150
><PRE
 
151
CLASS="PROGRAMLISTING"
 
152
>class Ball(pygame.sprite.Sprite):
 
153
        """A ball that will move across the screen
 
154
        Returns: ball object
 
155
        Functions: update, calcnewpos
 
156
        Attributes: area, vector"""
 
157
 
 
158
        def __init__(self, vector):
 
159
                pygame.sprite.Sprite.__init__(self)
 
160
                self.image, self.rect = load_png('ball.png')
 
161
                screen = pygame.display.get_surface()
 
162
                self.area = screen.get_rect()
 
163
                self.vector = vector
 
164
 
 
165
        def update(self):
 
166
                newpos = self.calcnewpos(self.rect,self.vector)
 
167
                self.rect = newpos
 
168
 
 
169
        def calcnewpos(self,rect,vector):
 
170
                (angle,z) = vector
 
171
                (dx,dy) = (z*math.cos(angle),z*math.sin(angle))
 
172
                return rect.move(dx,dy)</PRE
 
173
><P
 
174
>Here we have the <TT
 
175
CLASS="FUNCTION"
 
176
>Ball</TT
 
177
> class, with an <TT
 
178
CLASS="FUNCTION"
 
179
>__init__</TT
 
180
> function that sets the ball up, an <TT
 
181
CLASS="FUNCTION"
 
182
>update</TT
 
183
>
 
184
function that changes the ball's rectangle to be in the new position, and a <TT
 
185
CLASS="FUNCTION"
 
186
>calcnewpos</TT
 
187
> function to calculate the ball's
 
188
new position based on its current position, and the vector by which it is moving. I'll explain the physics in a moment. The one other
 
189
thing to note is the documentation string, which is a little bit longer this time, and explains the basics of the class. These strings
 
190
are handy not only to yourself and other programmers looking at the code, but also for tools to parse your code and document it. They
 
191
won't make much of a difference in small programs, but with large ones they're invaluable, so it's a good habit to get into.</P
 
192
><DIV
 
193
CLASS="SECT3"
 
194
><H3
 
195
CLASS="SECT3"
 
196
><A
 
197
NAME="AEN127"
 
198
></A
 
199
>4.1.1. Diversion 1: Sprites</H3
 
200
><P
 
201
>The other reason for creating a class for each object is sprites. Each image you render in your game will be a sprite object, and so
 
202
to begin with, the class for each object should inherit the <TT
 
203
CLASS="FUNCTION"
 
204
>Sprite</TT
 
205
> class. This is a really nice feature of Python - class
 
206
inheritance. Now the <TT
 
207
CLASS="FUNCTION"
 
208
>Ball</TT
 
209
> class has all of the functions that come with the <TT
 
210
CLASS="FUNCTION"
 
211
>Sprite</TT
 
212
> class, and any object
 
213
instances of the <TT
 
214
CLASS="FUNCTION"
 
215
>Ball</TT
 
216
> class will be registered by Pygame as sprites. Whereas with text and the background, which don't
 
217
move, it's OK to blit the object onto the background, Pygame handles sprite objects in a different manner, which you'll see when we
 
218
look at the whole program's code. </P
 
219
><P
 
220
>Basically, you create both a ball object, and a sprite object for that ball, and you then call the ball's update function on the
 
221
sprite object, thus updating the sprite. Sprites also give you sophisticated ways of determining if two objects have collided.
 
222
Normally you might just check in the main loop to see if their rectangles overlap, but that would involve a lot of code, which would
 
223
be a waste because the <TT
 
224
CLASS="FUNCTION"
 
225
>Sprite</TT
 
226
> class provides two functions (<TT
 
227
CLASS="FUNCTION"
 
228
>spritecollide</TT
 
229
> and <TT
 
230
CLASS="FUNCTION"
 
231
>groupcollide</TT
 
232
>)
 
233
to do this for you.</P
 
234
></DIV
 
235
><DIV
 
236
CLASS="SECT3"
 
237
><H3
 
238
CLASS="SECT3"
 
239
><A
 
240
NAME="AEN138"
 
241
></A
 
242
>4.1.2. Diversion 2: Vector physics</H3
 
243
><P
 
244
>Other than the structure of the <TT
 
245
CLASS="FUNCTION"
 
246
>Ball</TT
 
247
> class, the notable thing about this code is the vector physics, used to calculate
 
248
the ball's movement. With any game involving angular movement, you won't get very far unless you're comfortable with trigonometry, so
 
249
I'll just introduce the basics you need to know to make sense of the <TT
 
250
CLASS="FUNCTION"
 
251
>calcnewpos</TT
 
252
> function.</P
 
253
><P
 
254
>To begin with, you'll notice that the ball has an attribute <TT
 
255
CLASS="FUNCTION"
 
256
>vector</TT
 
257
>, which is made up of <TT
 
258
CLASS="FUNCTION"
 
259
>angle</TT
 
260
> and <TT
 
261
CLASS="FUNCTION"
 
262
>
 
263
z</TT
 
264
>. The angle is measured in radians, and will give you the direction in which the ball is moving. Z is the speed at which the ball
 
265
moves. So by using this vector, we can determine the direction and speed of the ball, and therefore how much it will move on the x and
 
266
y axes:</P
 
267
><DIV
 
268
CLASS="MEDIAOBJECT"
 
269
><P
 
270
><IMG
 
271
SRC="radians.png"></P
 
272
></DIV
 
273
><P
 
274
>The diagram above illustrates the basic maths behind vectors. In the left hand diagram, you can see the ball's projected movement
 
275
represented by the blue line. The length of that line (<TT
 
276
CLASS="FUNCTION"
 
277
>z</TT
 
278
>) represents its speed, and the angle is the direction in which
 
279
it will move. The angle for the ball's movement will always be taken from the x axis on the right, and it is measured clockwise from
 
280
that line, as shown in the diagram.</P
 
281
><P
 
282
>From the angle and speed of the ball, we can then work out how much it has moved along the x and y axes. We need to do this because
 
283
Pygame doesn't support vectors itself, and we can only move the ball by moving its rectangle along the two axes. So we need to
 
284
<I
 
285
CLASS="FIRSTTERM"
 
286
>resolve</I
 
287
> the angle and speed into its movement on the x axis (dx) and on the y axis (dy). This is a simple matter of
 
288
trigonometry, and can be done with the formulae shown in the diagram.</P
 
289
><P
 
290
>If you've studied elementary trigonometry before, none of this should be news to you. But just in case you're forgetful, here are some
 
291
useful formulae to remember, that will help you visualise the angles (I find it easier to visualise angles in degrees than in radians!) </P
 
292
><DIV
 
293
CLASS="MEDIAOBJECT"
 
294
><P
 
295
><IMG
 
296
SRC="formulae.png"></P
 
297
></DIV
 
298
></DIV
 
299
></DIV
 
300
></DIV
 
301
><DIV
 
302
CLASS="NAVFOOTER"
 
303
><HR
 
304
ALIGN="LEFT"
 
305
WIDTH="100%"><TABLE
 
306
SUMMARY="Footer navigation table"
 
307
WIDTH="100%"
 
308
BORDER="0"
 
309
CELLPADDING="0"
 
310
CELLSPACING="0"
 
311
><TR
 
312
><TD
 
313
WIDTH="33%"
 
314
ALIGN="left"
 
315
VALIGN="top"
 
316
><A
 
317
HREF="games3.html"
 
318
ACCESSKEY="P"
 
319
>Prev</A
 
320
></TD
 
321
><TD
 
322
WIDTH="34%"
 
323
ALIGN="center"
 
324
VALIGN="top"
 
325
><A
 
326
HREF="MakeGames.html"
 
327
ACCESSKEY="H"
 
328
>Home</A
 
329
></TD
 
330
><TD
 
331
WIDTH="33%"
 
332
ALIGN="right"
 
333
VALIGN="top"
 
334
><A
 
335
HREF="games5.html"
 
336
ACCESSKEY="N"
 
337
>Next</A
 
338
></TD
 
339
></TR
 
340
><TR
 
341
><TD
 
342
WIDTH="33%"
 
343
ALIGN="left"
 
344
VALIGN="top"
 
345
>Kicking things off</TD
 
346
><TD
 
347
WIDTH="34%"
 
348
ALIGN="center"
 
349
VALIGN="top"
 
350
>&nbsp;</TD
 
351
><TD
 
352
WIDTH="33%"
 
353
ALIGN="right"
 
354
VALIGN="top"
 
355
>User-controllable objects</TD
 
356
></TR
 
357
></TABLE
 
358
>
 
359
 
 
360
</body>
 
361
</html>
 
362
 
 
363
 
 
364
 
 
365
</DIV
 
366
></BODY
 
367
></HTML
 
368
>