Introduce the MapLoan to infinite scrolled map

This commit is contained in:
Gwilym Kuiper 2022-01-31 21:23:12 +00:00
parent 2c8fce40d3
commit 10c97f48d8
7 changed files with 80 additions and 43 deletions

View file

@ -46,20 +46,20 @@ fn main(mut gba: agb::Gba) -> ! {
.unwrap()
};
let mut gfx = gba.display.video.tiled0();
let (gfx, mut vram) = gba.display.video.tiled0();
let vblank = agb::interrupt::VBlank::get();
let mut input = agb::input::ButtonController::new();
gfx.vram.set_background_palette_raw(&MAP_PALETTE);
vram.set_background_palette_raw(&MAP_PALETTE);
let tileset = TileSet::new(&MAP_TILES, TileFormat::FourBpp);
let tileset_ref = gfx.vram.add_tileset(tileset);
let tileset_ref = vram.add_tileset(tileset);
let mut background = gfx.background();
let mut background = gfx.background(agb::display::Priority::P0);
for (i, &tile) in MAP_MAP.iter().enumerate() {
let i = i as u16;
background.set_tile(
&mut gfx.vram,
&mut vram,
(i % 32, i / 32).into(),
tileset_ref,
TileSetting::from_raw(tile),

View file

@ -5,10 +5,9 @@ use agb::display::example_logo;
#[agb::entry]
fn main(mut gba: agb::Gba) -> ! {
let mut gfx = gba.display.video.tiled0();
let (gfx, mut vram) = gba.display.video.tiled0();
let mut map = gfx.background(agb::display::Priority::P0);
let mut vram = gfx.vram;
example_logo::display_logo(&mut map, &mut vram);

View file

@ -17,11 +17,11 @@ struct BackCosines {
#[agb::entry]
fn main(mut gba: agb::Gba) -> ! {
let mut gfx = gba.display.video.tiled0();
let (gfx, mut vram) = gba.display.video.tiled0();
let mut background = gfx.background(agb::display::Priority::P0);
example_logo::display_logo(&mut background, &mut gfx.vram);
example_logo::display_logo(&mut background, &mut vram);
let mut time = 0;
let cosines = [0_u16; 32];

View file

@ -1,4 +1,5 @@
use core::cell::RefCell;
use core::ops::{Deref, DerefMut};
use alloc::vec::Vec;
use alloc::{boxed::Box, vec};
@ -424,17 +425,17 @@ impl RegularMap {
}
}
pub struct InfiniteScrolledMap {
map: RegularMap,
pub struct InfiniteScrolledMap<'a> {
map: MapLoan<'a, RegularMap>,
get_tile: Box<dyn Fn(Vector2D<i32>) -> (TileSetReference, TileSetting)>,
current_pos: Vector2D<i32>,
offset: Vector2D<i32>,
}
impl InfiniteScrolledMap {
impl<'a> InfiniteScrolledMap<'a> {
pub fn new(
map: RegularMap,
map: MapLoan<'a, RegularMap>,
get_tile: Box<dyn Fn(Vector2D<i32>) -> (TileSetReference, TileSetting)>,
) -> Self {
Self {
@ -613,25 +614,21 @@ fn div_ceil(x: i32, y: i32) -> i32 {
}
}
pub struct Tiled0<'a> {
pub struct Tiled0 {
regular: RefCell<Bitarray<1>>,
pub vram: VRamManager<'a>,
}
impl Tiled0<'_> {
impl Tiled0 {
pub(crate) unsafe fn new() -> Self {
set_graphics_settings(GraphicsSettings::empty() | GraphicsSettings::SPRITE1_D);
set_graphics_mode(DisplayMode::Tiled0);
Self {
regular: Default::default(),
vram: VRamManager::new(),
}
}
pub fn background(&mut self, priority: Priority) -> RegularMap {
pub fn background(&self, priority: Priority) -> MapLoan<'_, RegularMap> {
let mut regular = self.regular.borrow_mut();
let new_background = regular.first_zero().unwrap();
if new_background >= 4 {
@ -642,7 +639,7 @@ impl Tiled0<'_> {
regular.set(new_background, true);
bg
MapLoan::new(bg, new_background as u8, &self.regular)
}
}
@ -651,3 +648,41 @@ impl TileSetReference {
Self { id, generation }
}
}
pub struct MapLoan<'a, T> {
map: T,
background_id: u8,
regular_map_list: &'a RefCell<Bitarray<1>>,
}
impl<'a, T> Deref for MapLoan<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl<'a, T> DerefMut for MapLoan<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.map
}
}
impl<'a, T> MapLoan<'a, T> {
fn new(map: T, background_id: u8, regular_map_list: &'a RefCell<Bitarray<1>>) -> Self {
MapLoan {
map,
background_id,
regular_map_list,
}
}
}
impl<'a, T> Drop for MapLoan<'a, T> {
fn drop(&mut self) {
self.regular_map_list
.borrow_mut()
.set(self.background_id as usize, false);
}
}

View file

@ -33,11 +33,11 @@ mod tests {
#[test_case]
fn logo_display(gba: &mut crate::Gba) {
let mut gfx = gba.display.video.tiled0();
let (gfx, mut vram) = gba.display.video.tiled0();
let mut map = gfx.background(crate::display::Priority::P0);
display_logo(&mut map, &mut gfx.vram);
display_logo(&mut map, &mut vram);
crate::test_runner::assert_image_output("gfx/test_logo.png");
}

View file

@ -1,4 +1,8 @@
use super::{background::Tiled0, bitmap3::Bitmap3, bitmap4::Bitmap4};
use super::{
background::{Tiled0, VRamManager},
bitmap3::Bitmap3,
bitmap4::Bitmap4,
};
#[non_exhaustive]
pub struct Video {}
@ -14,7 +18,7 @@ impl Video {
unsafe { Bitmap4::new() }
}
pub fn tiled0(&mut self) -> Tiled0 {
unsafe { Tiled0::new() }
pub fn tiled0(&mut self) -> (Tiled0, VRamManager<'_>) {
(unsafe { Tiled0::new() }, VRamManager::new())
}
}

View file

@ -28,21 +28,21 @@ agb::include_gfx!("gfx/background.toml");
type Number = FixedNum<8>;
struct Level {
background: InfiniteScrolledMap,
foreground: InfiniteScrolledMap,
clouds: InfiniteScrolledMap,
struct Level<'a> {
background: InfiniteScrolledMap<'a>,
foreground: InfiniteScrolledMap<'a>,
clouds: InfiniteScrolledMap<'a>,
slime_spawns: Vec<(u16, u16)>,
bat_spawns: Vec<(u16, u16)>,
emu_spawns: Vec<(u16, u16)>,
}
impl Level {
impl<'a> Level<'a> {
fn load_level(
mut backdrop: InfiniteScrolledMap,
mut foreground: InfiniteScrolledMap,
mut clouds: InfiniteScrolledMap,
mut backdrop: InfiniteScrolledMap<'a>,
mut foreground: InfiniteScrolledMap<'a>,
mut clouds: InfiniteScrolledMap<'a>,
vram: &mut VRamManager,
) -> Self {
backdrop.init(vram, (8, 8).into());
@ -1772,7 +1772,7 @@ struct Game<'a> {
player: Player<'a>,
input: ButtonController,
frame_count: u32,
level: Level,
level: Level<'a>,
offset: Vector2D<Number>,
shake_time: u16,
sunrise_timer: u16,
@ -2086,7 +2086,7 @@ impl<'a> Game<'a> {
vram.set_background_palettes(&modified_palettes);
}
fn new(object: &'a ObjectControl, level: Level, start_at_boss: bool) -> Self {
fn new(object: &'a ObjectControl, level: Level<'a>, start_at_boss: bool) -> Self {
let mut player = Player::new(object);
let mut offset = (8, 8).into();
if start_at_boss {
@ -2138,12 +2138,11 @@ fn game_with_level(gba: &mut agb::Gba) {
let mut start_at_boss = false;
loop {
let mut background = gba.display.video.tiled0();
background
.vram
.set_background_palettes(background::background.palettes);
let (background, mut vram) = gba.display.video.tiled0();
let tileset_ref = background.vram.add_tileset(TileSet::new(
vram.set_background_palettes(background::background.palettes);
let tileset_ref = vram.add_tileset(TileSet::new(
background::background.tiles,
TileFormat::FourBpp,
));
@ -2189,7 +2188,7 @@ fn game_with_level(gba: &mut agb::Gba) {
let mut game = Game::new(
&object,
Level::load_level(backdrop, foreground, clouds, &mut background.vram),
Level::load_level(backdrop, foreground, clouds, &mut vram),
start_at_boss,
);
@ -2197,7 +2196,7 @@ fn game_with_level(gba: &mut agb::Gba) {
sfx.frame();
vblank.wait_for_vblank();
sfx.after_vblank();
match game.advance_frame(&object, &mut background.vram, &mut sfx) {
match game.advance_frame(&object, &mut vram, &mut sfx) {
GameStatus::Continue => {}
GameStatus::Lost => {
break false;