mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-26 00:56:38 +11:00
chicken object added
This commit is contained in:
parent
0bd99e71bd
commit
432c7f12f0
3 changed files with 215 additions and 12 deletions
|
@ -2,19 +2,33 @@
|
||||||
#![feature(start)]
|
#![feature(start)]
|
||||||
|
|
||||||
extern crate gba;
|
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 {
|
struct Vector2D {
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn frame_ranger(count: u32, start: u32, end: u32, delay: u32) -> u32 {
|
||||||
|
((count / delay) % (end + 1 - start)) + start
|
||||||
|
}
|
||||||
|
|
||||||
#[start]
|
#[start]
|
||||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
let mut gba = gba::Gba::new();
|
let mut gba = gba::Gba::new();
|
||||||
let mut gfx = gba.display.video.tiled0();
|
let mut gfx = gba.display.video.tiled0();
|
||||||
let vblank = gba.display.vblank.get();
|
let vblank = gba.display.vblank.get();
|
||||||
|
let mut input = gba::input::ButtonController::new();
|
||||||
|
|
||||||
gfx.set_sprite_palette(&CHICKEN_PALETTE);
|
gfx.set_sprite_palette(&CHICKEN_PALETTE);
|
||||||
gfx.set_sprite_tilemap(&CHICKEN_TILES);
|
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.background_0.set_screen_base_block(1);
|
||||||
gfx.copy_to_map(1, &MAP_MAP);
|
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 {
|
loop {
|
||||||
vblank.wait_for_VBlank();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,134 @@
|
||||||
#[non_exhaustive]
|
use super::DISPLAY_CONTROL;
|
||||||
pub struct Object {}
|
|
||||||
|
|
||||||
impl Object {
|
const OBJECT_MEMORY_STANDARD: *mut [ObjectAttributeStandard; 128] = 0x0700_0000 as *mut [_; 128];
|
||||||
pub(crate) fn new() -> Self {
|
|
||||||
Object {}
|
#[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 set_x(&mut self, x: u8) {
|
||||||
|
self.attributes.set_x(x)
|
||||||
pub fn disable(&mut self) {}
|
}
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use core::convert::TryInto;
|
||||||
use crate::memory_mapped::MemoryMapped1DArray;
|
use crate::memory_mapped::MemoryMapped1DArray;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
object::Object, set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings,
|
object::ObjectControl, set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings,
|
||||||
DISPLAY_CONTROL,
|
DISPLAY_CONTROL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ pub struct Tiled0 {
|
||||||
pub background_1: Background,
|
pub background_1: Background,
|
||||||
pub background_2: Background,
|
pub background_2: Background,
|
||||||
pub background_3: Background,
|
pub background_3: Background,
|
||||||
pub object: Object,
|
pub object: ObjectControl,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tiled0 {
|
impl Tiled0 {
|
||||||
|
@ -114,7 +114,7 @@ impl Tiled0 {
|
||||||
background_1: Background { layer: 1 },
|
background_1: Background { layer: 1 },
|
||||||
background_2: Background { layer: 2 },
|
background_2: Background { layer: 2 },
|
||||||
background_3: Background { layer: 3 },
|
background_3: Background { layer: 3 },
|
||||||
object: Object::new(),
|
object: ObjectControl::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue