Something that seems like it is close to working

This commit is contained in:
Gwilym Kuiper 2022-01-24 20:50:27 +00:00
parent 472875edac
commit f785d65057
8 changed files with 319 additions and 86 deletions

View file

@ -587,7 +587,7 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> From<Vector2D<I>> for Vector2
}
}
#[derive(PartialEq, Eq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Rect<T: Number> {
pub position: Vector2D<T>,
pub size: Vector2D<T>,
@ -657,10 +657,10 @@ impl<T: FixedWidthUnsignedInteger> Rect<T> {
let mut y = self.position.y;
core::iter::from_fn(move || {
x = x + T::one();
if x > self.position.x + self.size.x {
if x >= self.position.x + self.size.x {
x = self.position.x;
y = y + T::one();
if y > self.position.y + self.size.y {
if y >= self.position.y + self.size.y {
return None;
}
}

View file

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

View file

@ -19,7 +19,7 @@ struct BackCosines {
fn main(mut gba: agb::Gba) -> ! {
let mut gfx = gba.display.video.tiled0();
let mut background = gfx.background();
let mut background = gfx.background(agb::display::Priority::P0);
example_logo::display_logo(&mut background, &mut gfx.vram);

View file

@ -1,9 +1,10 @@
use alloc::vec;
use alloc::vec::Vec;
use alloc::{boxed::Box, vec};
use hashbrown::HashMap;
use crate::{
fixnum::Vector2D,
display,
fixnum::{Rect, Vector2D},
memory_mapped::{MemoryMapped, MemoryMapped1DArray},
};
@ -267,14 +268,14 @@ pub struct RegularMap {
}
impl RegularMap {
fn new(background_id: u8, screenblock: u8) -> Self {
fn new(background_id: u8, screenblock: u8, priority: Priority) -> Self {
Self {
background_id,
screenblock,
x_scroll: 0,
y_scroll: 0,
priority: Priority::P0,
priority,
tiles: [Tile::default(); 32 * 32],
tiles_dirty: true,
@ -335,13 +336,35 @@ impl RegularMap {
}
let screenblock_memory = self.screenblock_memory();
for (i, tile) in self.tiles.iter().enumerate() {
screenblock_memory.set(i, tile.0);
let scroll_pos = self.get_scroll_pos();
let x_scroll = scroll_pos.x % display::WIDTH as u16;
let y_scroll = scroll_pos.y % display::HEIGHT as u16;
let start_x = x_scroll / 8;
let end_x = (x_scroll + display::WIDTH as u16 + 8 - 1) / 8; // divide by 8 rounding up
let start_y = y_scroll / 8;
let end_y = (y_scroll + display::HEIGHT as u16 + 8 - 1) / 8;
for y in start_y..end_y {
for x in start_x..end_x {
let id = y.rem_euclid(32) * 32 + x.rem_euclid(32);
screenblock_memory.set(id as usize, self.tiles[id as usize].0);
}
}
self.tiles_dirty = false;
}
pub fn set_scroll_pos(&mut self, pos: Vector2D<u16>) {
self.x_scroll = pos.x;
self.y_scroll = pos.y;
}
pub fn get_scroll_pos(&self) -> Vector2D<u16> {
(self.x_scroll, self.y_scroll).into()
}
const fn bg_control_register(&self) -> MemoryMapped<u16> {
unsafe { MemoryMapped::new(0x0400_0008 + 2 * self.background_id as usize) }
}
@ -359,6 +382,174 @@ impl RegularMap {
}
}
pub struct InfiniteScrolledMap {
map: RegularMap,
get_tile: Box<dyn Fn(Vector2D<i32>) -> (TileSetReference, TileSetting)>,
current_pos: Vector2D<i32>,
offset: Vector2D<i32>,
}
impl InfiniteScrolledMap {
pub fn new(
map: RegularMap,
get_tile: Box<dyn Fn(Vector2D<i32>) -> (TileSetReference, TileSetting)>,
) -> Self {
Self {
map,
get_tile,
current_pos: (0, 0).into(),
offset: (0, 0).into(),
}
}
pub fn init(&mut self, vram: &mut VRamManager, pos: Vector2D<i32>) {
self.current_pos = pos;
let x_start = div_floor(self.current_pos.x, 8);
let y_start = div_floor(self.current_pos.y, 8);
let x_end = div_ceil(self.current_pos.x + display::WIDTH, 8);
let y_end = div_ceil(self.current_pos.y + display::HEIGHT, 8);
for (y_idx, y) in (y_start..y_end).enumerate() {
for (x_idx, x) in (x_start..x_end).enumerate() {
let pos = (x, y).into();
let (tile_set_ref, tile_setting) = (self.get_tile)(pos);
self.map.set_tile(
vram,
(x_idx as u16, y_idx as u16).into(),
tile_set_ref,
tile_setting,
);
}
}
let offset = self.current_pos - (x_start * 8, y_start * 8).into();
let offset_scroll = (
if offset.x < 0 {
(offset.x + 32 * 8) as u16
} else {
offset.x as u16
},
if offset.y < 0 {
(offset.y + 32 * 8) as u16
} else {
offset.y as u16
},
)
.into();
self.map.set_scroll_pos(offset_scroll);
self.offset = offset;
}
pub fn set_pos(&mut self, vram: &mut VRamManager, new_pos: Vector2D<i32>) {
let old_pos = self.current_pos;
let difference = new_pos - old_pos;
if difference.x.abs() > 8 || difference.y.abs() > 8 {
self.init(vram, new_pos);
return;
}
let is_new_y_mod_8 = new_pos.y % 8 == 0;
let is_new_x_mod_8 = new_pos.x % 8 == 0;
let top_bottom_rect: Rect<i32> = {
let top_bottom_height = difference.y.signum();
let new_tile_y = if top_bottom_height > 0 {
div_ceil(new_pos.y, 8) + if is_new_y_mod_8 { 20 } else { 22 }
} else {
div_floor(new_pos.y, 8)
};
Rect::new(
(div_floor(new_pos.x, 8), new_tile_y).into(),
(
if is_new_x_mod_8 { 30 } else { 32 },
top_bottom_height.abs(),
)
.into(),
)
};
let left_right_rect: Rect<i32> = {
let left_right_width = difference.x.signum();
let new_tile_x = if left_right_width > 0 {
div_ceil(new_pos.x, 8) + if is_new_x_mod_8 { 30 } else { 32 }
} else {
div_floor(new_pos.x, 8)
};
Rect::new(
(new_tile_x, div_floor(new_pos.y, 8)).into(),
(left_right_width.abs(), if is_new_y_mod_8 { 20 } else { 22 }).into(),
)
};
self.offset += difference;
self.current_pos = new_pos;
let offset_block = self.offset / 8;
for (x, y) in top_bottom_rect.iter().chain(left_right_rect.iter()) {
let (tileset_ref, tile_setting) = (self.get_tile)((x, y).into());
let tile_pos = (
(x + offset_block.x).rem_euclid(32) as u16,
(y + offset_block.y).rem_euclid(32) as u16,
)
.into();
self.map.set_tile(vram, tile_pos, tileset_ref, tile_setting)
}
let current_scroll = self.map.get_scroll_pos();
let new_scroll = (
(current_scroll.x as i32 + difference.x).rem_euclid(32 * 8) as u16,
(current_scroll.y as i32 + difference.y).rem_euclid(32 * 8) as u16,
)
.into();
self.map.set_scroll_pos(new_scroll);
}
pub fn show(&mut self) {
self.map.show();
}
pub fn hide(&mut self) {
self.map.hide();
}
pub fn commit(&mut self) {
self.map.commit();
}
}
fn div_floor(x: i32, y: i32) -> i32 {
if x > 0 && y < 0 {
(x - 1) / y - 1
} else if x < 0 && y > 0 {
(x + 1) / y - 1
} else {
x / y
}
}
fn div_ceil(x: i32, y: i32) -> i32 {
if x > 0 && y > 0 {
(x - 1) / y + 1
} else if x < 0 && y < 0 {
(x + 1) / y + 1
} else {
x / y
}
}
pub struct Tiled0<'a> {
num_regular: u8,
next_screenblock: u8,
@ -379,12 +570,12 @@ impl Tiled0<'_> {
}
}
pub fn background(&mut self) -> RegularMap {
pub fn background(&mut self, priority: Priority) -> RegularMap {
if self.num_regular == 4 {
panic!("Can only create 4 backgrounds");
}
let bg = RegularMap::new(self.num_regular, self.next_screenblock);
let bg = RegularMap::new(self.num_regular, self.next_screenblock, priority);
self.num_regular += 1;
self.next_screenblock += 1;

View file

@ -35,7 +35,7 @@ mod tests {
fn logo_display(gba: &mut crate::Gba) {
let mut gfx = gba.display.video.tiled0();
let mut map = gfx.background();
let mut map = gfx.background(crate::display::Priority::P0);
display_logo(&mut map, &mut gfx.vram);

View file

@ -24,6 +24,7 @@ dependencies = [
"agb_sound_converter",
"bare-metal",
"bitflags",
"hashbrown",
]
[[package]]
@ -65,6 +66,17 @@ dependencies = [
"syn",
]
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -94,9 +106,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bytemuck"
version = "1.7.3"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead"
[[package]]
name = "byteorder"
@ -160,6 +172,15 @@ dependencies = [
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
dependencies = [
"ahash",
]
[[package]]
name = "hound"
version = "3.4.0"
@ -250,10 +271,16 @@ dependencies = [
]
[[package]]
name = "png"
version = "0.17.4"
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02cd7d51cea7e2fa6bbcb8af5fbcad15b871451bfc2d20ed72dff2f4ae072a84"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "png"
version = "0.17.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba"
dependencies = [
"bitflags",
"crc32fast",
@ -394,6 +421,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"

View file

@ -45,8 +45,8 @@ fn main() {
pub const CLOUD_MAP: &[u16] = &[#(#cloud_tiles),*];
pub const BACKGROUND_MAP: &[u16] = &[#(#background_tiles),*];
pub const FOREGROUND_MAP: &[u16] = &[#(#foreground_tiles),*];
pub const WIDTH: u32 = #width;
pub const HEIGHT: u32 = #height;
pub const WIDTH: i32 = #width as i32;
pub const HEIGHT: i32 = #height as i32;
pub const SLIME_SPAWNS_X: &[u16] = &[#(#slimes_x),*];
pub const SLIME_SPAWNS_Y: &[u16] = &[#(#slimes_y),*];

View file

@ -8,13 +8,13 @@ mod sfx;
use core::cmp::Ordering;
use alloc::vec::Vec;
use alloc::{boxed::Box, vec::Vec};
use rng::get_random;
use agb::{
display::{
background::{BackgroundDistributor, BackgroundRegular},
background::{InfiniteScrolledMap, TileFormat, TileSet, TileSetting, VRamManager},
object::{ObjectControl, ObjectStandard},
Priority, HEIGHT, WIDTH,
},
@ -29,9 +29,9 @@ agb::include_gfx!("gfx/background.toml");
type Number = FixedNum<8>;
struct Level {
background: BackgroundRegular<'static>,
foreground: BackgroundRegular<'static>,
clouds: BackgroundRegular<'static>,
background: InfiniteScrolledMap,
foreground: InfiniteScrolledMap,
clouds: InfiniteScrolledMap,
slime_spawns: Vec<(u16, u16)>,
bat_spawns: Vec<(u16, u16)>,
@ -40,33 +40,14 @@ struct Level {
impl Level {
fn load_level(
mut backdrop: BackgroundRegular<'static>,
mut foreground: BackgroundRegular<'static>,
mut clouds: BackgroundRegular<'static>,
mut backdrop: InfiniteScrolledMap,
mut foreground: InfiniteScrolledMap,
mut clouds: InfiniteScrolledMap,
vram: &mut VRamManager,
) -> Self {
backdrop.set_position(Vector2D::new(0, 0));
backdrop.set_map(agb::display::background::Map::new(
tilemap::BACKGROUND_MAP,
Vector2D::new(tilemap::WIDTH, tilemap::HEIGHT),
0,
));
backdrop.set_priority(Priority::P2);
foreground.set_position(Vector2D::new(0, 0));
foreground.set_map(agb::display::background::Map::new(
tilemap::FOREGROUND_MAP,
Vector2D::new(tilemap::WIDTH, tilemap::HEIGHT),
0,
));
foreground.set_priority(Priority::P0);
clouds.set_position(Vector2D::new(0, -5));
clouds.set_map(agb::display::background::Map::new(
tilemap::CLOUD_MAP,
Vector2D::new(tilemap::WIDTH, tilemap::HEIGHT),
0,
));
clouds.set_priority(Priority::P3);
backdrop.init(vram, (8, 8).into());
foreground.init(vram, (8, 8).into());
clouds.init(vram, (2, 2).into());
backdrop.commit();
foreground.commit();
@ -1804,8 +1785,6 @@ struct Game<'a> {
boss: BossState<'a>,
move_state: MoveState,
fade_count: u16,
background_distributor: &'a mut BackgroundDistributor,
}
enum MoveState {
@ -1826,6 +1805,7 @@ impl<'a> Game<'a> {
fn advance_frame(
&mut self,
object_controller: &'a ObjectControl,
vram: &mut VRamManager,
sfx: &mut sfx::Sfx,
) -> GameStatus {
let mut state = GameStatus::Continue;
@ -1845,7 +1825,7 @@ impl<'a> Game<'a> {
self.offset.x = (tilemap::WIDTH as i32 * 8 - 248).into();
}
MoveState::FollowingPlayer => {
Game::update_sunrise(self.background_distributor, self.sunrise_timer);
Game::update_sunrise(vram, self.sunrise_timer);
if self.sunrise_timer < 120 {
self.sunrise_timer += 1;
} else {
@ -1867,7 +1847,7 @@ impl<'a> Game<'a> {
if boss.gone {
self.fade_count += 1;
self.fade_count = self.fade_count.min(600);
Game::update_fade_out(self.background_distributor, self.fade_count);
Game::update_fade_out(vram, self.fade_count);
}
}
}
@ -1969,15 +1949,11 @@ impl<'a> Game<'a> {
self.player.commit(this_frame_offset);
self.boss.commit(this_frame_offset);
self.level
.background
.set_position(this_frame_offset.floor());
self.level
.foreground
.set_position(this_frame_offset.floor());
self.level
.clouds
.set_position(this_frame_offset.floor() / 4);
let background_offset = (this_frame_offset.floor().x + 8, 8).into();
self.level.background.set_pos(vram, background_offset);
self.level.foreground.set_pos(vram, background_offset);
self.level.clouds.set_pos(vram, background_offset / 4);
self.level.background.commit();
self.level.foreground.commit();
self.level.clouds.commit();
@ -2082,7 +2058,7 @@ impl<'a> Game<'a> {
}
}
fn update_sunrise(background_distributor: &'a mut BackgroundDistributor, time: u16) {
fn update_sunrise(vram: &mut VRamManager, time: u16) {
let mut modified_palette = background::background.palettes[0].clone();
let a = modified_palette.get_colour(0);
@ -2093,10 +2069,10 @@ impl<'a> Game<'a> {
let modified_palettes = [modified_palette];
background_distributor.set_background_palettes(&modified_palettes);
vram.set_background_palettes(&modified_palettes);
}
fn update_fade_out(background_distributor: &'a mut BackgroundDistributor, time: u16) {
fn update_fade_out(vram: &mut VRamManager, time: u16) {
let mut modified_palette = background::background.palettes[0].clone();
let c = modified_palette.get_colour(2);
@ -2107,15 +2083,10 @@ impl<'a> Game<'a> {
let modified_palettes = [modified_palette];
background_distributor.set_background_palettes(&modified_palettes);
vram.set_background_palettes(&modified_palettes);
}
fn new(
object: &'a ObjectControl,
level: Level,
background_distributor: &'a mut BackgroundDistributor,
start_at_boss: bool,
) -> Self {
fn new(object: &'a ObjectControl, level: Level, start_at_boss: bool) -> Self {
let mut player = Player::new(object);
let mut offset = (8, 8).into();
if start_at_boss {
@ -2139,8 +2110,6 @@ impl<'a> Game<'a> {
move_state: MoveState::Advancing,
sunrise_timer: 0,
fade_count: 0,
background_distributor,
}
}
}
@ -2170,19 +2139,59 @@ fn game_with_level(gba: &mut agb::Gba) {
loop {
let mut background = gba.display.video.tiled0();
background.set_background_palettes(background::background.palettes);
background.set_background_tilemap(0, background::background.tiles);
background
.vram
.set_background_palettes(background::background.palettes);
let tileset_ref = background.vram.add_tileset(TileSet::new(
background::background.tiles,
TileFormat::FourBpp,
));
let mut object = gba.display.object.get();
object.enable();
let backdrop = InfiniteScrolledMap::new(
background.background(Priority::P2),
Box::new(move |pos| {
(
tileset_ref,
TileSetting::from_raw(
tilemap::BACKGROUND_MAP[(pos.x + tilemap::WIDTH * pos.y) as usize],
),
)
}),
);
let foreground = InfiniteScrolledMap::new(
background.background(Priority::P0),
Box::new(move |pos| {
(
tileset_ref,
TileSetting::from_raw(
tilemap::FOREGROUND_MAP[(pos.x + tilemap::WIDTH * pos.y) as usize],
),
)
}),
);
let clouds = InfiniteScrolledMap::new(
background.background(Priority::P3),
Box::new(move |pos| {
agb::println!("CLOUDS: {}, {}", pos.x, pos.y);
(
tileset_ref,
TileSetting::from_raw(
tilemap::CLOUD_MAP[(pos.x + tilemap::WIDTH * pos.y) as usize],
),
)
}),
);
let mut game = Game::new(
&object,
Level::load_level(
background.get_regular().unwrap(),
background.get_regular().unwrap(),
background.get_regular().unwrap(),
),
&mut background,
Level::load_level(backdrop, foreground, clouds, &mut background.vram),
start_at_boss,
);
@ -2190,7 +2199,7 @@ fn game_with_level(gba: &mut agb::Gba) {
sfx.frame();
vblank.wait_for_vblank();
sfx.after_vblank();
match game.advance_frame(&object, &mut sfx) {
match game.advance_frame(&object, &mut background.vram, &mut sfx) {
GameStatus::Continue => {}
GameStatus::Lost => {
break false;