Pages

Tuesday, June 11, 2013

A Newbie Guide to pygame by David Clark

A Newbie Guide to pygame - David Clark, Pygame v1.9.2 documentation

http://www.pygame.org/docs/tut/newbieguide.html

or Things I learned by trial and error so you don’t have to,

or How I learned to stop worrying and love the blit.

Pygame is a python wrapper for SDL, written by Pete Shinners. What this means is that, using pygame, you can write games or other multimedia applications in Python that will run unaltered on any of SDL’s supported platforms (Windows, Unix, Mac, beOS and others).

Pygame may be easy to learn, but the world of graphics programming can be pretty confusing to the newcomer. I wrote this to try to distill the practical knowledge I’ve gained over the past year or so of working with pygame, and it’s predecessor, pySDL. I’ve tried to rank these suggestions in order of importance, but how relevent any particular hint is will depend on your own background and the details of your project.

Get comfortable working in Python.

The most important thing is to feel confident using python. Learning something as potentially complicated as graphics programming will be a real chore if you’re also unfamiliar with the language you’re using. Write a few sizable non-graphical programs in python – parse some text files, write a guessing game or a journal-entry program or something. Get comfortable with string and list manipulation – know how to split, slice and combine strings and lists. Know how import works – try writing a program that is spread across several source files. Write your own functions, and practice manipulating numbers and characters; know how to convert between the two. Get to the point where the syntax for using lists and dictionaries is second-nature – you don’t want to have to run to the documentation every time you need to slice a list or sort a set of keys. Resist the temptation to run to a mailing list, comp.lang.python, or irc when you run into trouble. Instead, fire up the interpreter and play with the problem for a few hours. Print out the Python 2.0 Quick Reference and keep it by your computer.

This may sound incredibly dull, but the confidence you’ll gain through your familiarity with python will work wonders when it comes time to write your game. The time you spend making python code second-nature will be nothing compared to the time you’ll save when you’re writing real code.

Recognize which parts of pygame you really need.

Looking at the jumble of classes at the top of the pygame Documentation index may be confusing. The important thing is to realize that you can do a great deal with only a tiny subset of functions. Many classes you’ll probably never use – in a year, I haven’t touched the Channel, Joystick, cursors, Userrect, surfarray or version functions.

Know what a surface is.

The most important part of pygame is the surface. Just think of a surface as a blank piece of paper. You can do a lot of things with a surface – you can draw lines on it, fill parts of it with color, copy images to and from it, and set or read individual pixel colors on it. A surface can be any size (within reason) and you can have as many of them as you like (again, within reason). One surface is special – the one you create with pygame.display.set_mode(). This ‘display surface’ represents the screen; whatever you do to it will appear on the user’s screen. You can only have one of these – that’s an SDL limitation, not a pygame one.

So how do you create surfaces? As mentioned above, you create the special ‘display surface’ with pygame.display.set_mode(). You can create a surface that contains an image by using image.load(), or you can make a surface that contains text with font.render(). You can even create a surface that contains nothing at all with Surface().

Most of the surface functions are not critical. Just learn blit(), fill(), set_at() and get_at(), and you’ll be fine.

Use surface.convert().

When I first read the documentation for surface.convert(), I didn’t think it was something I had to worry about. ‘I only use pngs, therefore everything I do will be in the same format. So I don’t need convert()‘;. It turns out I was very, very wrong.

The ‘format’ that convert() refers to isn’t the file format (ie png, jpeg, gif), it’s what’s called the ‘pixel format’. This refers to the particular way that a surface records individual colors in a specific pixel. If the surface format isn’t the same as the display format, SDL will have to convert it on-the-fly for every blit – a fairly time-consuming process. Don’t worry too much about the explanation; just note that convert() is necessary if you want to get any kind of speed out of your blits.

How do you use convert? Just call it after creating a surface with the image.load() function. Instead of just doing:

surface = pygame.image.load('foo.png')

Do:

surface = pygame.image.load('foo.png').convert()

It’s that easy. You just need to call it once per surface, when you load an image off the disk. You’ll bepleased with the results; I see about a 6x increase in blitting speed by calling convert().

The only times you don’t want to use convert() is when you really need to have absolute control over an image’s internal format – say you were writing an image conversion program or something, and you needed to ensure that the output file had the same pixel format as the input file. If you’re writing a game, you need speed. Use convert().


Dirty rect animation.

The most common cause of inadequate frame rates in pygame programs results from misunderstanding the pygame.display.update() function. With pygame, merely drawing something to the display surface doesn’t cause it to appear on the screen – you need to call pygame.display.update(). There are three ways of calling this function:

pygame.display.update() – This updates the whole window (or the whole screen for fullscreen displays).

pygame.display.flip() – This does the same thing, and will also do the right thing if you’re using
doublebuffered hardware acceleration, which you’re not, so on to...

pygame.display.update(a rectangle or some list of rectangles) – This updates just the rectangular areas of the screen you specify.

Most people new to graphics programming use the first option – they update the whole screen every frame. The problem is that this is unacceptably slow for most people. Calling update() takes 35 milliseconds on my machine, which doesn’t sound like much, until you realize that 1000 / 35 = 28 frames per second maximum. And that’s with no game logic, no blits, no input, no AI, nothing. I’m just sitting there updating the screen, and 28 fps is my maximum framerate. Ugh.

The solution is called ‘dirty rect animation’. Instead of updating the whole screen every frame, only the parts that changed since the last frame are updated. I do this by keeping track of those rectangles in a list, then calling update(the_dirty_rectangles) at the end of the frame. In detail for a moving sprite, I:

Blit a piece of the background over the sprite’s current location, erasing it.

Append the sprite’s current location rectangle to a list called dirty_rects.

Move the sprite.

Draw the sprite at it’s new location.

Append the sprite’s new location to my dirty_rects list.

Call display.update(dirty_rects)

The difference in speed is astonishing. Consider that Solarwolf has dozens of constantly moving sprites updating smoothly, and still has enough time left over to display a parallax starfield in the background, and update that too.

There are two cases where this technique just won’t work. The first is where the whole window or screen really is being updated every frame – think of a smooth-scrolling engine like an overhead real-time strategy game or a side-scroller. So what do you do in this case? Well, the short answer is – don’t write this kind of game in pygame. The long answer is to scroll in steps of several pixels at a time; don’t try to make scrolling perfectly smooth. Your player will appreciate a game that scrolls quickly, and won’t notice the background jumping along too much.

A final note – not every game requires high framerates. A strategic wargame could easily get by on just a few updates per second – in this case, the added complexity of dirty rect animation may not be necessary.

...

David Clark is an avid pygame user and the editor of the Pygame Code Repository, a showcase for community-submitted python game code. He is also the author of Twitch, an entirely average pygame arcade game.

.END

No comments:

Post a Comment