add a no game

This commit is contained in:
Corwin 2023-05-06 18:50:35 +01:00
parent a0ead37eb5
commit 0271da6d43
No known key found for this signature in database
5 changed files with 215 additions and 13 deletions

BIN
agb/gfx/square.aseprite Normal file

Binary file not shown.

View file

@ -94,6 +94,7 @@ macro_rules! align_bytes {
#[macro_export]
macro_rules! include_aseprite {
($($aseprite_path: expr),*) => {{
#[allow(unused_imports)]
use $crate::display::object::{Size, Sprite, Tag, TagMap, Graphics};
use $crate::display::palette16::Palette16;
use $crate::align_bytes;

View file

@ -165,6 +165,11 @@ pub mod syscall;
/// Interactions with the internal timers
pub mod timer;
mod no_game;
/// Default game
pub use no_game::no_game;
pub(crate) mod arena;
pub use {agb_alloc::ExternalAllocator, agb_alloc::InternalAllocator};

208
agb/src/no_game.rs Normal file
View file

@ -0,0 +1,208 @@
//! The no game screen is what is displayed if there isn't a game made yet.
use agb_fixnum::{num, Num, Vector2D};
use alloc::vec;
use alloc::vec::Vec;
use crate::{
display::{
object::{OamIterator, ObjectUnmanaged, Sprite},
palette16::Palette16,
HEIGHT, WIDTH,
},
include_aseprite,
interrupt::VBlank,
};
const SQUARE: &Sprite = &include_aseprite!("gfx/square.aseprite").sprites()[0];
fn letters() -> Vec<Vec<Vector2D<Num<i32, 8>>>> {
vec![
// N
vec![
(num!(0.), num!(0.)).into(),
(num!(1.), num!(1.)).into(),
(num!(2.), num!(2.)).into(),
(num!(3.), num!(3.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(3.), num!(0.)).into(),
(num!(3.), num!(1.)).into(),
(num!(3.), num!(2.)).into(),
(num!(3.), num!(3.)).into(),
],
// O
vec![
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(1.), num!(3.)).into(),
(num!(2.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(2.)).into(),
(num!(3.), num!(1.)).into(),
(num!(3.), num!(0.)).into(),
(num!(2.), num!(0.)).into(),
(num!(1.), num!(0.)).into(),
],
// G
vec![
(num!(3.), num!(0.)).into(),
(num!(2.), num!(0.)).into(),
(num!(1.), num!(0.)).into(),
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(1.), num!(3.)).into(),
(num!(2.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(2.25)).into(),
(num!(3.), num!(1.5)).into(),
(num!(2.), num!(1.5)).into(),
],
// A
vec![
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(2.)).into(),
(num!(3.), num!(1.)).into(),
(num!(3.), num!(0.)).into(),
(num!(2.), num!(0.)).into(),
(num!(1.), num!(0.)).into(),
(num!(1.), num!(1.5)).into(),
(num!(2.), num!(1.5)).into(),
],
// M
vec![
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(2.)).into(),
(num!(3.), num!(1.)).into(),
(num!(3.), num!(0.)).into(),
(num!(1.5), num!(1.5)).into(),
(num!(0.5), num!(0.5)).into(),
(num!(2.5), num!(0.5)).into(),
(num!(1.), num!(1.)).into(),
(num!(2.), num!(1.)).into(),
],
// E
vec![
(num!(0.), num!(0.)).into(),
(num!(0.), num!(1.)).into(),
(num!(0.), num!(2.)).into(),
(num!(0.), num!(3.)).into(),
(num!(1.), num!(3.)).into(),
(num!(2.), num!(3.)).into(),
(num!(3.), num!(3.)).into(),
(num!(3.), num!(0.)).into(),
(num!(2.), num!(0.)).into(),
(num!(1.), num!(0.)).into(),
(num!(1.), num!(1.5)).into(),
(num!(2.), num!(1.5)).into(),
],
]
}
trait Renderable {
fn render(&self, slots: &mut OamIterator) -> Option<()>;
}
impl Renderable for ObjectUnmanaged {
fn render(&self, slots: &mut OamIterator) -> Option<()> {
slots.next()?.set(self);
Some(())
}
}
impl<T: Renderable> Renderable for &[T] {
fn render(&self, slots: &mut OamIterator) -> Option<()> {
for r in self.iter() {
r.render(slots)?;
}
Some(())
}
}
pub fn no_game(mut gba: crate::Gba) -> ! {
let (mut oam, mut loader) = gba.display.object.get_unmanaged();
let square = loader.get_vram_sprite(SQUARE);
let mut letter_positons = Vec::new();
let square_positions = {
let mut s = letters();
for letter in s.iter_mut() {
letter.sort_by_key(|a| a.manhattan_distance());
}
s
};
for (letter_idx, letter_parts) in square_positions.iter().enumerate() {
for part in letter_parts.iter() {
let position = part
.hadamard((8, 10).into())
.hadamard((num!(3.) / 2, num!(3.) / 2).into());
let letter_pos = Vector2D::new(
60 * (1 + letter_idx as i32 - ((letter_idx >= 2) as i32 * 3)),
70 * ((letter_idx >= 2) as i32),
);
letter_positons.push(position + letter_pos.change_base());
}
}
let bottom_right = letter_positons
.iter()
.copied()
.max_by_key(|x| x.manhattan_distance())
.unwrap();
let difference = (Vector2D::new(WIDTH - 8, HEIGHT - 8).change_base() - bottom_right) / 2;
for pos in letter_positons.iter_mut() {
*pos += difference;
}
let mut time: Num<i32, 8> = num!(0.);
let time_delta: Num<i32, 8> = num!(0.025);
let (_background, mut vram) = gba.display.video.tiled0();
vram.set_background_palettes(&[Palette16::new([u16::MAX; 16])]);
let vblank = VBlank::get();
loop {
time += time_delta;
time %= 1;
let letters: Vec<ObjectUnmanaged> = letter_positons
.iter()
.enumerate()
.map(|(idx, position)| {
let time = time + Num::<i32, 8>::new(idx as i32) / 128;
*position + Vector2D::new(time.sin(), time.cos()) * 10
})
.map(|pos| {
let mut obj = ObjectUnmanaged::new(square.clone());
obj.show().set_position(pos.floor());
obj
})
.collect();
vblank.wait_for_vblank();
for (obj, slot) in letters.iter().zip(oam.iter()) {
slot.set(obj);
}
}
}

View file

@ -14,22 +14,10 @@
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
#![cfg_attr(test, test_runner(agb::test_runner::test_runner))]
use agb::{display, syscall};
// The main function must take 1 arguments and never return. The agb::entry decorator
// ensures that everything is in order. `agb` will call this after setting up the stack
// and interrupt handlers correctly. It will also handle creating the `Gba` struct for you.
#[agb::entry]
fn main(mut gba: agb::Gba) -> ! {
let mut bitmap = gba.display.video.bitmap3();
for x in 0..display::WIDTH {
let y = syscall::sqrt(x << 6);
let y = (display::HEIGHT - y).clamp(0, display::HEIGHT - 1);
bitmap.draw_point(x, y, 0x001F);
}
loop {
syscall::halt();
}
agb::no_game(gba);
}