Sept. 12, 2010

Hello!

Here is the build script which I use for deploying my apps such as Infinite8BitPlatformer on Windows and OSX. I have used it to build both Pygame and wxWindows apps in the past. "Cross platform" might be a bit of a misnomer; you need to run it on the environment you are targetting (e.g. be on Windows to build for Windows) and have the correct environment, libraries etc. installed, but the same script should work on both platforms.

For notes about installing Python libraries into somewhere other than the default Python root directory, see this earlier post.

Please pay attention to the comments marked NOTE.

### Cross platform (win32, mac) build script
### By Chris McCormick <chris@mccormick.cx>
### This has worked with pygame and wx
### This script is public domain

from setuptools import setup
from sys import platform, argv
import os
from shutil import rmtree, copytree
import zipfile

# NOTE: you may want to change these next few lines to set these values manuall
# get the current bzr version number of this build
from bzrlib.branch import Branch
revno = Branch.open(".").revno()
# get the name of the project/app from the name of the current directory
app = os.path.basename(os.getcwd())

# remove the build and dist directories
def clean():
    print "Removing build and dist directories"
    for d in ["build", "dist"]:
        if os.path.isdir(d):
            rmtree(d)

clean()

# the default os string and extension for each platform
platforms = {
    "darwin": ("osx", ".app", "dist/" + app + ".app/Contents/Resources"),
    "win32": ("windows", "", "dist"),
}

# more convenient representation of the platform config
config = {
    "os": platforms[platform][0],
    "extension": platforms[platform][1],
    "resources": platforms[platform][2],
    }

# NOTE: this is optional, you might want to remove this bit
# output the correct VERSION file for this build
print "Writing VERSION file"
version_file = file(os.path.join("resources", "VERSION"), "w")
version_file.write("%s\n%s\n%s\n" % (revno, config["os"], config["extension"] + ".zip"))
version_file.close()

### PLATFORM SPECIFIC SECTION ###

# mac osx
if platform == "darwin":
    # add mac specific options
    options = {
        # NOTE: you may want to put other libraries in here, such as wx for wxWindows apps
        # some libraries need forcing
        'includes': ['simplejson', 'pygame'],
        'resources': ['resources',],
        'argv_emulation': True,
        'iconfile': 'resources/icon.icns',
        'semi_standalone': False,
    }

    # force the py2app build
    argv.insert(1, "py2app")

    # setup for mac .app (does the actual build)
    setup(
        setup_requires=['py2app'],
        app=[app + ".py"],
        options={'py2app': options},
    )
elif platform == "win32":
    import py2exe

    # hack to include simplejson egg in the build
    import pkg_resources
    # NOTE: this bit is manually copying the simplejson egg into the current directory
    # you may want to manually import other libraries here
    # some libraries need forcing like this
    eggs = pkg_resources.require("simplejson")
    from setuptools.archive_util import unpack_archive
    for egg in eggs:
        if os.path.isdir(egg.location):
            copytree(egg.location, ".")
        else:
            unpack_archive(egg.location, ".")
            rmtree("EGG-INFO")

    # windows specific options
    options = {
        "script": app + ".py",
        # NOTE: assumes your icon is in a folder called resources and is called 'main.ico'
        "icon_resources": [(1, os.path.join("resources", "main.ico"))],
    }   
    resources = ['resources',]

    # force the py2exe build
    argv.insert(1, "py2exe")

    # setup for windows .exe (does the actual build)
    setup(
        setup_requires = ['py2exe'],
        windows=[options],
    )

    # manually copy resources as I couldn't get it to happen with py2exe
    for r in resources:
        print 'Copying resource "%s"' % r
        copytree(r, os.path.join("dist", r))

    # get rid of simplejson directory
    # NOTE: if you manually forced other libraries above you'll probably want to remove them here
    rmtree("simplejson")

### PLATFORM SECTION DONE ###

# zip up our app to the correctly named zipfile
def recursive_zip(zipf, directory, root=None):
    if not root:
        root = os.path.basename(directory)
    list = os.listdir(directory)
    for file in list:
        realpath = os.path.join(directory, file)
        arcpath = os.path.join(root, file)
        print "Zipping:", arcpath
        if os.path.isfile(realpath):
            zipf.write(realpath, arcpath)
        elif os.path.isdir(realpath):
            recursive_zip(zipf, realpath, arcpath)

outfilename = "%s-%d-%s%s.zip" % (app, revno, config["os"], config["extension"])
zipout = zipfile.ZipFile(outfilename, "w")
recursive_zip(zipout, os.path.join("dist", platform == "darwin" and app + config["extension"] or ""))
zipout.close()

# clean up afterwards
clean()

# output the build-finished message
print "--- done ---"
print "Created %s" % outfilename

You should probably use Esky instead of this script.

Aug. 18, 2010

FreePlay was absolutely stellar this year. This is my third FreePlay, and it's the third set of people organising the event/conference/festival here in Melbourne, Australia. Maybe it's a sampling bias, but to me it feels like there is something in the genetics of this thing that guarantees enjoyment. Just the right mix of "well organised" and "punk rock", it carries a delicious slice of the indie gaming zietgeist over here to Australia.

