mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-26 00:56:38 +11:00
Introduce the MapLoan to infinite scrolled map
This commit is contained in:
parent
2c8fce40d3
commit
10c97f48d8
7 changed files with 80 additions and 43 deletions
|
@ -46,20 +46,20 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut gfx = gba.display.video.tiled0();
|
let (gfx, mut vram) = gba.display.video.tiled0();
|
||||||
let vblank = agb::interrupt::VBlank::get();
|
let vblank = agb::interrupt::VBlank::get();
|
||||||
let mut input = agb::input::ButtonController::new();
|
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 = 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() {
|
for (i, &tile) in MAP_MAP.iter().enumerate() {
|
||||||
let i = i as u16;
|
let i = i as u16;
|
||||||
background.set_tile(
|
background.set_tile(
|
||||||
&mut gfx.vram,
|
&mut vram,
|
||||||
(i % 32, i / 32).into(),
|
(i % 32, i / 32).into(),
|
||||||
tileset_ref,
|
tileset_ref,
|
||||||
TileSetting::from_raw(tile),
|
TileSetting::from_raw(tile),
|
||||||
|
|
|
@ -5,10 +5,9 @@ use agb::display::example_logo;
|
||||||
|
|
||||||
#[agb::entry]
|
#[agb::entry]
|
||||||
fn main(mut gba: agb::Gba) -> ! {
|
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 map = gfx.background(agb::display::Priority::P0);
|
||||||
let mut vram = gfx.vram;
|
|
||||||
|
|
||||||
example_logo::display_logo(&mut map, &mut vram);
|
example_logo::display_logo(&mut map, &mut vram);
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@ struct BackCosines {
|
||||||
|
|
||||||
#[agb::entry]
|
#[agb::entry]
|
||||||
fn main(mut gba: agb::Gba) -> ! {
|
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);
|
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 mut time = 0;
|
||||||
let cosines = [0_u16; 32];
|
let cosines = [0_u16; 32];
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use alloc::{boxed::Box, vec};
|
use alloc::{boxed::Box, vec};
|
||||||
|
@ -424,17 +425,17 @@ impl RegularMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InfiniteScrolledMap {
|
pub struct InfiniteScrolledMap<'a> {
|
||||||
map: RegularMap,
|
map: MapLoan<'a, RegularMap>,
|
||||||
get_tile: Box<dyn Fn(Vector2D<i32>) -> (TileSetReference, TileSetting)>,
|
get_tile: Box<dyn Fn(Vector2D<i32>) -> (TileSetReference, TileSetting)>,
|
||||||
|
|
||||||
current_pos: Vector2D<i32>,
|
current_pos: Vector2D<i32>,
|
||||||
offset: Vector2D<i32>,
|
offset: Vector2D<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InfiniteScrolledMap {
|
impl<'a> InfiniteScrolledMap<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
map: RegularMap,
|
map: MapLoan<'a, RegularMap>,
|
||||||
get_tile: Box<dyn Fn(Vector2D<i32>) -> (TileSetReference, TileSetting)>,
|
get_tile: Box<dyn Fn(Vector2D<i32>) -> (TileSetReference, TileSetting)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
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>>,
|
regular: RefCell<Bitarray<1>>,
|
||||||
|
|
||||||
pub vram: VRamManager<'a>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tiled0<'_> {
|
impl Tiled0 {
|
||||||
pub(crate) unsafe fn new() -> Self {
|
pub(crate) unsafe fn new() -> Self {
|
||||||
set_graphics_settings(GraphicsSettings::empty() | GraphicsSettings::SPRITE1_D);
|
set_graphics_settings(GraphicsSettings::empty() | GraphicsSettings::SPRITE1_D);
|
||||||
set_graphics_mode(DisplayMode::Tiled0);
|
set_graphics_mode(DisplayMode::Tiled0);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
regular: Default::default(),
|
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 mut regular = self.regular.borrow_mut();
|
||||||
let new_background = regular.first_zero().unwrap();
|
let new_background = regular.first_zero().unwrap();
|
||||||
if new_background >= 4 {
|
if new_background >= 4 {
|
||||||
|
@ -642,7 +639,7 @@ impl Tiled0<'_> {
|
||||||
|
|
||||||
regular.set(new_background, true);
|
regular.set(new_background, true);
|
||||||
|
|
||||||
bg
|
MapLoan::new(bg, new_background as u8, &self.regular)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,3 +648,41 @@ impl TileSetReference {
|
||||||
Self { id, generation }
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -33,11 +33,11 @@ mod tests {
|
||||||
|
|
||||||
#[test_case]
|
#[test_case]
|
||||||
fn logo_display(gba: &mut crate::Gba) {
|
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);
|
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");
|
crate::test_runner::assert_image_output("gfx/test_logo.png");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use super::{background::Tiled0, bitmap3::Bitmap3, bitmap4::Bitmap4};
|
use super::{
|
||||||
|
background::{Tiled0, VRamManager},
|
||||||
|
bitmap3::Bitmap3,
|
||||||
|
bitmap4::Bitmap4,
|
||||||
|
};
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct Video {}
|
pub struct Video {}
|
||||||
|
@ -14,7 +18,7 @@ impl Video {
|
||||||
unsafe { Bitmap4::new() }
|
unsafe { Bitmap4::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tiled0(&mut self) -> Tiled0 {
|
pub fn tiled0(&mut self) -> (Tiled0, VRamManager<'_>) {
|
||||||
unsafe { Tiled0::new() }
|
(unsafe { Tiled0::new() }, VRamManager::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,21 +28,21 @@ agb::include_gfx!("gfx/background.toml");
|
||||||
|
|
||||||
type Number = FixedNum<8>;
|
type Number = FixedNum<8>;
|
||||||
|
|
||||||
struct Level {
|
struct Level<'a> {
|
||||||
background: InfiniteScrolledMap,
|
background: InfiniteScrolledMap<'a>,
|
||||||
foreground: InfiniteScrolledMap,
|
foreground: InfiniteScrolledMap<'a>,
|
||||||
clouds: InfiniteScrolledMap,
|
clouds: InfiniteScrolledMap<'a>,
|
||||||
|
|
||||||
slime_spawns: Vec<(u16, u16)>,
|
slime_spawns: Vec<(u16, u16)>,
|
||||||
bat_spawns: Vec<(u16, u16)>,
|
bat_spawns: Vec<(u16, u16)>,
|
||||||
emu_spawns: Vec<(u16, u16)>,
|
emu_spawns: Vec<(u16, u16)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Level {
|
impl<'a> Level<'a> {
|
||||||
fn load_level(
|
fn load_level(
|
||||||
mut backdrop: InfiniteScrolledMap,
|
mut backdrop: InfiniteScrolledMap<'a>,
|
||||||
mut foreground: InfiniteScrolledMap,
|
mut foreground: InfiniteScrolledMap<'a>,
|
||||||
mut clouds: InfiniteScrolledMap,
|
mut clouds: InfiniteScrolledMap<'a>,
|
||||||
vram: &mut VRamManager,
|
vram: &mut VRamManager,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
backdrop.init(vram, (8, 8).into());
|
backdrop.init(vram, (8, 8).into());
|
||||||
|
@ -1772,7 +1772,7 @@ struct Game<'a> {
|
||||||
player: Player<'a>,
|
player: Player<'a>,
|
||||||
input: ButtonController,
|
input: ButtonController,
|
||||||
frame_count: u32,
|
frame_count: u32,
|
||||||
level: Level,
|
level: Level<'a>,
|
||||||
offset: Vector2D<Number>,
|
offset: Vector2D<Number>,
|
||||||
shake_time: u16,
|
shake_time: u16,
|
||||||
sunrise_timer: u16,
|
sunrise_timer: u16,
|
||||||
|
@ -2086,7 +2086,7 @@ impl<'a> Game<'a> {
|
||||||
vram.set_background_palettes(&modified_palettes);
|
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 player = Player::new(object);
|
||||||
let mut offset = (8, 8).into();
|
let mut offset = (8, 8).into();
|
||||||
if start_at_boss {
|
if start_at_boss {
|
||||||
|
@ -2138,12 +2138,11 @@ fn game_with_level(gba: &mut agb::Gba) {
|
||||||
let mut start_at_boss = false;
|
let mut start_at_boss = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut background = gba.display.video.tiled0();
|
let (background, mut vram) = gba.display.video.tiled0();
|
||||||
background
|
|
||||||
.vram
|
|
||||||
.set_background_palettes(background::background.palettes);
|
|
||||||
|
|
||||||
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,
|
background::background.tiles,
|
||||||
TileFormat::FourBpp,
|
TileFormat::FourBpp,
|
||||||
));
|
));
|
||||||
|
@ -2189,7 +2188,7 @@ fn game_with_level(gba: &mut agb::Gba) {
|
||||||
|
|
||||||
let mut game = Game::new(
|
let mut game = Game::new(
|
||||||
&object,
|
&object,
|
||||||
Level::load_level(backdrop, foreground, clouds, &mut background.vram),
|
Level::load_level(backdrop, foreground, clouds, &mut vram),
|
||||||
start_at_boss,
|
start_at_boss,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2197,7 +2196,7 @@ fn game_with_level(gba: &mut agb::Gba) {
|
||||||
sfx.frame();
|
sfx.frame();
|
||||||
vblank.wait_for_vblank();
|
vblank.wait_for_vblank();
|
||||||
sfx.after_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::Continue => {}
|
||||||
GameStatus::Lost => {
|
GameStatus::Lost => {
|
||||||
break false;
|
break false;
|
||||||
|
|
Loading…
Add table
Reference in a new issue