In yr code twiddling yr bits

June 30th, 2007

Added a few functions to gameobjects.util that seemed worth sharing. The first two are two-dimensional versions of range and xrange. When iterating over something 2 dimensional (such as pixels in an image) you typically have an outer loop for the y coordinate, and an inner loop for the x coordinate. The range2d and xrange2d functions combine these two loops in to one and take range iterables as parameters.

def range2d(range_x, range_y):

    """Creates a 2D range."""

    range_x = list(range_x)
    return [ (x, y) for y in range_y for x in range_x ]

def xrange2d(range_x, range_y):

    """Iterates over a 2D range."""

    range_x = list(range_x)
    for y in range_y:
        for x in range_x:
            yield (x, y)

Here's how you might use range2d to iterate over the coordinates in an image.

for x, y in range2d(xrange(width), xrange(height)):
    #Do something with x, y

The xrange2d function returns a generator rather than a list, but works the same.

Next up we have two functions to help with power of two textures; is_power_of_2 returns True if a given value is a power of 2, and next_power_of_2 returns a power of 2 that is greater than or equal to a given value. These may be useful if you are working with OpenGL which requires power of 2 textures. I know newer versions of OpenGL support non-power of 2 textures, but it is a good idea to stick to power of 2 dimensions for compatibility.

def is_power_of_2(n)
    """Returns True if a value is a power of 2."""
    return log(n, 2) % 1.0 == 0.0

def next_power_of_2(n):
    """Returns the next power of 2 that is greater than or equal to n"""
    return int(2 ** ceil(log(n, 2)))

There is actually bit-twiddling magic that could replace both of these functions, but I don't want to make any assumptions about which is faster in Python. The bit-twiddling code to calculate the next power of 2 is particularly suspect. It may generate just a dozen or so instructions in C, but I suspect that the Python overhead would make it slower than doing the float math. I may be wrong, but I lack the motivation to do the tests. The following is C *spit* code to find the next power of 2.

unsigned int v; // compute the next highest power of 2 of 32-bit v

v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;

If you are going for a job interview in the games industry, memorizing that code may be worthwhile, but you will never need it again!

Ok. Thats your lot. Go play nicely.

 

loltriops

June 19th, 2007

Normally I detest Internet phenomenas - I still don't know what that 'all your bases' nonsense was about. So I apologise in advanced for having stooped so low as to contribute to the current internet fad. For your viewing pleasure, here are the first two 'loltriops'.

Update: I guess that should be loltriopz. loltriop2 loltriop1
 

Master time with PyGame

June 15th, 2007

A novice games programmer learns he can move a sprite by adding a constant to its position every frame. For a while he is happy and mocks the master games programmer for having wasted many years learning. But soon the novice realises his sprites are unpredictable and move at different rates on different machines. The novice is despondent and visits the master for advice.

"Master. Why do my sprites not obey my commands? They jump when I ask them to slide."

"Frame rate is like the wolf, it can not be tamed", replies the master.

The novice returns to his code and a revelation comes to him. "I must move my sprites with the frame rate!" The novice changes his sprite code to move a distance relative to the time since the previous frame, and his sprites become at one with the frame rate. "I must truly be a master", thinks the novice.

For a while the novice is happy, and produces many simple games. But as the novice's logic gets more complex he is faced with a problem. "My game updates are tied to the frame rate!", thinks the novice. He realises that his game will run differently on other machines and yearns for the simpler days when he thought frame rate was constant. Despondent, he visits the master for advice.

"Master. How can I make my game run predictably on all machines?"

"Time is not rigid as a tree. Time is supple, as a reed", replies the master.

The novice goes back to his code and ponders the master's advice. A revelation comes to him, "Game logic can run in it's own time!" With that thought in mind, he separates his game logic from the render code and soon his game logic runs independently of the frame rate.

The novice is humbled and thanks the master for his help.

"Truly, you are a master now", replies the master.

To become a master you can either meditate in a cave in Tibet or use the GameClock class in the Game Objects library. GameClock manages game time, which marches on at a perfectly constant frame rate, no matter how many frames you can actually render. The main advantage of this approach is that the game will run the same on a fast computer, as it does a slow computer, which is extremely useful for recording demos or adding network play. It also makes the math for moving sprites (2D or 3D) a little simpler, because you can just add constants each frame.

Here's a snippet from the example project that shows how to separate the render loop in to an update phase and a render phase. The call to game_clock.update is an iterator that returns the frame count and time for each game logic update. It will return as many updates as necessary for game time to 'catch up' with the real time.

# Update phase
        for frame_count, game_time in game_clock.update():

            for ball in balls:
                ball.update()

        # Render phase
        for ball in balls:
            ball.render(screen)

