Skip to content
Experimental game framework with OpenGL 4, Pygame 2, and numpy
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
docs Use online packer for sprites Aug 18, 2019
examples Add per-layer post-processing effects Sep 11, 2019
fonts Allow updating the text of a label Aug 19, 2019
images Commit missing smoke image Aug 30, 2019
sounds Wire up sound loader Aug 9, 2019
tests Extract buffer allocators from VAO class Aug 29, 2019
.flake8 Import some tests from Pygame Zero Aug 10, 2019
.gitignore Don't cache Pygame Surfaces in the loader Aug 18, 2019
LICENSE Fix license, must be LGPL as uses code from Pygame Zero Aug 12, 2019 Import some tests from Pygame Zero Aug 10, 2019 Update README with the new features Aug 19, 2019
requirements Allocator to manage blocks of a buffer object Aug 10, 2019
requirements-dev.txt Import some tests from Pygame Zero Aug 10, 2019
requirements.txt Allow updating the text of a label Aug 19, 2019 Import some tests from Pygame Zero Aug 10, 2019
tox.ini Import some tests from Pygame Zero Aug 10, 2019

Wasabi 2D

A fledgling 2D graphics engine for Python, based on moderngl, with pygame 2.0 for some supporting functions.

Screenshot as of 2019-08-14

Current features include:

  • Sprite loading and rendering
  • Rendering of text labels
  • Stroked and solid-filled polygons, circles, stars, and rectangles
  • Rotate, scale and move any of the above
  • Sounds, keyboard and mouse events, animation/tweening, music, clocks and local storage from Pygame Zero (with most magic removed).


Use pip to install the dependencies in requirements.txt.

pip install -r requirements.txt

Initialising a scene

The Scene class holds all the renderable state. Initialising it will create a window with the provided dimensions and set it up to be drawn.

from wasabi2d import event, run, sounds, Scene, Vector2

scene = Scene(1600, 1200)

At the bottom of the file, call run() to actually run the game:


One attribute of interest is scene.background. This is the background color of the entire scene as an RGB triple. (1, 1, 1) is white and (0, 0, 0) is black.

Coordinate system

Unusually for an OpenGL-based game engine, wasabi2d uses Pygame's coordinate system where the top of the screen has coordinate 0 and coordinates increase downwards.

This allows easier porting of Pygame Zero games.


The camera is controlled by In particular, camera.pos is the center position of the camera. Initially, this is (scene.width / 2, scene.height / 2).

Creating a sprite

scene.layers is an automatically initialised sequence of layers. These are drawn from lowest to highest.

To create a sprite in a layer just call .add_sprite():

ship = scene.layers[0].add_sprite(
    pos=(scene.width / 2, scene.height / 2)

Sprites must be in a directory named images/ and must be named in lowercase with underscores.

A sprite object has attributes that you can set:

  • .pos - the position of the sprite

  • .angle - a rotation in radians

  • .color - the color to multiply the sprite with, as an RGBA tuple. (1, 1, 1, 1) is opaque white.

  • .scale - a scale factor for the sprite. 1 is original size.

  • .image - the name of the image for the sprite.

And these methods:

  • .delete() - delete the sprite.

Specifying colors

Colors can be specified to any object using the attribute color. There are many ways to specify color:

  • tuples of 3 or 4 floats between 0 and 1 - RGB or RGBA, respectively. If 3 numbers are given then the alpha value will be 1 (ie. opaque).
  • Pygame color names like white, yellow etc,
  • Hex RGB or RGBA color codes like #eecc6688

Creating circles, stars, polygons

Adding shapes to the scene follows a similar API - simply pick a layer number to add to and pass the appropriate parameters.

In general you can set these values as attributes on the returned shape.

Common attributes:

  • pos - 2-tuple - the center point of the shape
  • fill - bool - if True, the shape will be drawn filled. Otherwise, it will be drawn as an outline. This cannot currently be changed after creation.
  • color - a color, as described above.
  • angle - a rotation in radians
  • scale - a scale factor for the shape. 1 is original size.


Create a circle. Takes these additional parameters.

  • radius - float - the radius of the circle


Create a star. Parameters:

  • points - int - the number of points for the star.
  • outer_radius - float - the radius of the tips of the points
  • inner_radius - float - the radius of the inner corners of the star


Create a rectangle. Parameters:

  • width - float - the width of the rectangle before rotation/scaling
  • height - float - the height of the rectangle before rotation/scaling


Create a closed polygon.

  • vertices - sequence of (float, float) tuples. The vertices cannot currently be updated after creation.


wasabi2d supports text labels. The fonts for the labels must be in the fonts/ directory in TTF format, and have names that are lowercase_with_underscores.


Create a text label.

  • text - str - the text of the label
  • font - str - the name of the font to load
  • fontsize - float - the size of the font, in pixels. The actual height of the characters may differ due to the metrics of the font.
  • align - str - one of 'left', 'center', or 'right'. This controls how the text aligns relative to pos.

Handling events

The @wasabi2d.event decorator registers event handlers. The name of the function is important; the function

def on_mouse_down():

will be called when the mouse is clicked.

The methods are exactly as described in Pygame Zero's documentation, parameters and all.

There is one exception: update() now takes an optional keyboard parameter, as this is the normal place you would consider keyboard state.

For example:

def update(dt, keyboard):
    v = 20 * dt

    if keyboard.right:
        alien.pos[0] += v
    elif keyboard.left:
        alien.pos[0] -= v
    if keyboard.up:
        alien.pos[1] -= v
    elif keyboard.down:
        alien.pos[1] += v
You can’t perform that action at this time.