Archive for August, 2006

Live Coding, Continued

Erik on Aug 29th 2006

I have spent some time on further experiments with live coding and it seems to get tricky when you start using state. If you are loading and executing all of your code every frame, how do you handle tasks like animation? How do you load an image and cache it so you don’t have to reload every frame?

One approach I played with, just for fun, was animation without maintaining any state information. I have slightly expanded on my previous controller script. The major differences are that my new version will now print a stack trace if the current exception is different from the last exception. With the old script, if you eliminated one exception from your code, but a second exception prevented execution, no stack trace would be displayed. Also, this controller passes the livegame script the frame count when it calls play. You can view the updated script here: controller_stateless.py.

Here is my livegame_stateless.py:

fps = 30
screenWidth = 640
screenHeight = 480

# check to see if the pygame module is in the namespace
try:
    pygame
except NameError:
    # pygame doesn't exsist, so import it.
    # this only happens once.
    import pygame
    from pygame.locals import *

    # initialize the pygame display
    pygame.init()
    pygame.display.set_mode((screenWidth,screenHeight),0,32)
    display = pygame.display.get_surface()

    # initialize the pygame clock
    clk = pygame.time.Clock()

def getMotion(framecount, shapeSize, screenSize, velocity):
    """
        Calculates a linear position using a step number, a
        velocity, and a derived range of motion.

        Returns the position.
    """

    # calculate the range of motion:
    workingSize = (screenSize - shapeSize) / velocity

    # use mod to find position in the range of motion.
    # *2 is used to bounce back and forth inside the range
    pos = framecount % (workingSize * 2)   

    # if we are greater than the initial size, we are moving
    # in the opposite direction.
    if pos > workingSize:
        pos = 2*workingSize - pos

    return pos * velocity

def play(framecount):
    """ Main game logic, called once per frame."""

    # fill the display with black.  Clears the screen.
    pygame.draw.rect(display, (0,0,0,255),(0,0,screenWidth,screenHeight))

    shapeColor = (10,80,10,255)
    shapeWidth = 30
    shapeHeight = 30

    xVel = 10.0 # velocity in pixels per frame
    yVel = 10.0

    x = getMotion(framecount, shapeWidth, screenWidth, xVel)
    y = getMotion(framecount, shapeHeight, screenHeight, yVel)

    # draw a shape.
    pygame.draw.ellipse(display, shapeColor,(x,y,shapeWidth,shapeHeight))

    # update the display.
    pygame.display.flip()

    # check for events, and return true if we get an exit signal.
    events = pygame.event.get()
    for event in events:
        if event.type == QUIT or (event.type == KEYDOWN
                                    and event.key == K_ESCAPE):
            return True

    # try to maintain a set frame rate.
    clk.tick(fps)

    # No exit signal was recived, so return false.
    return False

This code isn’t truly stateless. I use the Pygame module loading to do some Pygame initialization and window setup. Even this could be removed, but you would need a very fast machine to be able to recreate the pygame window every frame at a decent framerate. I’ve tried it though, and it is pretty cool to be able to change your window size mid run by tweaking your initialization parameters.

The animation produced by this code is stateless. And the code was surprisingly easy to write. It would be interesting to see how far you could push this approach. I think that it would rapidly become impossible to work with, as any sort of complex program would need to be passed all of the previous user input as a parameter to the play function. While it would be interesting to try to write a game that constantly derived it’s state from a time coded array of past user input, I doubt it would be fruitful. I suppose games like chess could read a board state and return a new board state every frame. Its great, from a mental exercise point of view, but I expect a dead end productivity wise.

Caching

So, onward to the next approach. Caching. This essentially boils down to having some code that isn’t run every frame. For example, if I wanted to move a box across the screen, I could use some special code to initialize it’s x position to 0, and then the live code that runs every frame increments the position by 1. You rapidly run into problems with this approach though. For some interesting reading on the topic of state and live coding, take a look at this reddit comment.

When I started working on this approach, I immediately ran into problems where my initialized state wasn’t in sync with my live code. To expand on the box moving example, lets suppose that I want to add a second moving box. So I add a line of code to the initialization section that sets x2 to 0, and I add my code to the live section to increment x2 by 1 every frame. Should work, right? Nope. If you do this while the code is live, you get an exception because x2 was never initialized, because the init code hasn’t been re-run since you added x2. I don’t have a solution for this that I am really happy with, but I have a couple of hacks that go a long way towards eliminating this problem. One is having ‘r’ keypresses call the init function. This helps a little. You could add x2 to the init, save, press ‘r’, add x2 to the live segment, and save again. But that sucks. The other hack I added was to the controller. I put the controller in charge of the initialization function at start up. Also, if the controller encounters an exception when calling play() on the livegame, it attempts to call the init function, to see if resetting the system will resolve the exception. I’m not really happy with my implementation, but you can take a look at it here: controller_hackish.py.

Here is the corresponding livegame_hackish.py. To run this, you will need an image. I use my pixel art alien:

Eye Alien

