Mercurial > pygame
annotate docs/tut/SpriteIntro.html @ 3172:d1b367fc08bc tests-returncode
Use a return code of 1 when the tests fail.
| author | Thomas Kluyver <takowl@gmail.com> |
|---|---|
| date | Wed, 09 Jan 2013 10:13:57 +0000 |
| parents | 0102516f9724 |
| children |
| rev | line source |
|---|---|
| 284 | 1 <html><head><!-- |
| 2 TUTORIAL:Sprite Module Introduction | |
| 3 --> | |
| 4 <title>Pygame Tutorials - Sprite Module Intoduction</title> | |
| 5 </head> | |
| 6 <body> | |
| 7 | |
| 8 <h1 align="center"><font size="-1">Pygame Tutorials</font><br> | |
| 9 Sprite Module Introduction</h1> | |
| 10 | |
| 11 <h2 align="center">by Pete Shinners<br> | |
| 12 <font size="-1">pete@shinners.org</font></h2> | |
| 13 | |
| 363 | 14 <h3 align="center">Revision 1.1, April 12th, 2002</h3> |
| 284 | 15 <br> |
| 16 <br> | |
| 17 Pygame version 1.3 comes with a new module, pygame.sprite. This module | |
| 18 is written in python and includes some higher level classes to manage your | |
| 19 game objects. By using this module to its full potential, you can easily | |
| 20 manage and draw your game objects. The sprite classes are very optimized, | |
| 21 so it's likely your game will run faster with the sprite module than without.<br> | |
| 22 <br> | |
| 23 The sprite module is also meant to be very generic. It turns out you can | |
| 24 use it with nearly any type of gameplay. All this flexibility comes with a | |
|
1423
0102516f9724
Pygame docs: fixed some links
Lenard Lindstrom <len-l@telus.net>
parents:
531
diff
changeset
|
25 slight penalty, it needs a little understanding to properly use it. The <a href="../ref/sprite.html"> |
| 284 | 26 reference documentation</a> for the sprite module can keep you running, but |
| 27 you'll probably need a bit more explanation of how to use pygame.sprite in | |
| 28 your own game.<br> | |
| 29 <br> | |
| 30 Several of the pygame examples (like "chimp" and "aliens") have been updated | |
| 31 to use the sprite module. You may want to look into those first to see what | |
| 32 this sprite module is all about. The chimp module even has it's own line-by-line | |
| 33 tutorial, which may help get more an understanding of programming with python | |
| 34 and pygame.<br> | |
| 35 <br> | |
| 36 Note that this introduction will assume you have a bit of experience programming | |
| 37 with python, and are somewhat framiliar with the different parts of creating | |
| 38 a simple game. In this tutorial the word "reference" is occasianally used. | |
| 39 This represents a python variable. Variables in python are references, so | |
| 40 you can have several variables all pointing to the same object.<br> | |
| 41 <br> | |
| 42 | |
| 43 <h2>History Lesson</h2> | |
| 44 The term "sprite" is a holdover from older computer and game machines. | |
| 45 These older boxes were unable to draw and erase normal graphics fast enough | |
| 46 for them to work as games. These machines had special hardware to handle | |
| 47 game like objects that needed to animate very quickly. These objects were | |
| 48 called 'sprites' and had special limitations, but could be drawn and updated | |
| 49 very fast. They usually existed in special overlay buffers in the video. | |
| 50 These days computers have become generally fast enough to handle sprite like | |
| 51 objects without dedicated hardware. The term sprite is still used to represent | |
| 52 just about anything in a 2D game that is animated.<br> | |
| 53 <br> | |
| 54 <br> | |
| 55 | |
| 56 <h2>The Classes</h2> | |
| 57 The sprite module comes with two main classes. The first is Sprite, which | |
| 58 should be used as a base class for all your game objects. This class doesn't | |
| 59 really do anything on its own, it just includes several functions to help | |
| 60 manage the game object. The other type of class is Group. The Group class | |
| 61 is a container for different Sprite objects. There are actually several different | |
| 62 types of group classes. Some of the Groups can draw all the elements they | |
| 63 contain, for example.<br> | |
| 64 <br> | |
| 65 This is all there really is to it. We'll start with a description of what | |
| 66 each type of class does, and then discuss the proper ways to use these two | |
| 67 classes.<br> | |
| 68 <br> | |
| 69 | |
| 70 <h2>The Sprite Class</h2> | |
| 71 As mentioned before, the Sprite class is designed to be a base class for | |
| 72 all your game objects. You cannot really use it on its own, as it only has | |
| 73 several methods to help it work with the different Group classes. The sprite | |
| 74 keeps track of which groups it belongs to. The class constructor (__init__ | |
| 75 method) takes an argument of a Group (or list of Groups) the Sprite instance | |
| 76 should belong to. You can also change the Group membership for the Sprite | |
| 77 with the add() and remove() methods. There is also a groups() method, which | |
| 78 returns a list of the current groups containing the sprite.<br> | |
| 79 <br> | |
| 80 When using the your Sprite classes it's best to think of them as "valid" | |
| 81 or "alive" when they are belonging to one or more Groups. When you remove | |
| 82 the instance from all groups pygame will clean up the object. (Unless you | |
| 83 have your own references to the instance somewhere else.) The kill() method | |
| 84 removes the sprite from all groups it belongs to. This will cleanly delete | |
| 85 the sprite object. If you've put some little games together, you'll know sometimes | |
| 86 cleanly deleting a game object can be tricky. The sprite also comes with | |
| 87 an alive() method, which returns true if it is still a member of any groups.<br> | |
| 88 <br> | |
| 89 <br> | |
| 90 | |
| 91 <h2>The Group Class</h2> | |
| 92 The Group class is just a simple container. Similar to the sprite, it has | |
| 93 an add() and remove() method which can change which sprites belong to the | |
| 94 group. You also can pass a sprite or list of sprites to the contructor (__init__ | |
| 95 method) to create a Group instance that contains some initial sprites.<br> | |
| 96 <br> | |
| 97 The Group has a few other methods like empty() to remove all sprites from | |
| 98 the group and copy() which will return a copy of the group with all the same | |
| 99 members. Also the has() method will quickly check if the Group contains a | |
| 100 sprite or list of sprites.<br> | |
| 101 <br> | |
| 102 The other function you will use frequently is the sprites() method. This | |
| 103 returns an object that can be looped on to access every sprite the group contains. | |
| 104 Currently this is just a list of the sprites, but in later version of python | |
| 105 this will likely use iterators for better performance.<br> | |
| 106 <br> | |
| 107 As a shortcut, the Group also has an update() method, which will call an | |
| 108 update() method on every sprite in the group. Passing the same arguments to | |
| 109 each one. Usually in a game you need some function that updates the state | |
| 315 | 110 of a game object. It's very easy to call your own methods using the Group.sprites() |
| 284 | 111 method, but this is a shortcut that's used enough to be included. Also note |
| 112 that the base Sprite class has a "dummy" update() method that takes any sort | |
| 113 of arguments and does nothing.<br> | |
| 114 <br> | |
| 115 Lastly, the Group has a couple other methods that allow you to use it with | |
| 116 the builtlin len() method, getting the number of sprites it contains. and | |
| 117 the "truth" operator, which allows you to do "if mygroup:" to check if the | |
| 118 group has any sprites.<br> | |
| 119 <br> | |
| 120 | |
| 121 <h2>Mixing Them Together</h2> | |
| 122 At this point the two classes seem pretty basic. Not doing a lot more than | |
| 123 you can do with a simple list and your own class of game objects. But there | |
| 124 are some big advantages to using the Sprite and Group together. A sprite can | |
| 125 belong to as many groups as you want. Remember as soon as it belongs to no | |
| 126 groups, it will usually be cleared up (unless you have other "non-group" references | |
| 127 to that object)<br> | |
| 128 <br> | |
| 129 The first big thing is a fast simple way to categorize sprites. For example, | |
| 130 say we had a pacman-like game. We could make separate groups for the different | |
| 131 types of objects in the game. Ghosts, Pac, and Pellets. When pac eats a power | |
| 132 pellet, we can change the state for all ghost objects by effecting everything | |
| 133 in the Ghost group. This is quicker and simpler than looping through a list | |
| 134 of all the game objects and checking which ones are ghosts.<br> | |
| 135 <br> | |
| 315 | 136 Adding and removing groups and sprites from each other is a very fast operation, |
| 137 quicker than using lists to store everything. Therefore you can very | |
| 138 efficiently change group memberships. Groups can be used to work | |
| 284 | 139 like simple attributes for each game object. Instead of tracking some attribute |
| 140 like "close_to_player" for a bunch of enemy objects, you could add them to | |
| 141 a separate group. Then when you need to access all the enemies that are near | |
| 142 the player, you already have a list of them, instead of going through a list | |
| 143 of all the enemies, checking for the "close_to_player" flag. Later on your | |
| 144 game could add multiple players, and instead of adding more "close_to_player2", | |
| 145 "close_to_player3" attributes, you can easily add them to different groups | |
| 146 for each player.<br> | |
| 147 <br> | |
| 148 Another important benefit of using the Sprites and Groups, the groups cleanly | |
| 149 handle the deleting (or killing) of game objects. In a game where many objects | |
| 150 are referencing other objects, sometimes deleting an object can be the hardest | |
| 151 part, since it can't go away until it is not referenced by anyone. Say we | |
| 152 have an object that is "chasing" another object. The chaser can keep a simple | |
| 153 Group that references the object (or objects) it is chasing. If the object | |
| 315 | 154 being chased happens to be destroyed, we don't need to worry about notifying |
| 284 | 155 the chaser to stop chasing. The chaser can see for itself that its group is |
| 156 now empty, and perhaps find a new target.<br> | |
| 157 <br> | |
| 158 Again, the thing to remember is that adding and removing sprites from groups | |
| 159 is a very cheap/fast operation. You may be best off by adding many groups | |
| 160 to contain and organize your game objects. Some could even be empty for large | |
| 161 portions of the game, there isn't any penalties for managing your game like | |
| 162 this.<br> | |
| 163 <br> | |
| 164 | |
| 165 <h2>The Many Group Types</h2> | |
| 166 The above examples and reasons to use Sprites and Groups are only a tip | |
| 315 | 167 of the iceberg. Another advantage is that the sprite module comes with |
| 168 several different types of Groups. These groups all work just like a regular | |
| 284 | 169 old Group, but they also have added functionality (or slightly different functionality). |
| 170 Here's a list of the Group classes included with the sprite module.<br> | |
| 171 | |
| 172 <blockquote><b>Group</b><br> | |
| 173 This is the standard "no frills" group mainly explained above. Most of the | |
| 174 other Groups are derived from this one, but not all.<br> | |
| 175 <br> | |
| 176 <b>GroupSingle<br> | |
| 177 </b>This works exactly like the regular Group class, but it only contains | |
| 178 the most recently added sprite. Therefore when you add a sprite to this group, | |
| 179 it "forgets" about any previous sprites it had. Therefore it always contains | |
| 180 only one or zero sprites.<br> | |
| 181 <br> | |
| 182 <b>RenderPlain<br> | |
| 183 </b>This is a standard group derived from Group. It has a draw() method | |
| 184 that draws all the sprites it contains to the screen (or any Surface). For | |
| 185 this to work, it requires all sprites it contains to have a "image" and "rect" | |
| 186 attributes. It uses these to know what to blit, and where to blit it. <br> | |
| 187 <br> | |
| 188 <b>RenderClear<br> | |
| 189 </b>This is derived from the RenderPlain group, and adds a method named | |
| 190 clear(). This will erase the previous position of all drawn sprites. It uses | |
| 191 a background image to fill in the areas where the sprite were. It is smart | |
| 192 enough to handle deleted sprites and properly clear them from the screen when | |
| 193 the clear() method is called.<br> | |
| 194 <br> | |
| 195 <b>RenderUpdates</b><br> | |
| 196 This is the cadillac of rendering Groups. It is inherited from RenderClear, | |
| 315 | 197 but changes the draw() method to also return a list of pygame Rects, which represent |
| 284 | 198 all the areas onscreen that have been changed.<br> |
| 199 <br> | |
| 200 </blockquote> | |
| 201 That is the list of different groups available We'll discuss more about | |
| 202 these rendering groups in the next section. There's nothing stopping you | |
| 203 from creating your own Group classes as well. They are just python code, | |
| 204 so you can inherit from one of these and add/change whatever you want. In | |
| 205 the future I hope we can add a couple more Groups to this list. A GroupMulti | |
| 206 which is like the GroupSingle, but can hold up to a given number of sprites | |
| 207 (in some sort of circular buffer?). Also a super-render group that can clear | |
| 208 the position of the old sprites without needing a background image to do | |
| 209 it (by grabbing a copy of the screen before blitting). Who knows really, | |
| 210 but in the future we can add more useful classes to this list.<br> | |
| 211 <br> | |
| 212 | |
| 213 <h2>The Rendering Groups</h2> | |
| 214 From above we can see there are three different rendering groups. We could | |
| 215 probably just get away with the RenderUpdates one, but it adds overhead not | |
| 216 really needed for something like a scrolling game. So we have a couple tools | |
| 217 here, pick the right one for the right job.<br> | |
| 218 <br> | |
| 219 For a scrolling type game, where the background completely changes every | |
| 220 frame. We obviously don't need to worry about python's update rectangles in | |
| 221 the call to display.update(). You should definitely go with the RenderPlain | |
| 222 group here to manage your rendering.<br> | |
| 223 <br> | |
| 224 For games where the background is more stationary, you definitely don't | |
| 225 want pygame updating the entire screen (since it doesn't need to). This type | |
| 226 of game usually involves erasing the old position of each object, then drawing | |
| 227 it in a new place for each frame. This way we are only changing what is necessary. | |
| 228 Most of the time you will just want to use the RenderUpdates class here. Since | |
| 229 you will also want to pass this list of changes to the display.update() function.<br> | |
| 230 <br> | |
| 231 The RenderUpdates class also does a good job an minimizing | |
| 531 | 232 overlapping areas in the list of updated rectangles. If the previous position |
| 284 | 233 and current position of an object overlap, it will merge them into a single |
| 234 rectangle. Combine this with the fact that is properly handles deleted objects | |
| 235 and this is one powerful Group class. If you've written a game that manages | |
| 236 the changed rectangles for the objects in a game, you know this the cause | |
| 237 for a lot of messy code in your game. Especially once you start to throw in | |
| 238 objects that can be deleted at anytime. All this work is reduced down to | |
| 239 a clear() and draw() method with this monster class. Plus with the overlap | |
| 240 checking, it is likely faster than if you did it yourself.<br> | |
| 241 <br> | |
| 242 Also note that there's nothing stopping you from mixing and matching these | |
| 243 render groups in your game. You should definitely use multiple rendering groups | |
| 244 when you want to do layering with your sprites. Also if the screen is split into | |
| 245 multiple sections, perhaps each section of the screen should use an appropriate | |
| 246 render group?<br> | |
| 247 <br> | |
| 248 | |
| 249 | |
| 250 <h2>Collision Detection</h2> | |
| 251 The sprite module also comes with two very generic collision detection functions. | |
| 252 For more complex games, these really won't work for you, but you can easily | |
| 253 grab the sourcecode for them, and modify them as needed.<br> | |
| 254 Here's a summary of what they are, and what they do.<br> | |
| 255 | |
| 256 <blockquote><b>spritecollide(sprite, group, dokill) -> list<br> | |
| 257 </b>This checks for collisions between a single sprite and the sprites | |
| 258 in a group. It requires a "rect" attribute for all the sprites used. It returns | |
| 259 a list of all the sprites that overlap with the first sprite. The "dokill" | |
| 260 argument is a boolean argument. If it is true, the function will call the | |
| 261 kill() method on all the sprites. This means the last reference to each sprite | |
| 262 is probably in the returned list. Once the list goes away so do the sprites. | |
| 263 A quick example of using this in a loop,<br> | |
| 264 | |
| 265 <pre> >>> for bomb in sprite.spritecollide(player, bombs, 1):<br> ... boom_sound.play()<br> ... Explosion(bomb, 0)<br></pre> | |
| 266 This finds all the sprites in the "bomb" group that collide with the player. | |
| 267 Because of the "dokill" argument it deletes all the crashed bombs. For each | |
| 268 bomb that did collide, it plays a "boom" sound effect, and creates a new Explosion | |
| 269 where the bomb was. (Note, the Explosion class here knows to add each instance | |
| 270 to the appropriate class, so we don't need to store it in a variable, that | |
| 271 last line might feel a little "funny" to you python programmers.<br> | |
| 272 <br> | |
| 273 <b>groupcollide(group1, group2, dokill1, dokill2) -> dictionary</b><br> | |
| 274 This is similar to the spritecollide function, but a little more complex. | |
| 275 It checks for collisions for all the sprites in one group, to the sprites | |
| 276 in another. There is a dokill argument for the sprites in each list. When | |
| 277 dokill1 is true, the colliding sprites in group1 will be kill()ed. When dokill2 | |
| 278 is true, we get the same results for group2. The dictionary it returns works | |
| 279 like this; each key in the dictionary is a sprite from group1 that had a collision. | |
| 280 The value for that key is a list of the sprites that it collided with. Perhaps | |
| 281 another quick code sample explains it best<br> | |
| 282 | |
| 363 | 283 <pre> >>> for alien in sprite.groupcollide(aliens, shots, 1, 1).keys() |
| 284 ... boom_sound.play() | |
| 285 ... Explosion(alien, 0) | |
| 286 ... kills += 1 | |
| 287 </pre> | |
| 284 | 288 This code checks for the collisions between player bullets and all the aliens |
| 289 they might intersect. In this case we only loop over the dictionary keys, | |
| 290 but we could loop over the values() or items() if we wanted to do something | |
| 291 to the specific shots that collided with aliens. If we did loop over the values() | |
| 292 we would be looping through lists that contain sprites. The same sprite may | |
| 293 even appear more than once in these different loops, since the same "shot" | |
| 294 could have collided against multiple "aliens".<br> | |
| 295 <br> | |
| 296 <br> | |
| 297 </blockquote> | |
| 298 Those are the basic collision functions that come with pygame. It should | |
| 299 be easy to roll your own that perhaps use something differen than the "rect" | |
| 300 attribute. Or maybe try to fine-tweak your code a little more by directly | |
| 301 effecting the collision object, instead of building a list of the collision? | |
| 302 The code in the sprite collision functions is very optimized, but you could | |
| 303 speed it up slightly by taking out some functionality you don't need.<br> | |
| 304 <br> | |
| 305 | |
| 363 | 306 <h2>Common Problems</h2> |
| 307 <p>Currently there is one main problem that catches new users. When you | |
| 308 derive your new sprite class with the Sprite base, you <b>must</b> call the | |
| 309 Sprite.__init__() method from your own class __init__() method. If you forget | |
| 310 to call the Sprite.__init__() method, you get a cryptic error, like this; | |
| 311 <tt>AttributeError: 'mysprite' instance has no attribute '_Sprite__g'</tt>. | |
| 312 </p> | |
| 313 <br> | |
| 314 | |
| 315 <h2>Extending Your Own Classes <i>(Advanced)</i></h2> | |
| 316 | |
| 317 <p>Because of speed concerns, the current Group classes try to | |
| 318 only do exactly what they need, and not handle a lot of general situations. If you | |
| 319 decide you need extra features, you may want to create your own Group class.</p> | |
| 320 | |
| 321 <p>The Sprite and Group classes were designed to be extended, so feel free | |
| 322 to create your own Group classes to do specialized things. The best place to start | |
| 323 is probably the actual python source code for the sprite module. Looking at the | |
| 324 current Sprite groups should be enough example on how to create your own.</p> | |
| 325 | |
| 326 <p>For example, here is the source code for a rendering Group that calls a | |
| 327 render() method for each sprite, instead of just blitting an "image" variable from it. | |
| 328 Since we want it to also handle updated areas, we will start with a copy of the original | |
| 329 RenderUpdates group, here is the code: | |
| 330 <pre> | |
| 331 class RenderUpdatesDraw(RenderClear): | |
| 332 """call sprite.draw(screen) to render sprites""" | |
| 333 def draw(self, surface): | |
| 334 dirty = self.lostsprites | |
| 335 self.lostsprites = [] | |
| 336 for s, r in self.spritedict.items(): | |
| 337 newrect = s.draw(screen) #Here's the big change | |
| 338 if r is 0: | |
| 339 dirty.append(newrect) | |
| 340 else: | |
| 341 dirty.append(newrect.union(r)) | |
| 342 self.spritedict[s] = newrect | |
| 343 return dirty | |
| 344 </pre></p> | |
| 345 | |
| 346 <p>Following is more information on how you could create your own Sprite | |
| 347 and Group objects from scratch. </p> | |
| 284 | 348 |
| 363 | 349 <p>The Sprite objects only "require" two methods. "add_internal()" and "remove_internal()". |
| 284 | 350 These are called by the Group classes when they are removing a sprite from |
| 351 themselves. The add_internal() and remove_internal() have a single argument | |
| 363 | 352 which is a group. Your Sprite will need some way to also keep |
| 353 track of the Groups it belongs to. You will likely want to try to match the | |
| 284 | 354 other methods and arguments to the real Sprite class, but if you're not going |
| 363 | 355 to use those methods, you sure don't need them.</p> |
| 284 | 356 |
| 357 <p>It is almost the same requirements for creating your own Group. In | |
| 358 fact, if you look at the source you'll see the GroupSingle isn't derived from | |
| 359 the Group class, it just implements the same methods so you can't really tell | |
| 363 | 360 the difference. Again you need an "add_internal()" and "remove_internal()" method |
| 284 | 361 that the sprites call when they want to belong or remove themselves from |
| 362 the group. The add_internal() and remove_internal() have a single argument | |
| 363 which is a sprite. The only other requirement for the Group classes is they | |
| 364 have a dummy attribute named "_spritegroup". It doesn't matter what the value | |
| 365 is, as long as the attribute is present. The Sprite classes can look for this | |
| 366 attribute to determine the difference between a "group" and any ordinary python | |
| 367 container. (This is important, because several sprite methods can take an | |
| 368 argument of a single group, or a sequence of groups. Since they both look | |
| 369 similar, this is the most flexible way to "see" the difference.)</p> | |
| 370 | |
| 363 | 371 <p>You should through the code for the sprite module. While |
| 284 | 372 the code is a bit "tuned", it's got enough comments to help you follow along. |
| 373 There's even a todo section in the source if you feel like contributing.</p> | |
| 374 | |
| 375 </body></html> |
