If you like Python and making games, graphics, or demos you might have reached for pygame, pyglet, pyOpenGL, or kivy in the past. The browser has been a far-off land for Python. This is a shame, I think, because graphics programming in the browser is a superior experience for experimentation: zero-installation and no drivers to mess with.
I’ve been thinking about how we could make game development in Python more accessible for everyone. The browser is a nice target because it handles the drivers and setup. The only question was how we could run Python code there.
There are options but one I had heard about and decided to spend an afternoon with recently was Brython. Brython is a Python interpreter written in Javascript. Instead of compiling a subset of the Python language directly into Javascript it implements a full Python interpreter and runs your Python code.
I was curious if this would affect game development and runtime. Python is much easier, in my opinion, to work in and teach than Javascript. If it’s not going to destroy the game play experience for the user then perhaps trading off a little run-time speed and startup for a faster, easier development process is worth it for small projects. Prototypes and ideas are definitely small enough to warrant such trade offs.
Our goal is a simple demonstration you can see below.
We want to animate a box moving on a sinusoidal wave along the y-axis and trailing the mouse on the x-axis while the mouse is within the canvas bounds.
The first step is to download and unzip the Brython archive in your
project directory. You don’t even need Python installed on your
system. From here on out, brython.js
is your Python.
Add a test.html
file to the Brython distribution and add the
following to it:
1 2 3 4 5 6 7 8 9 10 11 12 | <html>
<head>
<meta charset="UTF-8">
<script src="brython.js"></script>
</head>
<body onload="brython(1)">
<script type="text/python" src="test.py"></script>
<div id="game" style="width: 800; height: 500; margin: 0 auto;">
<canvas id="stage" width="800" height="500" style="width: 100%"></canvas>
</div>
</body>
</html>
|
That’s all there is to it. The important part to note is that we call
the brython()
function in the document body’s onload
attribute.
Once you call this function from your page, Brython can run Python
scripts… as we do on the next line.
So go ahead and create test.py
next to your test.html
and move on
to the next step.
Brython, fortunately, includes an API for interacting with the browser and interoperating with Javascript. For our purposes in this tutorial we’re just going to focus on the browser API.
Here are the imports you should put at the top of test.py
:
1 2 3 4 5 | from browser import doc
from browser.timer import request_animation_frame as raf
import math
import time
|
There are a some things here to notice. First being the browser
package. It includes modules for interacting with most (or perhaps
all, I haven’t checked thoroughly) of the browser APIs. The doc
module gives us access to the DOM. We use requestAnimationFrame
from
the timer
module to schedule our animation loop in the browser. And
at the end we have a couple of… Python standard library imports.
A note on the standard library in Brython: it’s there but the issue is
thorny. Brython ships with a good deal of the standard library. You
can import all of the usual suspects. However the import machinery on
the web uses ajax callbacks since the Javascript runtime doesn’t have
direct access to the filesystem. This can get really slow if you try
to import a module that imports other modules such as random
.
Brython provides a bundled single-file standard lib that you can include in your HTML file directly but it requires asking the user to download around 2MB of code first.
It might be possible to compile your own bundled standard library to slim down that 2MB of code but that is out of the scope of the discussion here. Read the Brython documentation on the import mechanism for more information.
This tutorial is going to be using the 2D-context of the canvas element. With Brython this is a simple matter of adding a couple lines of code:
1 2 | canvas = doc['stage']
ctx = canvas.getContext('2d')
|
We now have a JSObject instance that wraps the Javascript CanvasRenderingContext2d object. This interopability API allows us to call methods on Javascript objects as well as read and write their attributes.
This code is purely for demonstration purposes and is in no way meant
to be illustrative of best practices or serve as a guide. Consider
yourself warned. However it suits our purpose for exploring the
Brython Javascript interop API and getting our box on the screen. Add
the following code to test.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ticks = 0
x = 0.0
def mouse_moved(ev):
global x
new_x = ev.clientX - (canvas.width / 2) + 25
if new_x > 50 and new_x < canvas.width - 100:
x = new_x
canvas.bind("mousemove", mouse_moved)
def clear():
ctx.save()
ctx.setTransform(1, 0, 0, 1, 0, 0)
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.restore()
def draw():
global ticks
ticks += 1
clear()
y = (150 * math.sin(ticks / 50)) + 150
ctx.fillStyle = "blue"
ctx.fillRect(x, y, 100.0, 100.0)
ctx.fill()
def animate(i):
global id
id = raf(animate)
draw()
animate(0)
|
We can call all of the canvas commands you’d normally find in a Javascript tutorial. Except that it is in Python. And you didn’t have to install any interpreters, developer tools, libraries, or compile any extensions.
I’m not going to disparage Javascript but I do prefer Python. Current generation browsers provide a rich set of APIs for graphics, networking, media playback and documents. The added bonus is being able to share your code with others. It’s nice that we have the tools today to leverage those abilities from almost any language we prefer.
I will continue experimenting with Brython and Skulpt in the hopes that I can get a full-fledged game running on them. I agree with other people in the Python community that this language should be better at games and one of the more important platforms for games today is the web. I suspect that the approach Brython and others take might be the avenue by which we can bring Python to the client-side of the web.
Download Brython or Skulpt today and see for yourself how much fun it is.