Writing a game in Python with Pygame. Part I

December 13th, 2008 at 11:18 am


Games are one of the most applicative areas of programming. To write even the simplest games, you have to get into graphics, math, physics and even AI. It’s a great and fun way to practice programming.

If you’re a fan of Python (and even if you aren’t) and are interested in games, Pygame is a great library for game programming, and you should definitely check it out. It runs on all major platforms, and provides simple tools to manage complex graphical worlds with movement and sounds.

There are quite a lot of Pygame tutorials on the web, but most of them are basic. Even the Pygame book stays at an introductory level. In order to proceed to a higher level of mastery, I’ve decided to write a tutorial of my own, hoping that it will provide the next logical step for persons wanting to use Pygame.

This tutorial explicitly encourages you to tinker with the code. It is also highly recommended to do the exercises in the end. These will greatly aid your understanding of the learned material.


For reasons I’ve mentioned above, this tutorial is not for complete beginners. If you’re just beginning with Pygame, first go through some of the tutorials from this page. This tutorial is also recommended as a basic introduction to Pygame.

Here, I assume that you have the following knowledge:

  • Python (you don’t have to be an advanced user, but not a complete beginner either)
  • Basics of math and physics (vectors, rectangles, laws of movement, probability, etc.). I will explain all the non-trivial tricks, but I won’t teach how to add vectors, and so on.
  • An acquaintance with Pygame. I.e. you’ve already went through at least a couple of the tutorials mentioned above.

Oh, and another thing… This tutorial will focus on a 2D game. 3D is a whole new level of complexity, and I prefer a simpler but complete game to a half-baked 3D demo.

Let’s get started

In this part, we’ll end up writing a demo – a complete simulation of creeps, round creatures that move around the screen, bouncing off walls and changing their direction from time to time:


While this is not yet a game per se, it’s a useful starting point, from which we can implement many various ideas. I’ll leave myself the luxury of postponing the decision of which game it will eventually be, for now.

The code

The complete package for part 1, with all the required images, can be downloaded from here. I recommend you to download it and run the demo. Having the code in front of your eyes is very useful. I tested it with Python 2.5.2 and Pygame 1.8.1, although it will probably work with other versions as well.

Pygame’s docs

Pygame’s API is documented fairly well. There is a complete list of modules, classes, constants and functions provided by Pygame there, and I encourage you to consult this resource often – for each Pygame class/method you’re not familiar with.


Okay, so first let’s set the goals for this part:

  • We want to have creeps moving around the screen
  • The amount of creeps and their appearance should be easily configurable
  • The creeps will bounce off walls correctly
  • To make things more interesting, the creeps will exhibit semi-random behavior

So what is a creep ?

A creep is a small image that will be moved around the screen and rotated using Pygame’s capabilities. Keeping rotated images pretty takes more artistic skill than I possess, so I’ll limit the rotations to quantas of 45 degrees (meaning that creeps will move up, down, left, right or in 4 diagonals).

The creep images contained in the downloadable package are small .png files [1]


Note that all the creep images have the same orientation. This is significant, as we will learn later.

How do creeps "move" ?

As you’ve undoubtedly read in one of the basic Pygame tutorials (haven’t you ??), movement is an illusion. Nothing really moves on a computer screen. Rather, the program displays a sequence of images with small displacements fast enough for the human eye to perceive movement. The rule of thumb is that anything 30 updates per second [2] or faster is good enough and looks smooth to the average person.

To implement periodic update of the screen, games use the "game loop".

The game loop

Just like a GUI, every game has the "main loop". In Pygame you implement it with a Python loop, which is simple enough. Here’s our main loop:

# The main game loop
while True:
    # Limit frame speed to 50 FPS
    time_passed = clock.tick(50)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:

    # Redraw the background

    # Update and redraw all creeps
    for creep in creeps:


Jumping right into the code, eh ? Well, let’s see what goes on here. As I’ve said, it’s your basic Python loop – endless, until the user asks to quit. pygame.QUIT is the only event handled here, as you can see. It arrives when the user attempts to close the program’s window.

How often does this loop run ? This is decided by the call to clock.tick. clock is a pygame.time.Clock object, created earlier. The call to tick basically says this: sleep until the next 1/50 second boundary, at most. In practice, this limits the game speed to 50 FPS, which is a good thing, because we want the game to be smooth on one hand, and not eat up most of the CPU on the other hand. You can experiment with this effect by playing with the value. Lower it to 10, for example. How does the demo look ? Also, see exercises 1 and 3.

