update hat chooses wizard

This commit is contained in:
Corwin 2022-02-24 21:45:14 +00:00
parent 4780b8525d
commit 8a6f341421
9 changed files with 442 additions and 144 deletions

View file

@ -10,7 +10,7 @@ description = "Library for converting graphics for use on the Game Boy Advance"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
image = { version = "0.24.1", default-features = false, features = [ "png", "bmp" ] } image = { version = "0.23", default-features = false, features = [ "png", "bmp" ] }
toml = "0.5.8" toml = "0.5.8"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
syn = "1.0.86" syn = "1.0.86"

View file

@ -258,6 +258,7 @@ impl Attributes {
pub struct Object<'a, 'b> { pub struct Object<'a, 'b> {
sprite: SpriteBorrow<'a>, sprite: SpriteBorrow<'a>,
previous_sprite: SpriteBorrow<'a>,
loan: Loan<'b>, loan: Loan<'b>,
attrs: Attributes, attrs: Attributes,
} }
@ -316,8 +317,10 @@ impl ObjectController {
index: inner.pop()?, index: inner.pop()?,
free_list: &self.free_objects, free_list: &self.free_objects,
}; };
let p_sprite = sprite.clone();
Some(Object { Some(Object {
sprite, sprite,
previous_sprite: p_sprite,
loan, loan,
attrs: Attributes::new(), attrs: Attributes::new(),
}) })
@ -363,8 +366,18 @@ impl<'a, 'b> Object<'a, 'b> {
} }
pub fn set_x(&mut self, x: u16) -> &mut Self { pub fn set_x(&mut self, x: u16) -> &mut Self {
self.attrs.a1a.set_x(x as u16); self.attrs.a1a.set_x(x.rem_euclid(1 << 9) as u16);
self.attrs.a1s.set_x(x as u16); self.attrs.a1s.set_x(x.rem_euclid(1 << 9) as u16);
self
}
pub fn set_priority(&mut self, priority: Priority) -> &mut Self {
self.attrs.a2.set_priority(priority);
self
}
pub fn hide(&mut self) -> &mut Self {
self.attrs.a0.set_object_mode(ObjectMode::Disabled);
self self
} }
@ -376,12 +389,12 @@ impl<'a, 'b> Object<'a, 'b> {
pub fn set_position(&mut self, position: Vector2D<i32>) -> &mut Self { pub fn set_position(&mut self, position: Vector2D<i32>) -> &mut Self {
self.attrs.a0.set_y(position.y as u8); self.attrs.a0.set_y(position.y as u8);
self.attrs.a1a.set_x(position.x as u16); self.attrs.a1a.set_x(position.x.rem_euclid(1 << 9) as u16);
self.attrs.a1s.set_x(position.x as u16); self.attrs.a1s.set_x(position.x.rem_euclid(1 << 9) as u16);
self self
} }
pub fn commit(&self) { pub fn commit(&mut self) {
let mode = self.attrs.a0.object_mode(); let mode = self.attrs.a0.object_mode();
let attrs: [[u8; 2]; 3] = match mode { let attrs: [[u8; 2]; 3] = match mode {
ObjectMode::Normal => [ ObjectMode::Normal => [
@ -404,6 +417,7 @@ impl<'a, 'b> Object<'a, 'b> {
ptr.add(1).write_volatile(attrs[1]); ptr.add(1).write_volatile(attrs[1]);
ptr.add(2).write_volatile(attrs[2]); ptr.add(2).write_volatile(attrs[2]);
}; };
self.previous_sprite = self.sprite.clone();
} }
} }
@ -579,6 +593,20 @@ impl<'a> Drop for SpriteBorrow<'a> {
} }
} }
impl<'a> Clone for SpriteBorrow<'a> {
fn clone(&self) -> Self {
let mut inner = self.controller.borrow_mut();
inner.sprite.entry(self.id).and_modify(|a| a.count += 1);
let _ = inner.get_palette(self.id.get_sprite().palette).unwrap();
Self {
id: self.id,
sprite_location: self.sprite_location,
palette_location: self.palette_location,
controller: self.controller,
}
}
}
#[derive(BitfieldSpecifier, Clone, Copy)] #[derive(BitfieldSpecifier, Clone, Copy)]
enum ObjectMode { enum ObjectMode {
Normal, Normal,

View file

@ -2,5 +2,10 @@
"files.associations": { "files.associations": {
"*.tsx": "xml", "*.tsx": "xml",
"*.tmx": "xml" "*.tmx": "xml"
} },
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.extraArgs": [
"--target",
"thumbv4t-none-eabi"
]
} }

