My Sincerest Apologies Tear-down

On Reddit I often see a variation of a conversation like this:

Newbie: I want to write games in Python!

Random person: Python is no good for games. You should use C++ or C#.

The claim that Python is not a good language to write games is not true. It's more accurate to say "Python is not a good language to write games alone."

It is well known that Python trades raw performance for productivity. But if you use it glue together powerful libraries written in faster languages then you can do better - you can have performance and productivity.

My Sincerest Apologies

In October 2017 Larry Hastings and I teamed up to enter the Pyweek Game Jam, and we won! Our game was a fast-paced 2D shooter with real-time lighting effects, called My Sincerest Apologies.

Here's a clip:

How did we write this in a week? With 3000 lines of Python code, but importantly, with four high-performance libraries.

Each one of these libraries is an independent project, written in its own way, but we were able to put them together in a game engine in our spare time in one week.

Pyglet

Pyglet provides bindings for OpenGL, sound, and input devices. As well as these it has higher-level capabilities for rendering 2D sprites and text.

Pyglet is written in pure Python using the ctypes module in the Python standard library.

Pyglet isn't the fastest OpenGL library around. However it gives you the tools to draw hundreds of sprites with very minimal cost, by arranging them into vertex buffers and handing them to OpenGL.

When you're using Pyglet you're mostly delegating all the hard work to your system's OpenGL drivers, and this is easily fast enough for writing many types of games.

All of the basic drawing we do in My Sincerest Apologies is done using Pyglet. We also use Pyglet to control the shaders, framebuffers and render passes needed for our lighting effects.

/2018/msa-pyglet.png

The base scene as rendered by Pyglet with lighting shaders turned off.

Lepton

Lepton is a venerable Python particle engine that I have recently taken maintainership of.

Lepton is written in C using the Python C API. Most common particle operations, such as forces, rotation, scaling and fading are performed in C under the control of Python. It also draws the particles using OpenGL.

Lepton means that we never need to actually access the particle data in Python. All we need to do is construct and modify Lepton's Emitter objects and let Lepton take care of everything else in fast C code.

/2018/msa-particles.png

Short-lived particle emitters are spawned wherever a railgun ray hits.

Pymunk

Most games need collision detection, and fast native code libraries are a great tool here too.

We used Pymunk, which is a Python library built around the Chipmunk 2D physics engine using CFFI.

Pymunk gives us a lot of the tools we need to create a 2D game. For a start it prevents the player character moving through walls. But it also gives us collision events that we can attach Python code to, such as when a bullet hits an enemy.

It lets us do ray queries to test for objects hit by our railgun rays. We get some great effects for free, such bouncing bullets or what happens when the player character collides with crates:

Lightvolume

Lightvolume is the most unknown of the libraries we used - because I wrote it during the competition!

Lightvolume handles the rendering of volumetric (2D) lights. You feed it geometry from Python and it implements the visibility algorithm described in this interactive article by Red Blob Games.

In fact it doesn't even implement this from scratch - it simply wraps the C++ implementation of the algorithm provided by trylock on Github! What a cheat, right? But this was very easy to wrap with just a little C/C++ code and CFFI again.

Lightvolume also takes care of rendering the lit area using OpenGL, meaning that again, we don't need to funnel data managed in a native code library back into Python. All we do with Python is feed in the lights and shadow casting objects, and set up shaders.

/2018/msa-lightvolume.png

A 2D lightvolume being rendered without shaders

Why not try it yourself in Pyweek 25?

That's what we did in Pyweek 24.

But if you read this article and thought "I'd like to have a go", then fear not! Pyweek 25 is happening in April 2018, starting on April 15th, and it's a great opportunity to try out some of these things for yourself.

Join us at pyweek.org!

Comments

Comments powered by Disqus