fps = 30
width = 640
height = 480

import random

class Alien:
    """
       Effectivly a very simple sprite class, with it's properties
       defined in it's init code.
    """

    def __init__(self):
        self.alienImage = pygame.image.load('eyealien.png')
        self.alienImage.convert_alpha()

        self.pos = [50,50]
        self.direction = [1,1]

        self.velocity = [2.5, 2.5]

    def draw(self, display):
        display.blit(self.alienImage, self.pos)

    def update(self):
        """
            Update is called every frame.
            Adjust the alien's position based on it's
            velocity.
        """

        if self.pos[0] > ( width - self.alienImage.get_width() ) \
                or self.pos[0] < 0:
            self.direction[0] *= -1

        if self.pos[1] > ( height - self.alienImage.get_width() ) \
                or self.pos[1] < 0:
            self.direction[1] *= -1

        self.pos[0] += self.velocity[0] * self.direction[0]
        self.pos[1] += self.velocity[1] * self.direction[1]  

# Ugh, has to be global because it is initialized in a function
# and used in a different scope.
global alien

def initState():
    """
        Called by the controller, used to initialize variables
        and objects that maintain state.
    """
    global alien

    alien = Alien()

# check to see if the pygame module is in the namespace
try:
    pygame
except NameError:
    # pygame doesn't exsist, so import it.
    # this only happens once.
    import pygame
    from pygame.locals import *

    # initialize the pygame display
    pygame.init()
    pygame.display.set_mode((width,height),0,32)
    display = pygame.display.get_surface()

    # initialize the pygame clock
    clk = pygame.time.Clock()

    initState()

def play():
    """ Main game logic, called once per frame."""
    global alien

    # fill the display with black.  Clears the screen.
    pygame.draw.rect(display, (0,0,0,255),(0,0,width,height))

    # draw a shape.
    pygame.draw.ellipse(display, (180,40,200,255),(200,160,100,50))

    # move the alien
    alien.update()

    # draw the alien
    alien.draw(display)

    # update the display.
    pygame.display.flip()

    # check for events, and return true if we get an exit signal.
    events = pygame.event.get()
    for event in events:
        if event.type == KEYDOWN and event.key == K_r:
            # reinitialize the program state.
            initState()
        if event.type == QUIT or (event.type == KEYDOWN
                                    and event.key == K_ESCAPE):
            return True

    # try to maintain a set frame rate.
    clk.tick(fps)

    # No exit signal was recived, so return false.
    return False

The above code loads an image, and uses an object in a way that maintains state across frames. There are a few things that I don’t like about it though. One is the globals. I had to make my alien object global, because I initialize it in a function and then use it outside of that function’s scope. It’s ugly, and I don’t know if python offers a better way to do it. The other problem is related to the contents of the reddit comment I linked to above. When my alien object is initialized, it captures the code of it’s methods. Which means that the method code is not live. If you change the Alien.draw() method for example, the change doesn’t take effect when you save the file. You must reinitialize the system to get an alien object that uses the new code. It’s possible to work with this, but it doesn’t fit with the spirit of keeping everything ultra-dynamic for live coding.

It would be really nice if a Python guru could just hand me a framework that addressed all of the problems, and made live coding a completely painless process. I really think this sort of thing could make for an amazing game development environment. I just wish I had more free time to work through the quirks.

Not on the topic of live coding, but still along the lines of game development and python dynamism, I recently discovered a Python project called Bruce the Presentation Tool. I don’t know much about it, buy one feature caught my eye. It has an interactive Python shell running inside a Pygame window. I imagine that this could be very useful for introspection when working with Pygame. In the past I’ve had a lot of success with using a keystroke to spawn an iPython shell in the console window I’ve launched my game from. It’s extremely useful for debugging and experimentation. I imagine that a deeper embedding of the shell might be even better.

Filed in Games, Programing | 2 responses so far

Live Coding Games in Python

Erik on Aug 2nd 2006

Reddit recently lead me to Logan Koester’s blog post about live coding with Python, and I found it fascinating. Live Coding is the practice of editing code for a running program in an environment that loads in the changes as they are made. Apparently people do this as a performance art, writing programs on the fly to play music. There is even a Wikipedia article on live coding.

I tried out the examples on Logan’s page, generated some weird drum loops, and had some fun with it all. The experience was a reminder that I want to learn how to make music. But it also opened my eyes to what seems like a new approach to programming.

After 30 seconds of looking I have failed to find a good reference on this, but I have read that a major factor in programmer productivity is the turnaround time between editing code and testing the results. If you are working on big project with a slow build process making changes takes a long time. Because changing too many things at once is a bad idea, you have to spend a lot of time waiting to test your code. If you are working on a small project in a scripting language, then it’s just save and run with little waiting to see the results of your edits.

What if we take this a step further? Are there productivity gains to be found through live coding, where you see the results of your changes when you save the code? I’ve decided it’s a neat idea, and I want to explore it. Since most of my programming focuses on game development, I tried out live coding with PyGame. What can I say? Recompiling your game’s codebase every frame strikes me as a wonderful way to trade cpu cycles for increased programmer productivity.