That's not to say that Paul and Eve don't have anything to do with how great it was. On the contrary, it remains so great because it has come to rest in such capable and nurturing hands. These guys are green-thumbed indie gardeners, ripening a plot of earth where many tiny seeds of ideas will end up growing into lovely games. And they are such incredibly nice people too.

A lot of the angst was gone this year. Many of us have left our jobs in industry and are doing that starving punk rock game developer thing. And it rules. The we-can-make-something-beautiful vibe was palpable. The inspiration and desire to create was so infections that I found myself reaching for the laptop to hammer out some code whenever I could, and so Infinite8BitPlatformer saw a few bugfixes and enhancements between sessions.

Just as it was a highlight meeting Jonathan Blow in 2007, for me a highlight of this year's festival was meeting Brandon Boyer and Adam Saltsman. Brandon and Adam each brought their own brand of energy and love for the art form. I only wish I had been around to hear Petri Purho speak last year too, all of whom highlight what a great job is being done of getting critical thinkers and practitioners over here each year.

Brandon's keynote was brilliantly emotive, and perfectly captured a sort of wistful energy for those games that don't yet exist, but could. He painted a brilliant, shimmering image of possibilities in front of our eyes, and lent us a powerful lust to coax our ideas into reality. When he pulled up a slide full of American indie record label logos from my youth, like Dischord, and Matador, and Calvin Johnson's K records, I felt a definite tugging on the heart strings, a flood of bittersweet memories, and this simultaneous realisation that hey, we are part of something as awesome as that whole thing was.

Adam got down and dirty in the semiotics of games and redefined in our minds the level at which games and play are part of our culture, and even our evolution, our genes. Conjouring forth papers on play and games from mid-century French intellectuals and the like, he was certainly showing tight research chops. At the beginning of the talk, "war came from games" sounded very contraversial to me. At the end of the talk I was convinced.

After hours the beer flowed, and of course that's where all of the most interesting, unrestrained conversations took place. Once again Eve and Paul's refinement shone through in their choice of venue, just around the corner from the library where the festival was going on. It's an oft-underlooked aspect of conference organisation, and usually left to the delegates to find a drinking hole where the ideas of the day can be unwound, probed, picked apart, and put back together again. At FreePlay however, this was all taken care of, and that was an excellent thing.

So anyway, there it is. Great festival, wonderful people, with the most awesomest of organisers.

Now it's time to create.

Aug. 8, 2010

This weekend I have competed in Simon Wittber's GameJam. It's been a fun couple of days and nights hanging out with other nerds, programming video games. I used my Javascript/HTML5 games library jsGameSoup which meant I got the first working iteration of the game up and running after about four hours on Friday night. Saturday afternoon I polished it and tweaked the game mechanic with some good suggestions from Jack, Simon, Nick, and Jason. This afternoon I spent a few minutes getting it online and fixing bugs.

Anyway, here is a link to the game, PingZinger. I would love to hear what you think!

The theme of the game was "choose two at the expense of the other," which should give you some clue as to how to play the game.

Have fun!

July 31, 2010

I am ridiculously behind on blogging because of the amount of contract work I have going on at the moment (working Saturdays and weeknights until 2am - not fun!) Anyway, I'll stop whining now.

Below is a video of the talk I gave at PyCon AU at the end of June. In it I talk about my time working for London based "reactive music" company, RjDj, and also about my video game Infinite8BitPlatformer.

I haven't posted an Infinite8BitPlatformer update for ages, and I have been meaning to do so since a lot of progress has been made since my last post, but here's a quick update:

  • Multiplayer code: this is going really well. It's almost at the point of beta release.
  • Contributors: another person has started contributing to the codebase. I am hopefully going to be merging his code this weekend. Julian has put basic chat into the multiplayer code, among other tweaks and bugfixes, and a huge amount of very useful information for other people looking to contribute. He's been very patient about my lack of time!

Anyway, back to work.

July 11, 2010

I've started a new album. It is called squeakyshoecore. It is algorithmically generated acid using some software I wrote. I am going to release it online bit by bit, as I finish each track. I will announce each new track here on this blog.

squeakyshoecore logo

squeakyshoecore

The software makes two different beats and two complementary melodies using random number generators and some carefully tuned algorithms for using those random numbers. The melody shaping rules involve applying a low dimensional random fractal effect on very basic seed melodies, producing a type of self-similarity which seems to sound interesting to humans. The beats are created using a variety of custom rule sets, much like my previous work with algorithmic hip-hop in CanOfBeats and my algorithmic drum-and-bass generator, GhostWave.

After that I manually control how loud each of the parts are present in the mix, what effects are being applied to the different parts, and the parameter values of those effects. I use a midi controller to mix it in real time and record it.

Soon I will make the latest version of the Pure Data patches ("GarageAcidLab") available online under a Free Software license.

Enjoy the first tracks!

P.S. Some other music I've released on the net previously is Cryptolect, end-of-millenium style chopped-up breakbeats.