chicken object added

This commit is contained in:
Corwin Kuiper 2021-03-12 13:43:09 +00:00 committed by Corwin
parent 0bd99e71bd
commit 432c7f12f0
3 changed files with 215 additions and 12 deletions

View file

@ -2,19 +2,33 @@
#![feature(start)]
extern crate gba;
use core::convert::{Into, TryInto};
use gba::{
display::{object::ObjectStandard, tiled0, HEIGHT, WIDTH},
number::Num,
};
use gba::display::tiled0;
struct Character {
object: ObjectStandard,
position: Vector2D,
velocity: Vector2D,
}
struct Vector2D {
x: i32,
y: i32,
}
fn frame_ranger(count: u32, start: u32, end: u32, delay: u32) -> u32 {
((count / delay) % (end + 1 - start)) + start
}
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
let mut gba = gba::Gba::new();
let mut gfx = gba.display.video.tiled0();
let vblank = gba.display.vblank.get();
let mut input = gba::input::ButtonController::new();
gfx.set_sprite_palette(&CHICKEN_PALETTE);
gfx.set_sprite_tilemap(&CHICKEN_TILES);
@ -33,8 +47,75 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
gfx.background_0.set_screen_base_block(1);
gfx.copy_to_map(1, &MAP_MAP);
let mut object = gfx.object;
object.enable();
unsafe { object.clear_objects() };
let mut chicken = Character {
object: object.get_object(0),
position: Vector2D {
x: 20 << 8,
y: 20 << 8,
},
velocity: Vector2D { x: 0, y: 0 },
};
chicken.object.set_tile_id(0);
chicken
.object
.set_x((chicken.position.x >> 8).try_into().unwrap());
chicken
.object
.set_y((chicken.position.y >> 8).try_into().unwrap());
chicken.object.commit();
let acceleration = 1 << 8;
let mut frame_count = 0;
loop {
vblank.wait_for_VBlank();
frame_count += 1;
input.update();
// Horizontal movement
chicken.velocity.x += (input.x_tri() as i32) * acceleration;
chicken.velocity.x = 10 * chicken.velocity.x / 16;
// Update position based on velocity
chicken.position.x += chicken.velocity.x;
chicken.position.y += chicken.velocity.y;
// Ensure the chicken remains within bounds
chicken.position.x = chicken.position.x.clamp(0, (WIDTH - 8) << 8);
chicken.position.y = chicken.position.y.clamp(0, (HEIGHT - 8) << 8);
// Update direction the chicken is facing
if chicken.velocity.x > 1 {
chicken.object.set_hflip(false);
} else if chicken.velocity.x < -1 {
chicken.object.set_hflip(true);
}
// Update the frame of the chicken
if (chicken.velocity.x != 0) {
chicken
.object
.set_tile_id(frame_ranger(frame_count, 1, 3, 10));
} else {
chicken.object.set_tile_id(0);
}
// Update the position of the chicken
chicken
.object
.set_x((chicken.position.x >> 8).try_into().unwrap());
chicken
.object
.set_y((chicken.position.y >> 8).try_into().unwrap());
// Commit the chicken to vram
chicken.object.commit();
}
}

View file

