2022-12-04
single-button gba rom
4:25p
before i forget: advent of code has been going pretty well so far, i'm doing it in rust again this year.
okay, bootstrapping a simple one-button test rom in agb. step 1, scaffold.
git clone https://github.com/agbrs/template single-button-agb cd single-button-agb cargo run
4:35p
agb is designed to integrate with aseprite, so i better get that set up. i've used it before but i don't think i own a licensed copy of it.
4:45p
i just picked up aseprite on itch.io and spent a few minutes getting re-acquainted.
so my plan is to show a single sprite on the screen, and pressing the a button will cause the sprite to toggle. im not sure if it is a moment toggle, or if its only toggled while being held down.
mkdir gfx # set up two-frame aseprite with distinctly different images # and unique tag names
in the gba src:
const FACES: &Graphics = include_aseprite!("gfx/face.aseprite");
const HAPPY_FACE: &Tag = FACES.tags().get("Happy Face");
const SAD_FACE: &Tag = FACES.tags().get("Sad Face");
5:45p
i have a simple demo working, i want to clean this up and then see about adding a sound effect when toggling the sprite.
7:00p
i had a bit of a break for the last 45 mins, but came back and was able to use the agb built-in sound synthesis to play back a really terrible sounding sound clip.
#![no_std]
#![no_main]
#![cfg_attr(test, feature(custom_test_frameworks))]
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
#![cfg_attr(test, test_runner(agb::test_runner::test_runner))]
use agb::{
display::object::{Graphics, Tag},
include_aseprite,
input::{Button, ButtonController},
sound,
};
const FACES: &Graphics = include_aseprite!("gfx/face.aseprite");
const HAPPY_FACE: &Tag = FACES.tags().get("Happy Face");
const SAD_FACE: &Tag = FACES.tags().get("Sad Face");
const WIDTH: i32 = agb::display::WIDTH - 16;
const HEIGHT: i32 = agb::display::HEIGHT - 16;
struct Face {
is_happy: bool,
x: i32,
y: i32,
vel_x: i32,
vel_y: i32,
}
impl Face {
fn new() -> Face {
Face {
is_happy: false,
x: 55,
y: 55,
vel_x: 1,
vel_y: 1,
}
}
fn tick(&mut self) -> () {
self.x = (self.x + self.vel_x).clamp(0, WIDTH);
self.y = (self.y + self.vel_y).clamp(0, HEIGHT);
if self.x == 0 || self.x == WIDTH {
self.vel_x = -self.vel_x;
}
if self.y == 0 || self.y == HEIGHT {
self.vel_y = -self.vel_y;
}
}
}
#[agb::entry]
fn main(mut gba: agb::Gba) -> ! {
gba.sound.enable();
let object_controller = gba.display.object.get();
let mut input = ButtonController::new();
let mut face_data = Face::new();
let sad_face_sprite = SAD_FACE.sprite(0);
let happy_face_sprite = HAPPY_FACE.sprite(0);
let mut face_obj = object_controller.object_sprite(sad_face_sprite);
loop {
input.update();
if input.is_just_pressed(Button::A) {
let face_sprite = match face_data.is_happy {
true => sad_face_sprite,
false => happy_face_sprite,
};
let sprite = object_controller.sprite(face_sprite);
face_obj.set_sprite(sprite);
face_data.is_happy = !face_data.is_happy;
gba.sound.noise().play_sound(
Some(0),
&sound::dmg::EnvelopeSettings::default(),
7,
false,
1,
);
}
face_data.tick();
face_obj.set_x(face_data.x as u16).set_y(face_data.y as u16);
agb::display::busy_wait_for_vblank();
object_controller.commit();
}
}
7:15p
uploaded to the gameSH and everything is great!!
10:15p
two things to look into:
- the chicken example from the agb crate
- exporting/embedding gba.ninja for itch.io publication
© 2025 Matthew Ryan Dillon