Obsolete sprites API (V1)¶
Obsolete for new games. This guide is retained only for maintaining existing games that import
ventilastation.sprites. Itson_enter(),step(), andon_exit()lifecycle is not the VS2 lifecycle. Start new games with the VS2 tutorial. V1 games still run; this documentation change does not remove runtime support.
Ventilastation applications are built using the MicroPython language. This is a version of the Python programming language, but optimized in its resource and memory usage so it is able to run on microcontrollers like the ESP32 used by the Ventilastation fan blade.
Part I: setup and overview¶
Requirements: VSDK¶
To develop for Ventilastation you first need the SDK and the emulator running: follow the setup steps for your OS. Part of that installation is cloning the VSDK repository (the Ventilastation Development Kit).
One folder per game¶
Every game lives in its own folder, games/<group>/<name>/ — the group is
usually your name or the game jam it was made at:
code/— the game’s Python code; the entry file iscode/<name>.pyand must define amain()function returning the initialSceneimages/— PNG graphics plus the__images__.yamlthat describes themsounds/— music and sound effects (MP3)menu.png— the icon shown in the console menu (64×30 pixels)meta.json— menu placement (see Part V)
Other folders you’ll bump into: system/ holds the launcher and other
built-in apps, apps/micropython/ventilastation/ is the SDK runtime, and
apps/micropython/roms/ is where your PNGs get compiled to ROM files when
the emulator starts.
Running¶
./vs-emu.sh (or vs-emu.bat) regenerates ROMs and starts the desktop
emulator. Arrow keys (or W/A/S/D) move Joy1; Space/O/P/Y are Joy1 A/B/X/Y;
Page Up and Page Down are Start and Back. H/J/K/L plus Z/X/C/V provide Joy2,
and Home/End are Joy2 Start/Back. A USB gamepad works too.
To start one game straight away instead of walking the menu, name it:
./vs-emu.sh --game myname.mygame (group and folder, joined with a dot).
Leaving the game returns to the menu.
Part II: How to clone the simplest game¶
Let’s start by cloning a very simple game, ventap, as a new game called
mygame in your own group folder:
mkdir -p games/myname/mygame/code
cp games/alecu/ventap/code/ventap.py games/myname/mygame/code/mygame.py
cp -r games/alecu/ventap/images games/myname/mygame/images
cp games/alecu/ventap/menu.png games/myname/mygame/menu.png
In mygame.py, rename the class called Ventap to MyGame, including its
use in super calls and in the main() function at the bottom.
Ventilastation cannot directly open PNG images: the definition file
images/__images__.yaml describes how they become sprite strips. The one
you copied looks like this:
palettegroups:
palette1:
- strip: bola.png
frames: 12
- strip: target.png
frames: 5
- fullscreen: fondo.png
A strip is a horizontal filmstrip of equally-sized animation frames; a
fullscreen image is projected onto the whole circular display. Whenever
you run the emulator, changed PNGs are recompiled into
apps/micropython/roms/<group>.<name>.rom — for us,
myname.mygame.rom. Point your game at it by changing the class attribute:
class MyGame(Scene):
stripes_rom = "myname.mygame"
Finally, create games/myname/mygame/meta.json so the launcher places it
in the menu (an empty {} works too — the game then appears at the end):
{ "order": 15 }
That’s it: run ./vs-emu.sh and your game is on the menu. There is no
launcher code or menu asset list to edit — the launcher discovers game
folders and the menu ROM automatically includes every game’s menu.png.
Part III: Scenes and the director¶
Games and applications created for Ventilastation are composed of one or
more Scenes. These are a logical grouping of Sprites (defined in the
next section).
Scenes are managed with a singleton called the director, which handles
the stack of scenes via its push(scene) and pop() methods.
A scene can define an on_enter() method that gets called whenever the
scene is shown, and an on_exit() method that is called when the scene is
popped. Make sure to call super() when you define these methods, e.g.
super().on_enter().
After the scene is shown, the director will start calling your step()
method every 30 milliseconds. Your game logic usually goes in this method.
If you need some action to happen later in the future, Scene provides
call_later(delay, callable). The delay is in milliseconds, and
callable is any function or bound method. If the scene is finished via
director.pop(), all its pending calls are automatically discarded.
⚠️ WARNING: create all Sprites and other objects in your scene’s
on_enter() and reuse them as much as possible. Do not create and release
objects in step(): for performance reasons, garbage collection only
happens when entering or exiting scenes.
Input¶
JOY_LEFT,JOY_RIGHT,JOY_UP,JOY_DOWN,BUTTON_A,BUTTON_B,BUTTON_C,BUTTON_D— joystick constantsis_pressed(button)— True while the button or direction is heldwas_pressed(button)— True only on the step where it went downwas_released(button)— True only on the step where it went updirector.timedout— True after 30 seconds without any input; use it to return to attract screens (director.reset_timeout()restarts the clock)
Sound and music¶
Tracks are named <group>.<game>/<filename> after the MP3s in each game’s
sounds/ folder — you can also play another game’s sounds, which is why
you’ll see alecu.vyruss/shoot1 all over the place.
sound_play(track)— play a one-shot sound effectmusic_play(track, loop=False)— start a music track; withloop=Trueit repeats until stopped or replacedmusic_off()— stop the current music track
By default music stops when a scene is popped; set keep_music = True on
the scene class to let it continue.
Part IV: Ventilastation display and Sprites¶
New games should use the newer vs2 API. This section
documents the original ventilastation.sprites API because existing games and
older tutorials still use it. The original API remains supported for now, but
it is obsolete for new development. Existing games can continue using it.
The radial display of Ventilastation means that its pixels are not square but tiny arcs — we call them “arxels”. There are 54 LEDs from the center out, and 256 angular steps where LEDs can change colors. All of this is handled by optimized C code (or the emulators), so you don’t need to worry about it.
As a game developer you handle graphics through the Sprite class. Up to
100 sprites can be shown and animated at once.
Within a scene, sprites created first are drawn on top of sprites created later, so the order in which you create them matters.
from ventilastation.sprites import Sprite
Do not import ventilastation.sprites and vs2 from the same game. A game can
declare its intended API in meta.json with { "api": "vs2", "api_revision": 2 }.
Each Sprite has the following methods:
position:
set_x(int),x(),set_y(int),y()image:
set_strip(strip_number)— look the number up by name withstripes["bola.png"](from ventilastation.director import stripes)animation frame:
set_frame(int),frame()hide:
disable(); callset_frame()again to show itperspective mode:
set_perspective(int),perspective()size:
width(),height()collisions:
collision([sprites])— returns the first colliding sprite from the list, orNone
There are three “perspective modes”:
Mode 0: fullscreen images¶
Declared as fullscreen: in __images__.yaml. These are always centered;
Y scales them down from full size and X rotates them. Ventap’s planet is a
mode 0 sprite. Start from a 320×320 PNG with few colors (16–32
recommended) and hard on/off transparency — there is no alpha blending on
this display. See Vyruss’s Saturn for a transparent example.
Mode 1: perspective sprites¶
The most common mode: a “tunnel” perspective where objects use fewer LEDs as they approach the center, giving a scaling effect.
X is the angle: 0 at the bottom, 64 left, 128 top, 192 right, wrapping at 256. Y is the depth: 0 just outside the display, ~16 fully visible at the edge, up to 255 at the center.
The tutorial system app lets you move sprites of every mode around
interactively — the fastest way to internalize these coordinates.
Mode 2: non-perspective sprites¶
For images that shouldn’t scale, like scoreboards or the Game Over sign.
X is the same angle as mode 1; Y runs from 0 at the outermost LED to
54 - sprite height at the innermost.
Part VI: Submit your game to the Ventilastation project¶
Submit your game as a GitHub pull request:
Keep everything for your game inside its games/<group>/<name>/ folder —
if you find yourself needing to touch the SDK or launcher, open an issue
instead (or read internals/ and send that as its
own PR).