Display, input, audio and base

Four module-level singletons, plus the button constants in vs2.controls.

vs2.display

Display geometry and palette animation.

display.width = 256
display.height = 54

On the rotor width is 256 and height is 54, but read them rather than hard-coding. height is the LED count, which is the Y range of a vs2.HUD layer only; see the circular display.

Palette animation

Recolouring the loaded palette is the cheapest effect a POV display has: one buffer write tints every sprite drawn from that palette group.

vs2.display.palettes

The loaded palette block, as a mutable buffer, or None.

This is the same buffer the asset bank loaded, so recolouring in place allocates nothing. Call vs2.display.apply_palettes() to publish the change. The buffer is replaced whenever a new asset pack loads, so resolve it in vs2.Scene.build() like any other asset handle.

display.apply_palettes()

Publish the current contents of vs2.display.palettes to the renderer.

Cheap enough to call every tick, which is what a colour-cycling effect wants:

def build(self):
    self.palettes = vs2.display.palettes

def update(self):
    cycle(self.palettes)
    vs2.display.apply_palettes()

vs2.controls

The two controllers and their buttons.

Designed for a star import, which is why __all__ is exactly the two controller views and the ten button constants:

import vs2
from vs2.controls import *

if joy1.held(LEFT):
    ...

Qualified access works too, and is how you reach idle_ms, which the star import deliberately leaves out.

This is a real module rather than a synthetic object so MicroPython’s IMPORT_STAR can safely implement the documented from vs2.controls import * form.

Reading a controller

joy1 and joy2 are the two controllers, named after the wire protocol’s fields. Both have the same three methods; they are documented here on joy1.

joy1.held(button)

Whether button is down right now.

Parameters:

button – A constant from this module, e.g. LEFT.

Returns:

bool – True while the button is held.

joy1.just_pressed(button)

Whether button went down on this tick.

True for exactly one tick per press, which is what fire, confirm and menu-stepping want.

Parameters:

button – A constant from this module, e.g. A.

Returns:

bool – True on the tick the button was pressed.

joy1.just_released(button)

Whether button came up on this tick.

True for exactly one tick per release. Useful for charge-and-release mechanics.

Parameters:

button – A constant from this module.

Returns:

bool – True on the tick the button was released.

held is a level; just_pressed and just_released are edges.

Buttons

vs2.controls.LEFT

Joystick left.

vs2.controls.RIGHT

Joystick right.

vs2.controls.UP

Joystick up.

vs2.controls.DOWN

Joystick down.

vs2.controls.A

Face button A.

vs2.controls.B

Face button B.

vs2.controls.X

Face button X.

vs2.controls.Y

Face button Y. Also pops the scene unless Scene.back_button is false.

vs2.controls.START

Start button.

vs2.controls.BACK

Back button. Also pops the scene unless Scene.back_button is false.

idle_ms

vs2.controls.idle_ms is milliseconds since any controller was last touched. It re-evaluates on every use and behaves like an integer, so it compares and does arithmetic directly:

if vs2.controls.idle_ms > 5000:
    self.dim_the_hud()

It is deliberately left out of __all__, so a star import does not bring it in. Most games want Scene.idle_timeout and Scene.on_idle instead.

vs2.audio

audio.sound(name)

Play a one-shot sound effect.

audio.music(name, loop=False)

Start a music track, optionally looping.

Music follows the app, not the scene: a track started here keeps playing across Scene.push(), Scene.pop() and Scene.switch() within the same game, and stops on its own when the game returns to the launcher. Call vs2.audio.stop_music() to stop it sooner.

audio.stop_music()

Stop the current music track.

audio.notes(notes)

Play a sequence of synthesised notes.

Names resolve against the current game’s sounds/ folder. A name containing / is already qualified and used as-is, which is how a game borrows another’s audio:

vs2.audio.sound("shoot")                  # this game's shoot.mp3
vs2.audio.sound("alecu.vyruss/shoot1")    # another game's

Music follows the app, not the scene: it keeps playing across push, pop and switch, and stops when the game returns to the launcher.

vs2.saves

saves.load(name, default=None)

Return the value saved under name, or default if there is none (nothing saved yet, or the file cannot be read).

saves.save(name, value)

Save value under name.

Returns:

bool – True if a file was written. False if the value was already saved (nothing is written then, which spares the flash) or the file could not be written, in which case the reason is printed and the game carries on.

Raises:

TypeError – If name is not a string or value cannot be saved as JSON.

Saved data is one small file per game, so a high score or a setting survives a restart. It lives on the console’s flash, and in a saves folder under apps/micropython/ in the desktop emulator. Load in build() and save only when a value changed.

best = vs2.saves.load("best", 0)          # 0 if nothing is saved yet
if score > best:
    vs2.saves.save("best", score)

vs2.base

Console base hardware — the RGB strip, the servo and the lit buttons. Values are range-checked and de-duplicated, so writing the same colour every tick costs one comparison and sends nothing. All of it is safe on a console with no physical base attached.

vs2.base.leds.set_all(255, 0, 0)
vs2.base.servo.set(128)
vs2.base.buttons.set(vs2.base.BUTTON_LED_ALL, blink_ms=250)
leds.set_all(red, green, blue)

Set every base LED to one colour. Each channel is 0..255.

leds.off()

Turn the base LEDs off.

servo.set(position)

Move the servo. position is 0..255.

buttons.set(mask, blink_ms=0)

Light the buttons named by mask, optionally blinking.

mask combines vs2.base.BUTTON_LED_1 and vs2.base.BUTTON_LED_2; blink_ms is 0..10000, where 0 means steady.

buttons.off()

Turn the button lights off.

base.BUTTON_LED_1 = 1
base.BUTTON_LED_2 = 2
base.BUTTON_LED_ALL = 3

Base output follows the app, not the scene: LED, servo and button-light state persists across scene transitions within a game and resets to safe defaults when the game returns to the launcher.

vs2.limits

The per-target resource budgets, readable at runtime.

limits.layers = 8
limits.sprites = 100
limits.tilemaps = 16
limits.image_strips = 100

The values on the rotor are in the budget table. Exceeding one raises vs2.ResourceLimitError during build(), the first time the scene is entered.