mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
commit
2d53977c49
BIN
examples/amplitude/gfx/bar.aseprite
Normal file
BIN
examples/amplitude/gfx/bar.aseprite
Normal file
Binary file not shown.
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
use agb::{
|
use agb::{
|
||||||
display::{
|
display::{
|
||||||
self,
|
self,
|
||||||
|
@ -33,6 +35,7 @@ struct Saw {
|
||||||
rotation_speed: Number,
|
rotation_speed: Number,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
enum Colour {
|
enum Colour {
|
||||||
Red,
|
Red,
|
||||||
Blue,
|
Blue,
|
||||||
|
@ -49,6 +52,7 @@ struct SpriteCache {
|
||||||
blue: SpriteVram,
|
blue: SpriteVram,
|
||||||
red: SpriteVram,
|
red: SpriteVram,
|
||||||
numbers: Box<[SpriteVram]>,
|
numbers: Box<[SpriteVram]>,
|
||||||
|
bars: [Box<[SpriteVram]>; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -57,6 +61,41 @@ enum DrawDirection {
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_bar(
|
||||||
|
position: Vector2D<i32>,
|
||||||
|
length: usize,
|
||||||
|
colour: Colour,
|
||||||
|
oam: &mut OamIterator,
|
||||||
|
sprite_cache: &SpriteCache,
|
||||||
|
) -> Option<()> {
|
||||||
|
let length = length as i32;
|
||||||
|
let number_of_sprites = length / 8;
|
||||||
|
let size_of_last = length % 8;
|
||||||
|
|
||||||
|
let sprites = match colour {
|
||||||
|
Colour::Red => &sprite_cache.bars[0],
|
||||||
|
Colour::Blue => &sprite_cache.bars[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
for sprite_idx in 0..number_of_sprites {
|
||||||
|
let mut object = ObjectUnmanaged::new(sprites[0].clone());
|
||||||
|
object
|
||||||
|
.show()
|
||||||
|
.set_position(position + (sprite_idx * 8, 0).into());
|
||||||
|
oam.next()?.set(&object);
|
||||||
|
}
|
||||||
|
|
||||||
|
if size_of_last != 0 {
|
||||||
|
let mut object = ObjectUnmanaged::new(sprites[8 - size_of_last as usize].clone());
|
||||||
|
object
|
||||||
|
.show()
|
||||||
|
.set_position(position + (number_of_sprites * 8, 0).into());
|
||||||
|
oam.next()?.set(&object);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_number(
|
fn draw_number(
|
||||||
mut number: u32,
|
mut number: u32,
|
||||||
position: Vector2D<i32>,
|
position: Vector2D<i32>,
|
||||||
|
@ -97,23 +136,38 @@ impl SpriteCache {
|
||||||
const SPRITES: &Graphics = include_aseprite!(
|
const SPRITES: &Graphics = include_aseprite!(
|
||||||
"gfx/circles.aseprite",
|
"gfx/circles.aseprite",
|
||||||
"gfx/saw.aseprite",
|
"gfx/saw.aseprite",
|
||||||
"gfx/numbers.aseprite"
|
"gfx/numbers.aseprite",
|
||||||
|
"gfx/bar.aseprite"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
fn generate_sprites(
|
||||||
|
tag: &'static Tag,
|
||||||
|
range: Range<usize>,
|
||||||
|
loader: &mut SpriteLoader,
|
||||||
|
) -> Box<[SpriteVram]> {
|
||||||
|
range
|
||||||
|
.map(|x| tag.sprite(x))
|
||||||
|
.map(|x| loader.get_vram_sprite(x))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
const NUMBERS: &Tag = SPRITES.tags().get("numbers");
|
const NUMBERS: &Tag = SPRITES.tags().get("numbers");
|
||||||
const BLUE_CIRCLE: &Sprite = SPRITES.tags().get("Blue").sprite(0);
|
const BLUE_CIRCLE: &Sprite = SPRITES.tags().get("Blue").sprite(0);
|
||||||
const RED_CIRCLE: &Sprite = SPRITES.tags().get("Red").sprite(0);
|
const RED_CIRCLE: &Sprite = SPRITES.tags().get("Red").sprite(0);
|
||||||
const SAW: &Sprite = SPRITES.tags().get("Saw").sprite(0);
|
const SAW: &Sprite = SPRITES.tags().get("Saw").sprite(0);
|
||||||
|
const BAR_RED: &Tag = SPRITES.tags().get("Red Bar");
|
||||||
|
const BAR_BLUE: &Tag = SPRITES.tags().get("Blue Bar");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
saw: loader.get_vram_sprite(SAW),
|
saw: loader.get_vram_sprite(SAW),
|
||||||
blue: loader.get_vram_sprite(BLUE_CIRCLE),
|
blue: loader.get_vram_sprite(BLUE_CIRCLE),
|
||||||
red: loader.get_vram_sprite(RED_CIRCLE),
|
red: loader.get_vram_sprite(RED_CIRCLE),
|
||||||
numbers: (0..10)
|
numbers: generate_sprites(NUMBERS, 0..10, loader),
|
||||||
.map(|x| NUMBERS.sprite(x))
|
bars: [
|
||||||
.map(|x| loader.get_vram_sprite(x))
|
generate_sprites(BAR_RED, 0..8, loader),
|
||||||
.collect::<Vec<_>>()
|
generate_sprites(BAR_BLUE, 0..8, loader),
|
||||||
.into_boxed_slice(),
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,6 +181,7 @@ struct Game {
|
||||||
input: ButtonController,
|
input: ButtonController,
|
||||||
frame_since_last_saw: i32,
|
frame_since_last_saw: i32,
|
||||||
alive_frames: u32,
|
alive_frames: u32,
|
||||||
|
energy: Number,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum GameState {
|
enum GameState {
|
||||||
|
@ -151,6 +206,7 @@ impl Game {
|
||||||
|
|
||||||
Game {
|
Game {
|
||||||
input: agb::input::ButtonController::new(),
|
input: agb::input::ButtonController::new(),
|
||||||
|
energy: finalised.max_energy,
|
||||||
settings: finalised,
|
settings: finalised,
|
||||||
circles,
|
circles,
|
||||||
saws: VecDeque::new(),
|
saws: VecDeque::new(),
|
||||||
|
@ -164,9 +220,14 @@ impl Game {
|
||||||
fn frame(&mut self, sprite_cache: &SpriteCache) -> GameState {
|
fn frame(&mut self, sprite_cache: &SpriteCache) -> GameState {
|
||||||
self.input.update();
|
self.input.update();
|
||||||
|
|
||||||
let (height, colour) = if self.input.is_pressed(Button::A) {
|
let (height, colour) = if self.input.is_pressed(Button::A) && self.energy > 0.into() {
|
||||||
|
self.energy -= self.settings.energy_use_speed;
|
||||||
(self.settings.wave_height_ability, Colour::Blue)
|
(self.settings.wave_height_ability, Colour::Blue)
|
||||||
} else {
|
} else {
|
||||||
|
if self.input.is_released(Button::A) {
|
||||||
|
self.energy += self.settings.energy_recover_speed;
|
||||||
|
self.energy = self.energy.min(self.settings.max_energy);
|
||||||
|
}
|
||||||
(self.settings.wave_height_normal, Colour::Red)
|
(self.settings.wave_height_normal, Colour::Red)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -288,6 +349,9 @@ struct Settings {
|
||||||
head_start_position: Vector2D<Number>,
|
head_start_position: Vector2D<Number>,
|
||||||
wave_height_normal: Number,
|
wave_height_normal: Number,
|
||||||
wave_height_ability: Number,
|
wave_height_ability: Number,
|
||||||
|
max_energy: Number,
|
||||||
|
energy_use_speed: Number,
|
||||||
|
energy_recover_speed: Number,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
|
@ -302,6 +366,9 @@ impl Settings {
|
||||||
frames_between_saws: self.frames_between_saws,
|
frames_between_saws: self.frames_between_saws,
|
||||||
wave_height_ability: self.wave_height_ability,
|
wave_height_ability: self.wave_height_ability,
|
||||||
wave_height_normal: self.wave_height_normal,
|
wave_height_normal: self.wave_height_normal,
|
||||||
|
max_energy: self.max_energy,
|
||||||
|
energy_recover_speed: self.energy_recover_speed,
|
||||||
|
energy_use_speed: self.energy_use_speed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,6 +380,9 @@ struct FinalisedSettings {
|
||||||
frames_between_saws: i32,
|
frames_between_saws: i32,
|
||||||
speed: Number,
|
speed: Number,
|
||||||
number_of_circles: usize,
|
number_of_circles: usize,
|
||||||
|
max_energy: Number,
|
||||||
|
energy_use_speed: Number,
|
||||||
|
energy_recover_speed: Number,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(mut gba: agb::Gba) -> ! {
|
pub fn main(mut gba: agb::Gba) -> ! {
|
||||||
|
@ -335,28 +405,42 @@ pub fn main(mut gba: agb::Gba) -> ! {
|
||||||
head_start_position: (40, 100).into(),
|
head_start_position: (40, 100).into(),
|
||||||
wave_height_normal: 20.into(),
|
wave_height_normal: 20.into(),
|
||||||
wave_height_ability: 5.into(),
|
wave_height_ability: 5.into(),
|
||||||
|
max_energy: 128.into(),
|
||||||
|
energy_use_speed: num!(0.5),
|
||||||
|
energy_recover_speed: 0.into(),
|
||||||
});
|
});
|
||||||
loop {
|
loop {
|
||||||
let state = game.frame(&sprite_cache);
|
let state = game.frame(&sprite_cache);
|
||||||
if game.alive_frames > max_score {
|
if game.alive_frames > max_score {
|
||||||
max_score = game.alive_frames;
|
max_score = game.alive_frames;
|
||||||
}
|
}
|
||||||
|
let max_bar_width = display::WIDTH - 2;
|
||||||
|
let bar_width_pixels = (game.energy * max_bar_width) / game.settings.max_energy;
|
||||||
|
let bar_width_pixels = (bar_width_pixels + num!(0.5)).floor().max(0) as usize;
|
||||||
vblank.wait_for_vblank();
|
vblank.wait_for_vblank();
|
||||||
let oam_frame = &mut unmanaged.iter();
|
let oam_frame = &mut unmanaged.iter();
|
||||||
draw_number(
|
draw_number(
|
||||||
max_score,
|
max_score,
|
||||||
(display::WIDTH - 4, 1).into(),
|
(display::WIDTH - 5, 2).into(),
|
||||||
oam_frame,
|
oam_frame,
|
||||||
DrawDirection::Left,
|
DrawDirection::Left,
|
||||||
&sprite_cache,
|
&sprite_cache,
|
||||||
);
|
);
|
||||||
draw_number(
|
draw_number(
|
||||||
game.alive_frames,
|
game.alive_frames,
|
||||||
(1, 1).into(),
|
(2, 2).into(),
|
||||||
oam_frame,
|
oam_frame,
|
||||||
DrawDirection::Right,
|
DrawDirection::Right,
|
||||||
&sprite_cache,
|
&sprite_cache,
|
||||||
);
|
);
|
||||||
|
draw_bar(
|
||||||
|
(1, 1).into(),
|
||||||
|
bar_width_pixels,
|
||||||
|
game.circles.back().unwrap().colour,
|
||||||
|
oam_frame,
|
||||||
|
&sprite_cache,
|
||||||
|
);
|
||||||
|
|
||||||
game.render(oam_frame, &sprite_cache);
|
game.render(oam_frame, &sprite_cache);
|
||||||
|
|
||||||
if let GameState::Loss(_) = state {
|
if let GameState::Loss(_) = state {
|
||||||
|
|
Loading…
Reference in a new issue