The update function calculates the position of the sprite at the current update, and the position it will be at the next update. This is because the render phase will likely occur at some point between game logic updates, and the render position should be adjusted proportionally. The method get_between_time returns a value between 0 and 1 that you can use to interpolate value between two game logic updates.

For example, if the sprite contains its current position (self.position) and its position at the next update (self.next_position), then you could find the render position with the following code (lerp is a function in gameobjects.util).

x, y = lerp( self.position,
                     self.next_position,
                     game_clock.get_between_frame() )

So what is a good rate for the game logic update? In my experience 20 logic updates per second is about right for most games. You can increase this rate if you want finer control, but it is probably not a good idea to go much lower as it will reduce the responsiveness of the game.

An additional advantage of GameClock is that you can control the speed of time with little effort. If you call game_clock.set_speed(0.5), then half as many game logic updates will be issued and the game will run at half speed. You can also make the game run faster by setting the speed to a value greater than 1.0. Alas, you can't set the speed to a negative value, as this would violate the laws of the cosmos.

You can experiment with the game logic update rate and time speed with the GameClock sample code. You will need PyGame of course, and Game Objects 0.0.2. Game Objects can be easy installed with the command: easy_install gameojects.

Download GameClock sample code

Here's a screenshot of the sample code running. I really must try to write samples that don't feature shiny spheres!

gametimesample
 

Game Objects Commandments

June 7th, 2007

I've moved Game Objects to Google Code. It's new home is http://code.google.com/p/gameobjects/. There are source and Win32 packages available.

Game Objects is intended to be a collection of classes to assist with the creation of games, or other realtime applications. Currently there is a 2D and 3D Vector class, and a well optimized 4x4 Matrix class, but eventually Game Objects will contain code for general route finding, entity management, AI and other cool stuff. I'm happy to take suggestions, and if you would like to submit code - even better! All classes should following these commandments.

  1. Easy to use. Thou shalt be no more complex than absolutely necessary, and thou shalt protect the user from doing stupid things.
  2. Fast. Thou shalt be fast, unless it comes in to conflict with 1.
  3. Pure Python. Thou shalt be in pure Python. Optimized C versions may exist as long as the interface is identical.
  4. Few dependencies. Thou shalt not require external modules, other than the standard library. External modules may be optional if they increase performance.

Current version is 0.0.1, but don't let the low version scare you, the current classes are quite stable. Most of my previous little PyGame experiments have used old versions of Game Objects, so I have ironed out most of the kinks. I plan on putting together a collection of samples, so there is something to play with. Any suggestions for interesting projects that make use of Game Objects will be gratefully received.

Update: I have created a Google Group for discussion of Game Objects (http://groups.google.com/group/gameobjects).
 

OpenGL sample code for PyGame

June 4th, 2007

I've uploaded a simple example of how to use OpenGL with PyGame. It's a listing from my forthcoming book, Beginning Game Development with Python and PyGame, and demonstrates how to initialize OpenGL, create a light and draw a simple 3D 'world'. It also shows how to use the camera matrix to create a simple 'fly-cam'.

To run it you will need PyOpenGL, which you can download from the website, or from the command line if you have Easy Install (type easy_install PyOpenGL). Use the cursor keys to look around, and the Q/A keys to move forward and back. You can also press Z and X to roll the camera.

Download simpleopengl.py

Here's a screenshot.

pyg3d

I'm impressed by the ease of using OpenGL with PyGame. It's a one liner to create an OpenGL display, and the OpenGL bindings work well. With good use of display lists or vertex arrays, performance can be on par with commercial games. To put it in perspective, you could render an entire 3D object in less time it takes to draw a simple 2D sprite. I hope people take advantage of it, because the 'casual games' market is huge right now, and Python could give developers a serious advantage in getting games to market quickly!

Update: I experimented with recording the demo using Fraps, which worked rather nicely - I may even consider buying it! I didn't realize it was recording audio though, or I may have chosen a different soundtrack (it recorded a portion of mp3 I was listening to). Hope nobody sues me. Here's the a video of the demo.
 

BBCode module moves to Google Code

June 3rd, 2007

Postmarkup, my BBCode parser module now has a new permanent home on google code (http://code.google.com/p/postmarkup/). It's more than adequate for my needs now, just wish I had time to work on my TurboGears site! I thought I would have more spare time since becoming a full time Python contractor, but I'm as busy as a... sorry, too busy to think of similie.

 

Proud parent

June 1st, 2007

The triops are just over 2 weeks old now, and as cute as a button. Tragically one hatchling died a few days ago, but the 7 that are remaining are doing well. Have a look at the photos.

Close up of a triop

(not actual size)

 
Search for Posts
2013
 
2012
 
2011
 
2010
 
2009
 
2008
 
2007
 
2006
 
 
© 2008 Will McGugan.

A technoblog blog, design by Will McGugan