Skip to main content

Common Script Examples

These examples are small on purpose. Replace names like hero, battle_theme, and TAG_PLAYER with the identifiers generated for your project.

Move an actor with the D-pad

void AUPDATE(void) BANKED{
uint8_t keys = joypad();

if(keys & J_LEFT) {
move_actor(-16, 0);
}
if(keys & J_RIGHT) {
move_actor(16, 0);
}
if(keys & J_UP) {
move_actor(0, -16);
}
if(keys & J_DOWN) {
move_actor(0, 16);
}
}

Actor movement uses 16 subpixels per pixel, so 16 means one screen pixel.

React once to a button press

static uint8_t previous_keys;

void AUPDATE(void) BANKED{
uint8_t keys = joypad();

if((keys & J_A) && !(previous_keys & J_A)) {
// Run once when A is pressed.
}

previous_keys = keys;
}

Set an actor animation

void AINIT(void) BANKED{
Hero* self = (Hero*) THIS_ACTOR;
init_actor(&self->base);

set_actor_animation(animations[hero]);
}

Use the sprite resource identifier inside animations[...].

Play music when a scene starts

void SINIT(void) BANKED{
Room* scene = (Room*) THIS_SCENE;
init_scene(&scene->base);

play_song(songs[battle_theme], 1);
}

Use the music resource identifier inside songs[...]. The second value is whether the song should loop.

Pause and resume music

static uint8_t previous_keys;

void AUPDATE(void) BANKED{
uint8_t keys = joypad();

if((keys & J_SELECT) && !(previous_keys & J_SELECT)) {
pause_music();
}

if((keys & J_START) && !(previous_keys & J_START)) {
resume_music();
}

previous_keys = keys;
}

pause_music() keeps the current song position. stop_music() clears it.

Play a channel sound effect over music

void PlayHitSound(void) BANKED{
const Song* sfx = songs[hit_sfx];

play_music_channel_sequence_banked(
MUSIC_CHANNEL_4,
hit_sfx_ch4_sequence,
sfx->sequence_length,
hit_sfx_instruments,
sfx->speed,
sfx->bank
);
}

Use a generated music asset for the effect and pass one of its channel sequences. The newest sequence requested for a channel takes over immediately; when it finishes, that channel returns to the current music.

Change to another scene

void AUPDATE(void) BANKED{
if(joypad() & J_START) {
set_scene_deferred(create_scene(_new_scene_2));
}
}

Use the generated scene enum value from SceneType. create_scene() allocates the scene but does not change THIS_SCENE; the game manager updates the current scene context when the scene is installed. set_scene_deferred() is preferred during updates and callbacks because it applies the change after the current update step.

Spawn an actor

void SpawnEnemy(uint16_t x, uint16_t y) BANKED{
Actor* enemy = create_actor(_Enemy);
if(enemy != NULL){
Actor* previous_actor = THIS_ACTOR;
THIS_ACTOR = enemy;
set_actor_position(x, y);
add_actor(enemy);
THIS_ACTOR = previous_actor;
}
}

Use the generated actor enum value from ActorType. create_actor() initializes the actor and returns it, but it restores the previous THIS_ACTOR before returning. Save and restore THIS_ACTOR around helper calls that should apply to the new actor before it is added to the scene.

Draw text

static TextHandle* label;

void SINIT(void) BANKED{
Room* scene = (Room*) THIS_SCENE;
init_scene(&scene->base);

label = create_text_handle();
draw_text(label, TEXT_LAYER_WINDOW, 1, 1, "Hello");
}

Keep the handle if you want to move, update, or remove the text later.

Change one map tile

void OpenDoor(void) BANKED{
register_changed_map_tile(10, 6, 4);
}

The first two values are tile coordinates, not pixels. The last value is the tile number to draw.

Find actors by tag

Actor* players[4];
uint8_t player_count = 0;

void SUPDATE(void) BANKED{
get_actors_by_tag(TAG_PLAYER, players, 4, &player_count);

if(player_count > 0) {
// players[0] is the first actor with TAG_PLAYER.
}

update_actors();
draw_actors();
}

Tags are useful when one script needs to find actors without knowing their exact names.

Use a collision callback

void OnEnemyHit(void) BANKED{
if(OTHER_COLLIDER != NULL) {
// This runs when this collider touches another collider.
}
}

Attach this function to a collider in the scene editor.