Now is a good time to immerse yourself in the documentation of tick, by the way.

The really interesting stuff happens later. On each iteration, the screen is refilled with the background color and all the creeps are updated and drawn. Finally, the display is updated with flip (Yes, you should read its documentation now).

What comes before the loop

Now let’s see what comes before the main loop:

# Game parameters
BG_COLOR = 150, 150, 80

screen = pygame.display.set_mode(
            (SCREEN_WIDTH, SCREEN_HEIGHT), 0, 32)
clock = pygame.time.Clock()

# Create N_CREEPS random creeps.
creeps = []
for i in range(N_CREEPS):
                        (   randint(0, SCREEN_WIDTH),
                            randint(0, SCREEN_HEIGHT)),
                        (   choice([-1, 1]),
                            choice([-1, 1])),

OK, not much magic here. The first few lines are self-explanatory. I also assume you already know how to initialize Pygame and create a display object. What about the creation of creeps, though?

creeps is a list of Creep objects – the heart and soul of this game. Here’s the declaration of the Creep class with its constructor’s signature:

class Creep(Sprite):
    """ A creep sprite that bounces off walls and changes its
        direction from time to time.
    def __init__(
            self, screen, img_filename, init_position,
            init_direction, speed):
        """ Create a new Creep.

                The screen on which the creep lives (must be a
                pygame Surface object, such as pygame.display)

                Image file for the creep.

                A vec2d or a pair specifying the initial position
                of the creep on the screen.

                A vec2d or a pair specifying the initial direction
                of the creep. Must have an angle that is a
                multiple of 45 degres.

                Creep speed, in pixels/millisecond (px/ms)

The arguments are well documented, and you can see how they are matched by the passed values when the creeps are created:

                    (   randint(0, SCREEN_WIDTH),
                        randint(0, SCREEN_HEIGHT)),
                    (   choice([-1, 1]),
                        choice([-1, 1])),

First, we pass the screen surface to the Creep. It will use it to figure out how to bounce off walls, and where to draw itself.

Next, the Creep is provided with a random image from the list of images (choice is a function from Python’s standard random module), and is set in a random position on the screen (randint is also from random), with a random direction (more about the direction later). The speed is set to 0.1 px/ms (0.1 pixels per millisecond), or 100 pixels per second.

Vectors and directions

This is perhaps the least simple part of the creeps demo. Grokking vectors in game programming is essential, since vectors are the chief mathematical tool for making computations related to movement on the screen.

We’ll use vectors for two things. One is to describe the position and velocity (displacement) of creeps. As you surely know, a position (a point) on the XY plane can be represented by a 2D vector. The difference between two vectors is the velocity (displacement) vector. In other words, adding the velocity vector to the original position vector yields the new position:


This is all good and nice, except for a small twist. While in the mathematical world, we’re accustomed to the XY plane to look as it does on the diagram above (positive X pointing right, positive Y pointing up), when we’re drawing on the screen we must think a bit differently. In almost all graphical drawing interfaces, the top-left corner is (0, 0), X increases to the right, and Y increases to downwards. In other words, the screen drawing XY plane is:


This is a very important diagram! It represents the basic 8 normalized vectors we’ll be using in the creep demo. These are the directions the creep can be pointing in (all multiples of 45 degrees over the unit circle). Make sure you understand it before moving on.

Recall the direction argument to the constructor of Creep ? This is the vector that specifies the initial direction of the creep. Actually, the constructor allows to pass in a pair, which is later turned into a vector and normalized (so, for instance, passing the pair (-1, -1) will result in the expected north-west direction).

This direction will be later changed by the creep itself when it either decides to go another way or bounces off a wall.

Implementing vectors

Surprisingly, Pygame doesn’t have a "standard" vector implementation shipping with it. So game writers have to either roll their own or find vector modules online.

Included in the package is the vec2d.py file, a 2D vector implementation I’ve borrowed from the Pygame Wiki. It is a pretty good implementation of a 2D vector with a lot of useful utility functions. There’s no need for you to read and understand its full code now, but see exercise 4.

Updating the creep

The most interesting function of this demo is the update method of Creep.

def update(self, time_passed):

This method is called periodically by the main loop and is passed the amount of time passed (in milliseconds) since the previous call. Using this knowledge, the creep can compute its next location.

Let’s learn the code of update, step by step:

# Maybe it's time to change the direction ?