The first step is building the controlling script that does the live coding magic. I started with Logan’s example, but I wanted to do a couple of things differently. The first is I wanted to see a message and a backtrace for both syntax and runtime errors. The second is that I wanted the host and the client to be largely independent. Here is my controller.

controller.py:

import traceback
import StringIO

from time import sleep

done = False
imported = False
loadBroken = False
runBroken = False

def genTraceback(ErrString):
    """ Takes an error message as an arguemnt.
        Generates a traceback of the most recent
        exception, and prints it with the error
        message.  Sleeps for 2 seconds before
        returning.
    """
    fp = StringIO.StringIO()
    traceback.print_exc(file=fp)
    message = fp.getvalue()

    print ErrString,"\n", message
    print "\nFix livegame.py to continue.\n"

    sleep(2) 

# loop until we sucessfully import livegame.py
while not imported:
    try:
        import livegame
    except:
        if not loadBroken:
            genTraceback("Failed to import livegame.py.")
            # set a flag so that the traceback is only printed
            # once
            loadBroken = True
    else:
        imported = True

# loop until livegame.play() returns True
while not done:

    # attempt to reload the code
    try:
        reload (livegame)
    except:
        # if the reload fails, print the traceback once.
        if not loadBroken:
            genTraceback("livegame.py is broken.")
            loadBroken = True

    else:
        loadBroken = False

        # if the reload is succesful, try to run livegame.play()
        try:
            done = livegame.play()
        except:
            if not runBroken:
                genTraceback("play() in livegame.py is broken.")
                runBroken = True

        else:
            runBroken = False

Sorry for the \" silliness in the above code. It seems to be a wordpress bug. Anyway, what the above code does is load livegame.py and then reload it in a loop, calling livegame’s play function every time. Thanks to the traceback and StringIO modules, it outputs both syntax and runtime error tracebacks to the console seamlessly.

Here is a very basic livegame.py:

fps = 10
width = 640
height = 480

# check to see if the pygame module is in the namespace
try:
    pygame
except NameError:
    # pygame doesn't exsist, so import it.
    # this only happens once.
    import pygame
    from pygame.locals import *

    # initialize the pygame display
    pygame.init()
    pygame.display.set_mode((width,height),0,32)
    display = pygame.display.get_surface()

    # initialize the pygame clock
    clk = pygame.time.Clock()

def play():
    """ Main game logic, called once per frame."""

    # fill the display with black.  Clears the screen.
    pygame.draw.rect(display, (0,0,0,255),(0,0,width,height))

    # draw a shape.
    pygame.draw.ellipse(display, (0,40,200,255),(200,200,100,50))

    # update the display.
    pygame.display.flip()

    # check for events, and return true if we get an exit signal.
    events = pygame.event.get()
    for event in events:
        if event.type == QUIT or (event.type == KEYDOWN
                                    and event.key == K_ESCAPE):
            return True

    # try to maintain a set frame rate.
    clk.tick(fps)

    # No exit signal was recived, so return false.
    return False

The first time this code is run, it initializes PyGame and creates a window. Every time play is called, it clears the window, draws a blue ellipse, checks for events, and then sleeps long enough to try to maintain a set framerate. If you press the escape key livegame signals the controller script, and the controller exits. To see where things get interesting, change this line:


pygame.draw.ellipse(display, (0,0,255,255),(200,200,100,50))

to something like this:


pygame.draw.rect(display, (255,0,0,255),(200,200,200,100))

Save the change with the PyGame window open beside your text editor, and watch the small blue ellipse instantly turn into a larger red rectangle. A basic example, I admit. But it hints at very deep potential.

The next step is taking this live environment, and building a full game using it. I intend to give it a try, hopefully soon. It will take some cleverness to keep things both dynamic and running fast enough. I might have to set up some sort of caching system so that expensive operations, such as loading an image or level from disk, don’t happen every frame. I could perhaps bind a key so that the expensive stuff is only done on request, but I think the experiment will be most interesting if I keep that sort of thing to a minimum.

There are obvious improvements to the above code that could be made, but I wanted to keep things as simple as possible. Though I do want to add more features before I make an attempt at building something significant using the live environment. I hope to modify the controller so that it takes the name of its client as a command line argument. I would like it if the controller gave some sort of audible notification if the client code caused an exception and produced a new traceback. I will see if I can use Ipython’s handy syntax highlighting for the controller’s tracebacks. It would also be neat to modify the client code to use the python if name == '__main__' trick. Then the client could optionally run as an independent program without the controller. This would also allow changing settings such as the target frames per second based on the environment the code is running in.

If I haven’t stated it enough already this post: this approach opens up lots of interesting possibilities. The only downside is that some day I’m going to start writing flash games that run directly in the browser. When I do that, I’m really going to miss all this dynamic language magic that I’m learning to use with Python.

Edit: I’ve posted an update, Live Coding, Continued

Filed in Games, Programing | 9 responses so far