View file

@ -24,6 +24,10 @@ dependencies = [
"agb_sound_converter", "agb_sound_converter",
"bare-metal", "bare-metal",
"bitflags", "bitflags",
"hashbrown",
"modular-bitfield",
"phf",
"rustc-hash",
] ]
[[package]] [[package]]
@ -37,6 +41,7 @@ dependencies = [
name = "agb_image_converter" name = "agb_image_converter"
version = "0.6.0" version = "0.6.0"
dependencies = [ dependencies = [
"asefile",
"image", "image",
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -64,6 +69,31 @@ dependencies = [
"syn", "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 = "asefile"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0d5f7de918fd4cb18249819fc4bd27f6a5dbfbc9dcb271727f27dacf17ce880"
dependencies = [
"bitflags",
"byteorder",
"flate2",
"image",
"log",
"nohash",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -117,11 +147,44 @@ dependencies = [
[[package]] [[package]]
name = "deflate" name = "deflate"
version = "1.0.0" version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
dependencies = [ dependencies = [
"adler32", "adler32",
"byteorder",
]
[[package]]
name = "flate2"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
dependencies = [
"cfg-if",
"crc32fast",
"libc",
"miniz_oxide 0.4.4",
]
[[package]]
name = "getrandom"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
dependencies = [
"ahash",
] ]
[[package]] [[package]]
@ -132,9 +195,9 @@ checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549"
[[package]] [[package]]
name = "image" name = "image"
version = "0.24.1" version = "0.23.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db207d030ae38f1eb6f240d5a1c1c88ff422aa005d10f8c6c6fc5e75286ab30e" checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"byteorder", "byteorder",
@ -152,14 +215,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]] [[package]]
name = "miniz_oxide" name = "libc"
version = "0.5.1" version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "miniz_oxide"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
dependencies = [
"adler32",
]
[[package]]
name = "miniz_oxide"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
dependencies = [ dependencies = [
"adler", "adler",
"autocfg",
] ]
[[package]]
name = "modular-bitfield"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74"
dependencies = [
"modular-bitfield-impl",
"static_assertions",
]
[[package]]
name = "modular-bitfield-impl"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "nohash"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0f889fb66f7acdf83442c35775764b51fed3c606ab9cee51500dbde2cf528ca"
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.44" version = "0.1.44"
@ -183,9 +298,9 @@ dependencies = [
[[package]] [[package]]
name = "num-rational" name = "num-rational"
version = "0.4.0" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"num-integer", "num-integer",
@ -202,17 +317,79 @@ dependencies = [
] ]
[[package]] [[package]]
name = "png" name = "once_cell"
version = "0.17.5" version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "phf"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
"phf_macros",
"phf_shared",
"proc-macro-hack",
]
[[package]]
name = "phf_generator"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_macros"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "phf_shared"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
dependencies = [
"siphasher",
]
[[package]]
name = "png"
version = "0.16.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"crc32fast", "crc32fast",
"deflate", "deflate",
"miniz_oxide", "miniz_oxide 0.3.7",
] ]
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.36" version = "1.0.36"
@ -231,6 +408,42 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.9" version = "1.0.9"
@ -268,6 +481,18 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "siphasher"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.86" version = "1.0.86"
@ -302,3 +527,15 @@ name = "unicode-xid"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -1,6 +0,0 @@
version = "1.0"
[image.object_sheet]
filename = "object_sheet.png"
tile_size = "8x8"
transparent_colour = "2ce8f4"

View file

@ -1,6 +1,8 @@
use super::{object_tiles, sfx::SfxPlayer, Entity, FixedNumberType, HatState, Level}; use crate::TAG_MAP;
use super::{sfx::SfxPlayer, Entity, FixedNumberType, HatState, Level};
use agb::{ use agb::{
display::object::{ObjectControl, Size}, display::object::{ObjectController, Size},
fixnum::Vector2D, fixnum::Vector2D,
}; };
@ -28,11 +30,11 @@ pub enum EnemyUpdateState {
} }
impl<'a> Enemy<'a> { impl<'a> Enemy<'a> {
pub fn new_slime(object: &'a ObjectControl, start_pos: Vector2D<FixedNumberType>) -> Self { pub fn new_slime(object: &'a ObjectController, start_pos: Vector2D<FixedNumberType>) -> Self {
Enemy::Slime(Slime::new(object, start_pos + (0, 1).into())) Enemy::Slime(Slime::new(object, start_pos + (0, 1).into()))
} }
pub fn new_snail(object: &'a ObjectControl, start_pos: Vector2D<FixedNumberType>) -> Self { pub fn new_snail(object: &'a ObjectController, start_pos: Vector2D<FixedNumberType>) -> Self {
Enemy::Snail(Snail::new(object, start_pos)) Enemy::Snail(Snail::new(object, start_pos))
} }
@ -45,6 +47,7 @@ impl<'a> Enemy<'a> {
pub fn update( pub fn update(
&mut self, &mut self,
controller: &'a ObjectController,
level: &Level, level: &Level,
player_pos: Vector2D<FixedNumberType>, player_pos: Vector2D<FixedNumberType>,
hat_state: HatState, hat_state: HatState,
@ -52,8 +55,12 @@ impl<'a> Enemy<'a> {
sfx_player: &mut SfxPlayer, sfx_player: &mut SfxPlayer,
) -> EnemyUpdateState { ) -> EnemyUpdateState {
let update_state = match self { let update_state = match self {
Enemy::Slime(slime) => slime.update(level, player_pos, hat_state, timer, sfx_player), Enemy::Slime(slime) => {
Enemy::Snail(snail) => snail.update(level, player_pos, hat_state, timer, sfx_player), slime.update(controller, level, player_pos, hat_state, timer, sfx_player)
}
Enemy::Snail(snail) => {
snail.update(controller, level, player_pos, hat_state, timer, sfx_player)
}
Enemy::Empty => UpdateState::Nothing, Enemy::Empty => UpdateState::Nothing,
}; };
@ -82,7 +89,7 @@ struct EnemyInfo<'a> {
impl<'a> EnemyInfo<'a> { impl<'a> EnemyInfo<'a> {
fn new( fn new(
object: &'a ObjectControl, object: &'a ObjectController,
start_pos: Vector2D<FixedNumberType>, start_pos: Vector2D<FixedNumberType>,
collision: Vector2D<u16>, collision: Vector2D<u16>,
) -> Self { ) -> Self {
@ -123,19 +130,18 @@ pub struct Slime<'a> {
} }
impl<'a> Slime<'a> { impl<'a> Slime<'a> {
fn new(object: &'a ObjectControl, start_pos: Vector2D<FixedNumberType>) -> Self { fn new(object: &'a ObjectController, start_pos: Vector2D<FixedNumberType>) -> Self {
let mut slime = Slime { let mut slime = Slime {
enemy_info: EnemyInfo::new(object, start_pos, (14u16, 14u16).into()), enemy_info: EnemyInfo::new(object, start_pos, (14u16, 14u16).into()),
state: SlimeState::Idle, state: SlimeState::Idle,
}; };
slime.enemy_info.entity.sprite.set_sprite_size(Size::S16x16);
slime slime
} }
fn update( fn update(
&mut self, &mut self,
controller: &'a ObjectController,
level: &Level, level: &Level,
player_pos: Vector2D<FixedNumberType>, player_pos: Vector2D<FixedNumberType>,
hat_state: HatState, hat_state: HatState,
@ -147,11 +153,13 @@ impl<'a> Slime<'a> {
match self.state { match self.state {
SlimeState::Idle => { SlimeState::Idle => {
let offset = (timer / 16 % 2) * 4; let offset = (timer / 16) as usize;
self.enemy_info
.entity let tag = TAG_MAP.get("Slime Idle").unwrap();
.sprite let frame = tag.get_animation_sprite(offset);
.set_tile_id(object_tiles::SLIME_IDLE_START + offset as u16); let sprite = controller.get_sprite(frame).unwrap();
self.enemy_info.entity.sprite.set_sprite(sprite);
if (self.enemy_info.entity.position - player_pos).magnitude_squared() if (self.enemy_info.entity.position - player_pos).magnitude_squared()
< (64 * 64).into() < (64 * 64).into()
@ -178,7 +186,7 @@ impl<'a> Slime<'a> {
} }
} }
SlimeState::Jumping(jumping_start_frame) => { SlimeState::Jumping(jumping_start_frame) => {
let offset = (timer - jumping_start_frame) / 4; let offset = (timer - jumping_start_frame) as usize / 4;
if timer == jumping_start_frame + 1 { if timer == jumping_start_frame + 1 {
sfx_player.slime_jump(); sfx_player.slime_jump();
@ -188,12 +196,11 @@ impl<'a> Slime<'a> {
self.enemy_info.entity.velocity = (0, 0).into(); self.enemy_info.entity.velocity = (0, 0).into();
self.state = SlimeState::Idle; self.state = SlimeState::Idle;
} else { } else {
let sprite_offset = if offset >= 4 { 7 - offset } else { offset }; let tag = TAG_MAP.get("Slime Jump").unwrap();
let frame = tag.get_animation_sprite(offset);
let sprite = controller.get_sprite(frame).unwrap();
self.enemy_info self.enemy_info.entity.sprite.set_sprite(sprite);
.entity
.sprite
.set_tile_id(object_tiles::SLIME_JUMP_START + (sprite_offset * 4) as u16);
} }
if player_has_collided { if player_has_collided {
@ -209,17 +216,18 @@ impl<'a> Slime<'a> {
sfx_player.slime_death(); sfx_player.slime_death();
} }
let offset = (timer - dying_start_frame) / 4; let offset = (timer - dying_start_frame) as usize / 4;
self.enemy_info.entity.velocity = (0, 0).into(); self.enemy_info.entity.velocity = (0, 0).into();
if offset >= 4 { if offset >= 4 {
return UpdateState::Remove; return UpdateState::Remove;
} }
self.enemy_info let tag = TAG_MAP.get("Slime splat").unwrap();
.entity let frame = tag.get_animation_sprite(offset);
.sprite let sprite = controller.get_sprite(frame).unwrap();
.set_tile_id(object_tiles::SLIME_SPLAT_START + (offset * 4) as u16);
self.enemy_info.entity.sprite.set_sprite(sprite);
} }
} }
@ -247,14 +255,12 @@ pub struct Snail<'a> {
} }
impl<'a> Snail<'a> { impl<'a> Snail<'a> {
fn new(object: &'a ObjectControl, start_pos: Vector2D<FixedNumberType>) -> Self { fn new(object: &'a ObjectController, start_pos: Vector2D<FixedNumberType>) -> Self {
let mut snail = Snail { let mut snail = Snail {
enemy_info: EnemyInfo::new(object, start_pos, (16u16, 16u16).into()), enemy_info: EnemyInfo::new(object, start_pos, (16u16, 16u16).into()),
state: SnailState::Idle(0), state: SnailState::Idle(0),
}; };
snail.enemy_info.entity.sprite.set_sprite_size(Size::S16x16);
snail snail
} }
@ -264,6 +270,7 @@ impl<'a> Snail<'a> {
fn update( fn update(
&mut self, &mut self,
controller: &'a ObjectController,
level: &Level, level: &Level,
player_pos: Vector2D<FixedNumberType>, player_pos: Vector2D<FixedNumberType>,
hat_state: HatState, hat_state: HatState,
@ -288,10 +295,11 @@ impl<'a> Snail<'a> {
} }
} }
self.enemy_info let tag = TAG_MAP.get("Snail Idle").unwrap();
.entity let frame = tag.get_animation_sprite(0);
.sprite let sprite = controller.get_sprite(frame).unwrap();
.set_tile_id(object_tiles::SNAIL_IDLE_START);
self.enemy_info.entity.sprite.set_sprite(sprite);
if player_has_collided { if player_has_collided {
if hat_state != HatState::WizardTowards { if hat_state != HatState::WizardTowards {
return UpdateState::KillPlayer; return UpdateState::KillPlayer;
@ -301,17 +309,18 @@ impl<'a> Snail<'a> {
} }
} }
SnailState::Emerging(time) => { SnailState::Emerging(time) => {
let offset = (timer - time) / 4; let offset = (timer - time) as usize / 4;
if offset >= 5 { if offset >= 5 {
self.state = SnailState::Moving(timer); self.state = SnailState::Moving(timer);
} }
self.enemy_info.entity.velocity = (0, 0).into(); self.enemy_info.entity.velocity = (0, 0).into();
self.enemy_info let tag = TAG_MAP.get("Snail Emerge").unwrap();
.entity let frame = tag.get_animation_sprite(offset);
.sprite let sprite = controller.get_sprite(frame).unwrap();
.set_tile_id(object_tiles::SNAIL_EMERGE_START + (offset * 4) as u16);
self.enemy_info.entity.sprite.set_sprite(sprite);
if player_has_collided { if player_has_collided {
if hat_state != HatState::WizardTowards { if hat_state != HatState::WizardTowards {
@ -328,12 +337,13 @@ impl<'a> Snail<'a> {
sfx_player.snail_retreat(); sfx_player.snail_retreat();
} }
let offset = (timer - time) / 8 % 2; let offset = (timer - time) as usize / 8;
self.enemy_info let tag = TAG_MAP.get("Snail Move").unwrap();
.entity let frame = tag.get_animation_sprite(offset);
.sprite let sprite = controller.get_sprite(frame).unwrap();
.set_tile_id(object_tiles::SNAIL_MOVE + (offset * 4) as u16);
self.enemy_info.entity.sprite.set_sprite(sprite);
if timer % 32 == 0 { if timer % 32 == 0 {
let x_vel: FixedNumberType = let x_vel: FixedNumberType =
@ -358,16 +368,17 @@ impl<'a> Snail<'a> {
} }
} }
SnailState::Retreating(time) => { SnailState::Retreating(time) => {
let offset = 5 - (timer - time) / 4; let offset = 5 - (timer - time) as usize / 4;
if offset == 0 { if offset == 0 {
self.state = SnailState::Idle(timer); self.state = SnailState::Idle(timer);
} }
self.enemy_info let tag = TAG_MAP.get("Snail Emerge").unwrap();
.entity let frame = tag.get_animation_sprite(offset);
.sprite let sprite = controller.get_sprite(frame).unwrap();
.set_tile_id(object_tiles::SNAIL_EMERGE_START + (offset * 4) as u16);
self.enemy_info.entity.sprite.set_sprite(sprite);
self.enemy_info.entity.velocity = (0, 0).into(); self.enemy_info.entity.velocity = (0, 0).into();
if player_has_collided { if player_has_collided {
@ -383,18 +394,26 @@ impl<'a> Snail<'a> {
sfx_player.snail_death(); sfx_player.snail_death();
} }
let offset = (timer - time) / 4; let offset = (timer - time) as usize / 4;
let tile_id = if offset < 5 { let frame = if offset < 5 {
object_tiles::SNAIL_EMERGE_START + ((5 - offset) * 4) as u16 TAG_MAP
.get("Snail Emerge")
.unwrap()
.get_animation_sprite(5 - offset)
} else if offset == 5 { } else if offset == 5 {
object_tiles::SNAIL_IDLE_START TAG_MAP.get("Snail Idle").unwrap().get_animation_sprite(0)
} else if offset < 5 + 7 { } else if offset < 5 + 7 {
object_tiles::SNAIL_DEATH_START + ((offset - 5) * 4) as u16 TAG_MAP
.get("Snail Death")
.unwrap()
.get_animation_sprite(offset - 5)
} else { } else {
return UpdateState::Remove; return UpdateState::Remove;
}; };
self.enemy_info.entity.sprite.set_tile_id(tile_id); let sprite = controller.get_sprite(frame).unwrap();
self.enemy_info.entity.sprite.set_sprite(sprite);
self.enemy_info.entity.velocity = (0, 0).into(); self.enemy_info.entity.velocity = (0, 0).into();
} }
} }

View file

@ -18,27 +18,6 @@ pub struct Level {
start_pos: (i32, i32), start_pos: (i32, i32),
} }
mod object_tiles {
pub const WIZARD_TILE_START: u16 = 0;
pub const WIZARD_JUMP: u16 = 4 * 4;
pub const WIZARD_FALL_START: u16 = 5 * 4;
pub const HAT_TILE_START: u16 = 9 * 4;
pub const HAT_TILE_START_SECOND: u16 = 28 * 4;
pub const HAT_TILE_START_THIRD: u16 = 38 * 4;
pub const SLIME_IDLE_START: u16 = 19 * 4;
pub const SLIME_JUMP_START: u16 = 20 * 4;
pub const SLIME_SPLAT_START: u16 = 24 * 4;
pub const SNAIL_IDLE_START: u16 = 48 * 4;
pub const SNAIL_EMERGE_START: u16 = 49 * 4;
pub const SNAIL_MOVE: u16 = 54 * 4;
pub const SNAIL_DEATH_START: u16 = 56 * 4;
}
agb::include_gfx!("gfx/object_sheet.toml");
mod map_tiles { mod map_tiles {
use super::Level; use super::Level;
@ -106,25 +85,32 @@ agb::include_gfx!("gfx/tile_sheet.toml");
use agb::{ use agb::{
display::{ display::{
background::BackgroundRegular, background::BackgroundRegular,
object::{ObjectControl, ObjectStandard, Size}, object::{Object, ObjectController, Sprite, TagMap},
Priority, HEIGHT, WIDTH, Priority, HEIGHT, WIDTH,
}, },
fixnum::{FixedNum, Vector2D}, fixnum::{FixedNum, Vector2D},
input::{self, Button, ButtonController}, input::{self, Button, ButtonController},
}; };
const SPRITE_TAGS: (&[Sprite], &TagMap) = agb::include_aseprite!("gfx/sprites.aseprite");
const SPRITES: &[Sprite] = SPRITE_TAGS.0;
const TAG_MAP: &TagMap = SPRITE_TAGS.1;
type FixedNumberType = FixedNum<10>; type FixedNumberType = FixedNum<10>;
pub struct Entity<'a> { pub struct Entity<'a> {
sprite: ObjectStandard<'a>, sprite: Object<'a, 'a>,
position: Vector2D<FixedNumberType>, position: Vector2D<FixedNumberType>,
velocity: Vector2D<FixedNumberType>, velocity: Vector2D<FixedNumberType>,
collision_mask: Vector2D<u16>, collision_mask: Vector2D<u16>,
} }
impl<'a> Entity<'a> { impl<'a> Entity<'a> {
pub fn new(object: &'a ObjectControl, collision_mask: Vector2D<u16>) -> Self { pub fn new(object: &'a ObjectController, collision_mask: Vector2D<u16>) -> Self {
let mut sprite = object.get_object_standard(); let dummy_sprite = object
.get_sprite(TAG_MAP.get("Walking").unwrap().get_sprite(0))
.unwrap();
let mut sprite = object.get_object(dummy_sprite).unwrap();
sprite.set_priority(Priority::P1); sprite.set_priority(Priority::P1);
Entity { Entity {
sprite, sprite,
@ -360,14 +346,21 @@ fn ping_pong(i: i32, n: i32) -> i32 {
} }
impl<'a> Player<'a> { impl<'a> Player<'a> {
fn new(controller: &'a ObjectControl, start_position: Vector2D<FixedNumberType>) -> Self { fn new(controller: &'a ObjectController, start_position: Vector2D<FixedNumberType>) -> Self {
let mut hat = Entity::new(controller, (6_u16, 6_u16).into());
let mut wizard = Entity::new(controller, (6_u16, 14_u16).into()); let mut wizard = Entity::new(controller, (6_u16, 14_u16).into());
let mut hat = Entity::new(controller, (6_u16, 6_u16).into());
wizard.sprite.set_sprite(
controller
.get_sprite(TAG_MAP.get("Walking").unwrap().get_sprite(0))
.unwrap(),
);
hat.sprite.set_sprite(
controller
.get_sprite(TAG_MAP.get("HatSpin").unwrap().get_sprite(0))
.unwrap(),
);
wizard.sprite.set_tile_id(object_tiles::WIZARD_TILE_START);
hat.sprite.set_tile_id(object_tiles::HAT_TILE_START);
wizard.sprite.set_sprite_size(Size::S16x16);
hat.sprite.set_sprite_size(Size::S16x16);
wizard.sprite.show(); wizard.sprite.show();
hat.sprite.show(); hat.sprite.show();
@ -393,6 +386,7 @@ impl<'a> Player<'a> {
fn update_frame( fn update_frame(
&mut self, &mut self,
input: &ButtonController, input: &ButtonController,
controller: &'a ObjectController,
timer: i32, timer: i32,
level: &Level, level: &Level,
enemies: &[enemies::Enemy], enemies: &[enemies::Enemy],
@ -467,23 +461,29 @@ impl<'a> Player<'a> {
self.wizard.velocity = self.wizard.update_position(level); self.wizard.velocity = self.wizard.update_position(level);
if self.wizard.velocity.x.abs() > 0.into() { if self.wizard.velocity.x.abs() > 0.into() {
let offset = (ping_pong(timer / 16, 4)) as u16; let offset = (ping_pong(timer / 16, 4)) as usize;
self.wizard_frame = offset as u8; self.wizard_frame = offset as u8;
self.wizard let walk = TAG_MAP.get("Walking").unwrap();
.sprite let frame = walk.get_animation_sprite(offset);
.set_tile_id(object_tiles::WIZARD_TILE_START + offset * 4); let sprite = controller.get_sprite(frame).unwrap();
self.wizard.sprite.set_sprite(sprite);
} }
if self.wizard.velocity.y < -FixedNumberType::new(1) / 16 { if self.wizard.velocity.y < -FixedNumberType::new(1) / 16 {
// going up // going up
self.wizard_frame = 5; self.wizard_frame = 5;
self.wizard.sprite.set_tile_id(object_tiles::WIZARD_JUMP); let walk = TAG_MAP.get("Jumping").unwrap();
let frame = walk.get_animation_sprite(0);
let sprite = controller.get_sprite(frame).unwrap();
self.wizard.sprite.set_sprite(sprite);
} else if self.wizard.velocity.y > FixedNumberType::new(1) / 16 { } else if self.wizard.velocity.y > FixedNumberType::new(1) / 16 {
// going down // going down
let offset = if self.wizard.velocity.y * 2 > 3.into() { let offset = if self.wizard.velocity.y * 2 > 3.into() {
((timer / 4) % 4) as u16 (timer / 4) as usize
} else { } else {
// Don't flap beard unless going quickly // Don't flap beard unless going quickly
0 0
@ -491,9 +491,11 @@ impl<'a> Player<'a> {
self.wizard_frame = 0; self.wizard_frame = 0;
self.wizard let walk = TAG_MAP.get("Falling").unwrap();
.sprite let frame = walk.get_animation_sprite(offset);
.set_tile_id(object_tiles::WIZARD_FALL_START + offset * 4); let sprite = controller.get_sprite(frame).unwrap();
self.wizard.sprite.set_sprite(sprite);
} }
if input.x_tri() != agb::input::Tri::Zero { if input.x_tri() != agb::input::Tri::Zero {
@ -502,19 +504,23 @@ impl<'a> Player<'a> {
} }
let hat_base_tile = match self.num_recalls { let hat_base_tile = match self.num_recalls {
0 => object_tiles::HAT_TILE_START, 0 => TAG_MAP.get("HatSpin").unwrap(),
1 => object_tiles::HAT_TILE_START_SECOND, 1 => TAG_MAP.get("HatSpin2").unwrap(),
_ => object_tiles::HAT_TILE_START_THIRD, _ => TAG_MAP.get("HatSpin3").unwrap(),
}; };
match self.facing { match self.facing {
agb::input::Tri::Negative => { agb::input::Tri::Negative => {
self.wizard.sprite.set_hflip(true); self.wizard.sprite.set_hflip(true);
self.hat.sprite.set_tile_id(hat_base_tile + 4 * 5); self.hat
.sprite
.set_sprite(controller.get_sprite(hat_base_tile.get_sprite(5)).unwrap());
} }
agb::input::Tri::Positive => { agb::input::Tri::Positive => {
self.wizard.sprite.set_hflip(false); self.wizard.sprite.set_hflip(false);
self.hat.sprite.set_tile_id(hat_base_tile); self.hat
.sprite
.set_sprite(controller.get_sprite(hat_base_tile.get_sprite(0)).unwrap());
} }
_ => {} _ => {}
} }
@ -543,11 +549,13 @@ impl<'a> Player<'a> {
_ => 4, _ => 4,
}; };
let hat_sprite_offset = timer / hat_sprite_divider % 10; let hat_sprite_offset = (timer / hat_sprite_divider) as usize;
self.hat self.hat.sprite.set_sprite(
.sprite controller
.set_tile_id(hat_base_tile + (hat_sprite_offset * 4) as u16); .get_sprite(hat_base_tile.get_animation_sprite(hat_sprite_offset))
.unwrap(),
);
if self.hat_slow_counter < 30 && self.hat.velocity.magnitude() < 2.into() { if self.hat_slow_counter < 30 && self.hat.velocity.magnitude() < 2.into() {
self.hat.velocity = (0, 0).into(); self.hat.velocity = (0, 0).into();
@ -578,9 +586,11 @@ impl<'a> Player<'a> {
self.hat.position = self.wizard.position - hat_resting_position; self.hat.position = self.wizard.position - hat_resting_position;
} }
HatState::WizardTowards => { HatState::WizardTowards => {
self.hat self.hat.sprite.set_sprite(
.sprite controller
.set_tile_id(hat_base_tile + 4 * (timer / 2 % 10) as u16); .get_sprite(hat_base_tile.get_animation_sprite(timer as usize / 2))
.unwrap(),
);
let distance_vector = let distance_vector =
self.hat.position - self.wizard.position + hat_resting_position; self.hat.position - self.wizard.position + hat_resting_position;
let distance = distance_vector.magnitude(); let distance = distance_vector.magnitude();
@ -617,7 +627,7 @@ enum UpdateState {
impl<'a, 'b, 'c> PlayingLevel<'a, 'b> { impl<'a, 'b, 'c> PlayingLevel<'a, 'b> {
fn open_level( fn open_level(
level: &'a Level, level: &'a Level,
object_control: &'a ObjectControl, object_control: &'a ObjectController,
background: &'a mut BackgroundRegular<'b>, background: &'a mut BackgroundRegular<'b>,
foreground: &'a mut BackgroundRegular<'b>, foreground: &'a mut BackgroundRegular<'b>,
input: ButtonController, input: ButtonController,
@ -676,22 +686,27 @@ impl<'a, 'b, 'c> PlayingLevel<'a, 'b> {
self.player.wizard.sprite.set_priority(Priority::P0); self.player.wizard.sprite.set_priority(Priority::P0);
} }
fn dead_update(&mut self) -> bool { fn dead_update(&mut self, controller: &'a ObjectController) -> bool {
self.timer += 1; self.timer += 1;
let tag = TAG_MAP.get("Player Death").unwrap();
let frame = tag.get_animation_sprite(self.timer as usize / 8);
let sprite = controller.get_sprite(frame).unwrap();
self.player.wizard.velocity += (0.into(), FixedNumberType::new(1) / 32).into(); self.player.wizard.velocity += (0.into(), FixedNumberType::new(1) / 32).into();
self.player.wizard.position += self.player.wizard.velocity; self.player.wizard.position += self.player.wizard.velocity;
self.player self.player.wizard.sprite.set_sprite(sprite);
.wizard
.sprite
.set_tile_id((self.timer / 8 % 2 * 4 + 63 * 4) as u16);
self.player.wizard.commit_position(self.background.position); self.player.wizard.commit_position(self.background.position);
self.player.wizard.position.y - self.background.position.y < (HEIGHT + 8).into() self.player.wizard.position.y - self.background.position.y < (HEIGHT + 8).into()
} }
fn update_frame(&mut self, sfx_player: &mut sfx::SfxPlayer) -> UpdateState { fn update_frame(
&mut self,
controller: &'a ObjectController,
sfx_player: &mut sfx::SfxPlayer,
) -> UpdateState {
self.timer += 1; self.timer += 1;
self.input.update(); self.input.update();
@ -699,6 +714,7 @@ impl<'a, 'b, 'c> PlayingLevel<'a, 'b> {
self.player.update_frame( self.player.update_frame(
&self.input, &self.input,
controller,
self.timer, self.timer,
self.background.level, self.background.level,
&self.enemies, &self.enemies,
@ -707,6 +723,7 @@ impl<'a, 'b, 'c> PlayingLevel<'a, 'b> {
for enemy in self.enemies.iter_mut() { for enemy in self.enemies.iter_mut() {
match enemy.update( match enemy.update(
controller,
self.background.level, self.background.level,
self.player.wizard.position, self.player.wizard.position,
self.player.hat_state, self.player.hat_state,
@ -784,8 +801,6 @@ fn main(mut agb: agb::Gba) -> ! {
tiled.set_background_palettes(tile_sheet::background.palettes); tiled.set_background_palettes(tile_sheet::background.palettes);
tiled.set_background_tilemap(0, tile_sheet::background.tiles); tiled.set_background_tilemap(0, tile_sheet::background.tiles);
object.set_sprite_palettes(object_sheet::object_sheet.palettes);
object.set_sprite_tilemap(object_sheet::object_sheet.tiles);
let mut world_display = tiled.get_raw_regular().unwrap(); let mut world_display = tiled.get_raw_regular().unwrap();
world_display.clear(level_display::BLANK); world_display.clear(level_display::BLANK);
@ -793,7 +808,6 @@ fn main(mut agb: agb::Gba) -> ! {
let mut background = tiled.get_regular().unwrap(); let mut background = tiled.get_regular().unwrap();
let mut foreground = tiled.get_regular().unwrap(); let mut foreground = tiled.get_regular().unwrap();
object.enable();
mixer.enable(); mixer.enable();
let mut music_box = sfx::MusicBox::new(); let mut music_box = sfx::MusicBox::new();
@ -856,11 +870,12 @@ fn main(mut agb: agb::Gba) -> ! {
world_display.hide(); world_display.hide();
loop { loop {
match level.update_frame(&mut sfx::SfxPlayer::new(&mut mixer, &music_box)) { match level.update_frame(&object, &mut sfx::SfxPlayer::new(&mut mixer, &music_box))
{
UpdateState::Normal => {} UpdateState::Normal => {}
UpdateState::Dead => { UpdateState::Dead => {
level.dead_start(); level.dead_start();
while level.dead_update() { while level.dead_update(&object) {
music_box.before_frame(&mut mixer); music_box.before_frame(&mut mixer);
mixer.frame(); mixer.frame();
vblank.wait_for_vblank(); vblank.wait_for_vblank();