# Make the creep point in the correct direction.
# Since our direction vector is in screen coordinates
# (i.e. right bottom is 1, 1), and rotate() rotates
# counter-clockwise, the angle must be inverted to
# work correctly.
self.image = pygame.transform.rotate(
    self.base_image, -self.direction.angle)

First, the internal _change_direction is called to see if the creep wants to randomly change its direction. The code of _change_direction will be simple to understand after we complete going through update, so I’m leaving it for exercise 5.

The next operation is to rotate the creep image in the correct direction. Recall how I noted that all the creep images point to the right? This is essential for correct and consistent rotation. transform.rotate (read its docs!) rotates a given surface counterclockwise by the provided angle.

Now, why do we give it a negation of the angle ? This is exactly because of the inverted "screen XY plane" I’ve mentioned before.
Imagine the base creep image (which is, by the way, loaded in the constructor of Creep – see how):


And suppose our direction is 45 degrees (that is, south-east in our screen coordinates). If we give 45 degrees to rotate, it will make the creep point north-east (as its rotation is counterclockwise). So to perform the correct rotation, we have to negate the angle.

Next in update, we see:

# Compute and apply the displacement to the position
# vector. The displacement is a vector, having the angle
# of self.direction (which is normalized to not affect
# the magnitude of the displacement)
displacement = vec2d(
    self.direction.x * self.speed * time_passed,
    self.direction.y * self.speed * time_passed)

self.pos += displacement

As I said, self.direction is a normalized vector that tells us where the creep points to. It is important for it to be normalized for this computation to work correctly, because we don’t want it to affect the magnitude of the displacement. The displacement is computed from the basic rule of motion that distance equals speed multiplied by time, just in 2 dimensions.

The next part of update deals with bouncing off walls. To make it more intelligible, I want to first show how the creep is drawn to the screen.


Blitting is the game programmers’ jargon for transferring an image (or a pattern) onto a drawable surface. In Pygame this is implemented with the blit function.