@ -1,12 +1,134 @@
#[non_exhaustive]
pub struct Object {}
use super::DISPLAY_CONTROL;
impl Object {
pub(crate) fn new() -> Self {
Object {}
const OBJECT_MEMORY_STANDARD: *mut [ObjectAttributeStandard; 128] = 0x0700_0000 as *mut [_; 128];
#[non_exhaustive]
pub struct ObjectControl {}
#[non_exhaustive]
pub struct ObjectStandard {
attributes: ObjectAttributeStandard,
id: usize,
}
pub enum Mode {
Normal = 0,
Affline = 1,
Hidden = 2,
AfflineDouble = 3,
}
impl ObjectStandard {
pub fn commit(&self) {
unsafe {
(&mut (*OBJECT_MEMORY_STANDARD)[self.id] as *mut ObjectAttributeStandard)
.write_volatile(self.attributes)
}
}
pub fn enable(&mut self) {}
pub fn disable(&mut self) {}
pub fn set_x(&mut self, x: u8) {
self.attributes.set_x(x)
}
pub fn set_y(&mut self, y: u8) {
self.attributes.set_y(y)
}
pub fn set_tile_id(&mut self, id: u32) {
self.attributes.set_tile_id(id)
}
pub fn set_hflip(&mut self, hflip: bool) {
self.attributes.set_hflip(hflip)
}
}
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct ObjectAttributeStandard {
low: u32,
high: u32,
}
impl ObjectAttributeStandard {
pub fn set_hflip(&mut self, hflip: bool) {
let mask = (1 << 0xC) << 16;
let attr = self.low;
let attr = attr & !mask;
if hflip {
self.low = attr | mask
} else {
self.low = attr
}
}
pub fn set_x(&mut self, x: u8) {
let mask = ((1 << 8) - 1) << 16;
let attr1 = self.low;
let attr_without_x = attr1 & !mask;
let attr_with_new_x = attr_without_x | ((x as u32) << 16);
self.low = attr_with_new_x;
}
pub fn set_y(&mut self, y: u8) {
let mask = (1 << 8) - 1;
let attr0 = self.low;
let attr_without_y = attr0 & !mask;
let attr_with_new_y = attr_without_y | y as u32;
self.low = attr_with_new_y;
}
pub fn set_tile_id(&mut self, id: u32) {
let mask = (1 << 9) - 1;
assert!(id <= mask, "tile id is greater than 9 bits");
let attr = self.high;
let attr = attr & !mask;
let attr = attr | id;
self.high = attr;
}
pub fn set_mode(&mut self, mode: Mode) {
let mask = 0b11 << 0x8;
self.low = (self.low & !mask) | ((mode as u32) << 0x8);
}
}
impl ObjectAttributeStandard {
fn new() -> Self {
ObjectAttributeStandard { low: 0, high: 0 }
}
}
impl ObjectControl {
pub(crate) fn new() -> Self {
ObjectControl {}
}
/// # Safety
/// Temporary
pub unsafe fn clear_objects(&mut self) {
let mut o = ObjectAttributeStandard::new();
o.set_mode(Mode::Hidden);
for index in 0..(*OBJECT_MEMORY_STANDARD).len() {
(&mut (*OBJECT_MEMORY_STANDARD)[index] as *mut ObjectAttributeStandard)
.write_volatile(o);
}
}
pub fn enable(&mut self) {
let disp = DISPLAY_CONTROL.get();
let disp = disp | (1 << 0x0C);
DISPLAY_CONTROL.set(disp);
}
pub fn disable(&mut self) {
let disp = DISPLAY_CONTROL.get();
let disp = disp & !(1 << 0x0C);
DISPLAY_CONTROL.set(disp);
}
pub fn get_object(&self, id: usize) -> ObjectStandard {
assert!(id < 128, "object id must be less than 128");
ObjectStandard {
attributes: ObjectAttributeStandard::new(),
id,
}
}
}

View file

@ -3,7 +3,7 @@ use core::convert::TryInto;
use crate::memory_mapped::MemoryMapped1DArray;
use super::{
object::Object, set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings,
object::ObjectControl, set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings,
DISPLAY_CONTROL,
};
@ -102,7 +102,7 @@ pub struct Tiled0 {
pub background_1: Background,
pub background_2: Background,
pub background_3: Background,
pub object: Object,
pub object: ObjectControl,
}
impl Tiled0 {
@ -114,7 +114,7 @@ impl Tiled0 {
background_1: Background { layer: 1 },
background_2: Background { layer: 2 },
background_3: Background { layer: 3 },
object: Object::new(),
object: ObjectControl::new(),
}
}