def blitme(self):
    """ Blit the creep onto the screen that was provided in
        the constructor.
    # The creep image is placed at self.pos.
    # To allow for smooth movement even when the creep rotates
    # and the image size changes, its placement is always
    # centered.
    draw_pos = self.image.get_rect().move(
        self.pos.x - self.image_w / 2,
        self.pos.y - self.image_h / 2)
    self.screen.blit(self.image, draw_pos)

Blitting, like many other things in Pygame, use the versatile pygame.Rect class. The call to blit accepts an image (a surface, actually) and a rectangle that specifies where this image will be blitted to the surface on which blit is invoked.

And sure enough, we provide the drawing position as the creep’s current position (self.pos) but with a small adjustment. What for ?

Thing is, when images are rotated in Pygame, their size increases. Here’s why:


Since the image is square, Pygame has to include all of its information in the rotated image, so the rotated image has to grow in size. This only happens for rotations that are not multiples of 90 degrees, by the way (see exercise 6).

So, whenever a creep turns, its image size changes. Without a special adjustment, the creep will shift with each turn and the animation won’t be smooth and pretty.

The adjustment is simple enough: we center the creep when we draw it. Look at this code again:

draw_pos = self.image.get_rect().move(
    self.pos.x - self.image_w / 2,
    self.pos.y - self.image_h / 2)
self.screen.blit(self.image, draw_pos)

The draw position is computed to be the center of the creep’s image. Even when the image rotates and grows, its center stays in the same place, so there will be no noticeable shift in the creep this way.

Bouncing off walls

Make sure you understand the "centered drawing" trick described in the previous section (and see exercise 7) first. Once you do, understanding how the creep bounces off walls is easy. Here’s the code:

# When the image is rotated, its size is changed.
# We must take the size into account for detecting
# collisions with the walls.
self.image_w, self.image_h = self.image.get_size()
bounds_rect = self.screen.get_rect().inflate(
                -self.image_w, -self.image_h)

if self.pos.x < bounds_rect.left:
    self.pos.x = bounds_rect.left
    self.direction.x *= -1
elif self.pos.x > bounds_rect.right:
    self.pos.x = bounds_rect.right
    self.direction.x *= -1
elif self.pos.y < bounds_rect.top:
    self.pos.y = bounds_rect.top
    self.direction.y *= -1
elif self.pos.y > bounds_rect.bottom:
    self.pos.y = bounds_rect.bottom
    self.direction.y *= -1

First, the screen boundary itself is computed, by taking the rectangle representing the screen and adjusting it to the image size (this is required for our centered drawing).

Then, for each of the 4 walls we compute whether the creep collides with it, and if it does, the creep’s direction is inverted in the axis perpendicular to the wall, simulating a smooth bounce. Let’s dissect one of such conditions:


if self.pos.x < bounds_rect.left:
    self.pos.x = bounds_rect.left
    self.direction.x *= -1

This is for the bounce off the left wall. The creeps always arrives to it from the right, so when we negate the X component of its direction vector while keeping the Y component intact, it will start moving to the right but with the same vertical direction.


We’ve seen most of the interesting code of creeps.py now. If something still remains unclear, go through the whole code with the diagrams from this tutorial in front of your eyes. If things remain unclear, let me know and I’ll gladly help.

One can understand a tutorial or a lecture on several levels. The most basic is just reading it. To make understanding deeper, one must also practice the material. And to master something, you should apply your brain to new material, new challenges based on the tutorial but not directly explained in it. For this, I once again warmly encourage you to at least look at the exercises and try to think how to do them. The best would be implementing solutions and tinkering with the code itself.

What’s next

The creeps demo can serve as a good basis for quite a few games. I haven’t decided which I want to write, yet, and how far I want to take this tutorial at all. So its future direction depends a lot on your feedback. Feel free to comment or write me an email.



  1. Increase the amount of creeps by modifying the N_CREEPS constant. On my PC, the demo runs easily and smoothly with hundreds of creeps.
  2. Modify the creep creation line to have 60% gray creeps, 20% blue and 20% pink.
  3. Experiment with the call to clock.tick in the main loop. Try to print out the time passed between ticks, and then modify the argument to tick. If you provide no argument, it runs as fast as it can. See how much time passes between ticks when the amount of creeps increases.
  4. Open vec2d.py, and read the code of all the methods and attributes used in our creeps demo.
  5. Modify the _change_direction method to change the behavior of creeps. (1) Make them change direction more often and observe the behavior. (2) Can you make them stop for a second once in a while ? You’d have to modify the speed for that.
  6. Can you use basic trigonometry to compute by how much the image increases when it’s rotated by 45 degrees in Pygame ?
  7. Rewrite the drawing code to cancel centered drawing (just provide the unadjusted image rectangle to blit). How does it look ?


  • 13.12.2008 – Simplified the code for bouncing off walls. Thanks to Andrei for the tip.
[1] PNG is a useful format – it is free, provides efficient lossless compression and supports alpha (transparency).
[2] Or Frames Per Second (FPS) in game programming jargon. Counting FPS is the hobby of game programmers worldwide.

Related posts:

  1. Writing a game in Python with Pygame. Part II
  2. Writing a game in Python with Pygame. Part IV
  3. Writing a game in Python with Pygame. Part III
  4. Book review: “Beginning game development with Python and Pygame” by Will McGugan
  5. Project Euler problem 83 – how creeps can help

29 Responses to “Writing a game in Python with Pygame. Part I”

  1. andreiNo Gravatar Says:

    why just not invert x/y direction when bouncing of vertical/horisontal wall?

    if self.pos.x < bounds_rect.left or self.pos.x > bounds_rect.right :
        self.pos.x = bounds_rect.left if self.pos.x < bounds_rect.left else bounds_rect.right
        self.direction.x = - self.direction.x
  2. elibenNo Gravatar Says:

    You’re right – this makes the code a bit simpler. I’ll update the tutorial and the code.

  3. Francis Esmonde-WhiteNo Gravatar Says:

    Hi eliben,

    I happen to be reading said python game book at the moment. Your tutorial is nicely written, but it’s almost identical to the examples given in the book (chapters 5 and 6 of Will McGugan’s ‘beginning game development with python and pygame’, http://www.willmcgugan.com). Why not do something a bit more ambitious?

    For the rotations, can’t you use the image (surface) rotation function, then just query the new image (surface) array to check what the new size is… that way you can re-center it using the increased size. The code is:


    [p. 119]

    How about including sprite-sprite interactions? You could check to see if the next movement will cause the current sprite to touch another sprite, then have it ‘bounce’ off the other sprite(use trigonometry, find the normal to the other sprites circular surface, and then make it reflect along the plane). You could even include a ‘mass’ term in each sprite, and have the collision modeled as an elastic collision.


  4. elibenNo Gravatar Says:


    Have you missed the “Part I” piece of the post title :-) ?

    True, there’s some overlap between this tutorial and chapters 5 and 6 of the book, but while the book ends at about this level, this tutorial is only the first part! I am trying to do something more ambitious here, because I plan to post other installments of the tutorial, taking the game to much higher levels of complexity.

    So stay tuned :-)

  5. Mikko OhtamaaNo Gravatar Says:

    pygame is now available for mobile phones too:


  6. tshirtmanNo Gravatar Says:

    I can’t wait to see what’s next, I’m working on my game with pygame since 9 months, and it’s starting to be in a good shape, but you may have some tips ready to help me (I still have small issues). If you get to speak about AI and network I would be very glad! (although it’s out of the “pygame” topic ^^).

    Python+Pygame is such a great combination! And I use profusions of PNG too ^^, XML too is really useful.

    @Mikko: this is fantastic news!

  7. LarsNo Gravatar Says:


    I see a little error in the wall bouncing code here.

    You use one if and three elifs but that’s actually a little to much “else” here. Pretend your creep would bounce at coordinates 0,0. You check to see if the x ordinate is lower than possible which would be true in our case.
    So you change the x moving direction. But what about the y axis now? It needs a change too but it will first be fixed in the next loop since the y axis part is skipped in the first run because of the second elif.
    The next loop should fix it because most likely the x axis is bigger than the movement in one step so the checks for ‘sanity’ of x values are both negative. While this looks a bit picky at this time it leads to problems where coordinates < 0 are an error condition.

    just my 2¢ :-)

  8. elibenNo Gravatar Says:


    From a purist point of view, you’re right, Y can get negative in some very very rare cases. But it will get negative only for a few milliseconds, until the next call to update, so there’s no real impact on the game whatsoever.

    That said, I will fix the code for the next releases of the tutorial in order to, as you’ve correctly noted, prepare for more complex needs in the future.

    Thanks for noticing.

  9. Goal Setting CollegeNo Gravatar Says:

    Eli, this is an awesome series of tutorials! Thanks for your efforts! Actually, a friend of mine is working on some pygame programming and I’m just helping him out with some research. I’ve already forward a link to your series to him!

  10. Marc RussellNo Gravatar Says:

    Ive been meaning to look at PyGame for a while and this will be a great starting point for me as you have set out some clear tutorials here, so firstly thanks for that.

    Secondly to the reason I wanted to comment is that I have a couple of free graphics and font libraries of sprites and bitmap fonts that I’ve created royalty free. They may come in handy to you and your visitors and can be found on my site here

    http://www.spicypixel.net/2008/01/16/fontpack-royalty-free-bitmap-fonts/ and http://www.spicypixel.net/2008/01/10/gfxlib-fuzed-a-free-developer-graphic-library/

    If you’d like to collaborate on some free python games please get in touch, you have my email (free stuff of course).


  11. dissertationNo Gravatar Says:

    that’s actually a little to much “else” here. Pretend your creep would bounce at coordinates 0,0. You check to see if the x ordinate is lower than possible which would be true in our case.

  12. WZNo Gravatar Says:


    I’m a beginner to Pygame, and I’d like to thank you immensely for your series of tutorials. I’m going through them all slowly, trying out all the exercises you’ve provided.

    If it’s not too much, I have a question: what is a good way of doing Exercise (5) (2). I’ve tried several methods (for loops, temporary variables, etc), but they don’t seem to work, and I’m currently a bit lost.

    Thank you for your time.

  13. WZNo Gravatar Says:

    One more question also, if you don’t mind: For number (7), I commented out these:

    draw_pos = self.image.get_rect().move(self.pos.x, self.pos.y)
    self.screen.blit(self.image, draw_pos)

    … and I replaced them with:

    self.screen.blit(self.image, (self.pos.x, self.pos.y))

    I assume this is correct? However, I do not see any difference in the rotation. (Or at least, I do not know what I should be seeing.)

  14. elibenNo Gravatar Says:

    WZ, thanks for the feedback, I’m glad you’re enjoying the articles. Regarding your questions:

    For (5)(2). The creep has an internal counter and it gets update ‘ticks’ from calls to _change_direction. It can at random decide to “stop”. For that you can modify the internal self.speed variable to 0 for a second. When a second passes (a counter accumulates…) you can resume the speed to its past value.

    For (7) the change has to be done in function blitme(). Read the “Blitme!” section of the article once again, especially the explanation of centering.

  15. EricNo Gravatar Says:

    Hello, you’re so expert in Python. Would you write a blog system in Python. I have applied a appengine account at http://appengine.google.com/ and want to build a blog here. But there is no blog system can run on it. It only supports Pathon.

  16. SharonNo Gravatar Says:

    Hi eliben, I’m a fan of Python and considering writing a python CMS in the next one year. Your code is brilliant and I like your coding style.

  17. Arthur1989No Gravatar Says:

    Hello,I am a Chinese student from Sun Yat-Sen University,I have gone through this series of tutorials carefully,and it helps me a lot,thanks for your efforts!I am now wondering whether I can translate this series into Chinese and post it on my blog.I promise it will never be used for commercial activity.Looking forward to your reply.

  18. elibenNo Gravatar Says:

    Arthur, yes you can translate it into Chinese, no problems.

  19. AndrewNo Gravatar Says:

    just fyi, you have “advanced useD” where you want “useR” (except you don’t have/want that capitalization of course).

  20. elibenNo Gravatar Says:

    @Andrew, thanks – fixed.

  21. Joseph BleauNo Gravatar Says:

    First of all, thank you for the tutorial, some great tips in there. I was following along, implementing your concepts, and I ran into a bit of a snag. It seems that the longer my little creeps here frolic about, the more distorted they become, and shortly following, the application begins to slow to a crawl. I’ve identified it as being directly related to my transform.rotate(). I was hoping you could take a gander and enlighten me. :)

    Lines 50-52, when commented out, relieve the problem: http://codepad.org/xfkDuYO4

    Also, if you have any thoughts on my coding style, criticisms are welcomed.


  22. ArtNo Gravatar Says:

    Great tutorial! I have a question on finding the center of the box though.

    draw_pos = self.image.get_rect().move(
    self.pos.x – self.image_w / 2,
    self.pos.y – self.image_h / 2)

    When you call the Surface’s get_rect() command you create a rectangle starting at (0,0) with length and width the size of your image. Then you call the move function of the Rect class to position it at the ‘center’ of the image with those supplied x,y arguments.

    But arn’t pos.x and pos.y the top left corners of the image? So when you subtract the image dimensions from your position you end up being outside of your box? Above and to the left?

    Also in general, when you draw and specify points are you drawing the object with its top left corner at that specific point? I believe this is how its done in Java, so I am confused on basically where the image sits.

  23. elibenNo Gravatar Says:


    Thanks for the feedback :-)

    I think you should go over the section staring with “Blitme!” again. There I discuss why a creep is drawed at its center. self.pos always points at the creep center, which is why the shift is needed to draw it, since blit needs the top-left corner.

  24. MarsNo Gravatar Says:

    Hi Eli

    I fall in love with Pygame after reading this article. :) There is also a Traditional Chinese translation done:

    I will translate other Pygame articles in the next few weeks when I am available. Thanks for your detailed explanation.

  25. elibenNo Gravatar Says:


    Well done, thanks.

  26. PijusNo Gravatar Says:

    I’ve read in another pygame tutorial, that to properly exit pygame you have to call pygame.quit(), and only then call sys.exit(). I was having trouble quitting the creeps example until I changed the game quitting function into this:

    def exit_game():
  27. KyleDOTNo Gravatar Says:

    I think I might need some help, I’m using this tutorial to help make a game of my own where ‘Survivors’ run across the screen but I have been going back and forth between here and my code but there is something wrong my ‘Survivors’ aren’t showing up and I can’t figure out why. Below is my code
    class Survivor:
    def __init__(
    self, screen, img_filename, init_position,
    init_direction, speed):
    (50, width),
    (50, height)),
    (choice([-1, 1]),
    choice([-1, 1])),
    def blitme(self):
    draw_pos = self.image.get_rect().move(
    self.pos.x – self.image_w / 2,)
    self.screen.blit(self.image, draw_pos)

  28. Paul DuncanNo Gravatar Says:

    First off I want to thank you for the guide. It should prove to be useful for my dive into Python and my project of trying to write an old NES game in python as closely as possible before moving onto other things.

    “The rule of thumb is that anything 30 updates per second [2] or faster is good enough and looks smooth to the average person.”

    I want to clarify for people, that this applies to 2D games only. It is much harder in a 2D game to tell the difference after about 30. However in 3D games 30 is a *minimum* performance number to shoot for. The difference between 30 and 60fps in that regard is massive and silky smooth. There is little performance reason in a 2D game to limit things to 30, even if the jump to 60 is less apparent. 60 is practical and fits the refresh rate of of the vast majority of LCD screens people will be playing future developed py.games on. In short, the performance lost is negligible to the even slight visual improvement gained.

    Just my input as a gamer that *can* see the difference.

  29. KevinTranNo Gravatar Says:

    Nice post