mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-11 09:31:34 +11:00
Merge pull request #171 from corwinkuiper/objects
Better objects, again!
This commit is contained in:
commit
3c2483bc95
83
agb-image-converter/Cargo.lock
generated
83
agb-image-converter/Cargo.lock
generated
|
@ -18,6 +18,7 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||||
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",
|
||||||
|
@ -26,6 +27,20 @@ dependencies = [
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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"
|
||||||
|
@ -73,18 +88,31 @@ 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]]
|
[[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",
|
||||||
|
@ -96,14 +124,45 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[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 = "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"
|
||||||
|
@ -127,9 +186,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",
|
||||||
|
@ -147,14 +206,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.5"
|
version = "0.16.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba"
|
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"deflate",
|
"deflate",
|
||||||
"miniz_oxide",
|
"miniz_oxide 0.3.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -10,9 +10,10 @@ 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"
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
|
asefile = "0.3.2"
|
||||||
|
|
23
agb-image-converter/src/aseprite.rs
Normal file
23
agb-image-converter/src/aseprite.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use asefile::{AsepriteFile, Tag};
|
||||||
|
use image::DynamicImage;
|
||||||
|
|
||||||
|
pub fn generate_from_file(filename: &Path) -> (Vec<DynamicImage>, Vec<Tag>) {
|
||||||
|
let ase = AsepriteFile::read_file(filename).expect("Aseprite file should exist");
|
||||||
|
|
||||||
|
let mut images = Vec::new();
|
||||||
|
let mut tags = Vec::new();
|
||||||
|
|
||||||
|
for frame in 0..ase.num_frames() {
|
||||||
|
let image = ase.frame(frame).image();
|
||||||
|
|
||||||
|
images.push(DynamicImage::ImageRgba8(image))
|
||||||
|
}
|
||||||
|
|
||||||
|
for tag in 0..ase.num_tags() {
|
||||||
|
tags.push(ase.tag(tag).clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
(images, tags)
|
||||||
|
}
|
|
@ -13,6 +13,10 @@ pub(crate) struct Image {
|
||||||
impl Image {
|
impl Image {
|
||||||
pub fn load_from_file(image_path: &path::Path) -> Self {
|
pub fn load_from_file(image_path: &path::Path) -> Self {
|
||||||
let img = image::open(image_path).expect("Expected image to exist");
|
let img = image::open(image_path).expect("Expected image to exist");
|
||||||
|
Self::load_from_dyn_image(img)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_from_dyn_image(img: image::DynamicImage) -> Self {
|
||||||
let (width, height) = img.dimensions();
|
let (width, height) = img.dimensions();
|
||||||
|
|
||||||
let width = width as usize;
|
let width = width as usize;
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
|
use palette16::Palette16OptimisationResults;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use syn::parse_macro_input;
|
use proc_macro2::Literal;
|
||||||
|
use syn::parse::Parser;
|
||||||
|
use syn::{parse_macro_input, punctuated::Punctuated, LitStr};
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
use std::{iter, path::Path, str};
|
||||||
|
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote, ToTokens};
|
||||||
|
|
||||||
|
mod aseprite;
|
||||||
mod colour;
|
mod colour;
|
||||||
mod config;
|
mod config;
|
||||||
mod image_loader;
|
mod image_loader;
|
||||||
mod palette16;
|
mod palette16;
|
||||||
mod rust_generator;
|
mod rust_generator;
|
||||||
|
|
||||||
|
use image::GenericImageView;
|
||||||
use image_loader::Image;
|
use image_loader::Image;
|
||||||
|
|
||||||
use colour::Colour;
|
use colour::Colour;
|
||||||
|
@ -56,7 +62,7 @@ pub fn include_gfx(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
let images = config.images();
|
let images = config.images();
|
||||||
let image_code = images.iter().map(|(image_name, &image)| {
|
let image_code = images.iter().map(|(image_name, &image)| {
|
||||||
convert_image(image, parent, &image_name, &config.crate_prefix())
|
convert_image(image, parent, image_name, &config.crate_prefix())
|
||||||
});
|
});
|
||||||
|
|
||||||
let module = quote! {
|
let module = quote! {
|
||||||
|
@ -70,6 +76,126 @@ pub fn include_gfx(input: TokenStream) -> TokenStream {
|
||||||
TokenStream::from(module)
|
TokenStream::from(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use quote::TokenStreamExt;
|
||||||
|
struct ByteString<'a>(&'a [u8]);
|
||||||
|
impl ToTokens for ByteString<'_> {
|
||||||
|
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||||
|
tokens.append(Literal::byte_string(self.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn include_aseprite_inner(input: TokenStream) -> TokenStream {
|
||||||
|
let parser = Punctuated::<LitStr, syn::Token![,]>::parse_separated_nonempty;
|
||||||
|
let parsed = match parser.parse(input) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(e) => return e.to_compile_error().into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut optimiser = palette16::Palette16Optimiser::new();
|
||||||
|
let mut images = Vec::new();
|
||||||
|
let mut tags = Vec::new();
|
||||||
|
|
||||||
|
let root = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get cargo manifest dir");
|
||||||
|
|
||||||
|
let filenames: Vec<PathBuf> = parsed
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.value())
|
||||||
|
.map(|s| Path::new(&root).join(&*s))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for filename in filenames.iter() {
|
||||||
|
let (frames, tag) = aseprite::generate_from_file(filename);
|
||||||
|
|
||||||
|
tags.push((tag, images.len()));
|
||||||
|
|
||||||
|
for frame in frames {
|
||||||
|
let width = frame.width();
|
||||||
|
assert!(width == frame.height() && width.is_power_of_two() && width <= 32);
|
||||||
|
|
||||||
|
let image = Image::load_from_dyn_image(frame);
|
||||||
|
add_to_optimiser(&mut optimiser, &image, width as usize);
|
||||||
|
images.push(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let optimised_results = optimiser.optimise_palettes(None);
|
||||||
|
|
||||||
|
let (palette_data, tile_data, assignments) = palete_tile_data(&optimised_results, &images);
|
||||||
|
|
||||||
|
let palette_data = palette_data.iter().map(|colours| {
|
||||||
|
quote! {
|
||||||
|
Palette16::new([
|
||||||
|
#(#colours),*
|
||||||
|
])
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut pre = 0;
|
||||||
|
let sprites = images
|
||||||
|
.iter()
|
||||||
|
.zip(assignments.iter())
|
||||||
|
.map(|(f, assignment)| {
|
||||||
|
let start: usize = pre;
|
||||||
|
let end: usize = pre + (f.width / 8) * (f.height / 8) * 32;
|
||||||
|
let data = ByteString(&tile_data[start..end]);
|
||||||
|
pre = end;
|
||||||
|
let width = f.width;
|
||||||
|
let height = f.height;
|
||||||
|
quote! {
|
||||||
|
Sprite::new(
|
||||||
|
&PALETTES[#assignment],
|
||||||
|
#data,
|
||||||
|
Size::from_width_height(#width, #height)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let tags = tags.iter().flat_map(|(tag, num_images)| {
|
||||||
|
tag.iter().map(move |tag| {
|
||||||
|
let start = tag.from_frame() as usize + num_images;
|
||||||
|
let end = tag.to_frame() as usize + num_images;
|
||||||
|
let direction = tag.animation_direction() as usize;
|
||||||
|
|
||||||
|
let name = tag.name();
|
||||||
|
assert!(start <= end, "Tag {} has start > end", name);
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
(#name, Tag::new(SPRITES, #start, #end, #direction))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let include_paths = filenames.iter().map(|s| {
|
||||||
|
let s = s.as_os_str().to_string_lossy();
|
||||||
|
quote! {
|
||||||
|
const _: &[u8] = include_bytes!(#s);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let module = quote! {
|
||||||
|
#(#include_paths)*
|
||||||
|
|
||||||
|
|
||||||
|
const PALETTES: &[Palette16] = &[
|
||||||
|
#(#palette_data),*
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const SPRITES: &[Sprite] = &[
|
||||||
|
#(#sprites),*
|
||||||
|
];
|
||||||
|
|
||||||
|
const TAGS: &TagMap = &TagMap::new(
|
||||||
|
&[
|
||||||
|
#(#tags),*
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenStream::from(module)
|
||||||
|
}
|
||||||
|
|
||||||
fn convert_image(
|
fn convert_image(
|
||||||
settings: &dyn config::Image,
|
settings: &dyn config::Image,
|
||||||
parent: &Path,
|
parent: &Path,
|
||||||
|
@ -98,11 +224,19 @@ fn convert_image(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16Optimiser {
|
fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16Optimiser {
|
||||||
|
let mut palette_optimiser = palette16::Palette16Optimiser::new();
|
||||||
|
add_to_optimiser(&mut palette_optimiser, image, tile_size);
|
||||||
|
palette_optimiser
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_to_optimiser(
|
||||||
|
palette_optimiser: &mut palette16::Palette16Optimiser,
|
||||||
|
image: &Image,
|
||||||
|
tile_size: usize,
|
||||||
|
) {
|
||||||
let tiles_x = image.width / tile_size;
|
let tiles_x = image.width / tile_size;
|
||||||
let tiles_y = image.height / tile_size;
|
let tiles_y = image.height / tile_size;
|
||||||
|
|
||||||
let mut palette_optimiser = palette16::Palette16Optimiser::new();
|
|
||||||
|
|
||||||
for y in 0..tiles_y {
|
for y in 0..tiles_y {
|
||||||
for x in 0..tiles_x {
|
for x in 0..tiles_x {
|
||||||
let mut palette = palette16::Palette16::new();
|
let mut palette = palette16::Palette16::new();
|
||||||
|
@ -118,6 +252,74 @@ fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16O
|
||||||
palette_optimiser.add_palette(palette);
|
palette_optimiser.add_palette(palette);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
palette_optimiser
|
|
||||||
|
fn palete_tile_data(
|
||||||
|
optimiser: &Palette16OptimisationResults,
|
||||||
|
images: &[Image],
|
||||||
|
) -> (Vec<Vec<u16>>, Vec<u8>, Vec<usize>) {
|
||||||
|
let palette_data: Vec<Vec<u16>> = optimiser
|
||||||
|
.optimised_palettes
|
||||||
|
.iter()
|
||||||
|
.map(|palette| {
|
||||||
|
palette
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(|colour| colour.to_rgb15())
|
||||||
|
.chain(iter::repeat(0))
|
||||||
|
.take(16)
|
||||||
|
.map(|colour| colour as u16)
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut tile_data = Vec::new();
|
||||||
|
|
||||||
|
for image in images {
|
||||||
|
let tile_size = image.height;
|
||||||
|
let tiles_x = image.width / tile_size;
|
||||||
|
let tiles_y = image.height / tile_size;
|
||||||
|
|
||||||
|
for y in 0..tiles_y {
|
||||||
|
for x in 0..tiles_x {
|
||||||
|
let palette_index = optimiser.assignments[y * tiles_x + x];
|
||||||
|
let palette = &optimiser.optimised_palettes[palette_index];
|
||||||
|
|
||||||
|
for inner_y in 0..tile_size / 8 {
|
||||||
|
for inner_x in 0..tile_size / 8 {
|
||||||
|
for j in inner_y * 8..inner_y * 8 + 8 {
|
||||||
|
for i in inner_x * 8..inner_x * 8 + 8 {
|
||||||
|
let colour = image.colour(x * tile_size + i, y * tile_size + j);
|
||||||
|
tile_data.push(palette.colour_index(colour));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tile_data = tile_data
|
||||||
|
.chunks(2)
|
||||||
|
.map(|chunk| chunk[0] | (chunk[1] << 4))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let assignments = optimiser.assignments.clone();
|
||||||
|
|
||||||
|
(palette_data, tile_data, assignments)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use asefile::AnimationDirection;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// These directions defined in agb and have these values. This is important
|
||||||
|
// when outputting code for agb. If more animation directions are added then
|
||||||
|
// we will have to support them there.
|
||||||
|
fn directions_to_agb() {
|
||||||
|
assert_eq!(AnimationDirection::Forward as usize, 0);
|
||||||
|
assert_eq!(AnimationDirection::Reverse as usize, 1);
|
||||||
|
assert_eq!(AnimationDirection::PingPong as usize, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,12 +151,12 @@ impl Palette16Optimiser {
|
||||||
let mut a_colour_is_used = false;
|
let mut a_colour_is_used = false;
|
||||||
|
|
||||||
for current_palette in unsatisfied_palettes {
|
for current_palette in unsatisfied_palettes {
|
||||||
if palette.union_length(¤t_palette) > MAX_COLOURS_PER_PALETTE {
|
if palette.union_length(current_palette) > MAX_COLOURS_PER_PALETTE {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for colour in ¤t_palette.colours {
|
for colour in ¤t_palette.colours {
|
||||||
if palette.colours.contains(&colour) {
|
if palette.colours.contains(colour) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
170
agb/Cargo.lock
generated
170
agb/Cargo.lock
generated
|
@ -24,6 +24,9 @@ dependencies = [
|
||||||
"agb_sound_converter",
|
"agb_sound_converter",
|
||||||
"bare-metal",
|
"bare-metal",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"hashbrown",
|
||||||
|
"modular-bitfield",
|
||||||
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -37,6 +40,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 +68,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 +146,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 +194,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",
|
||||||
|
@ -146,14 +208,66 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[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"
|
||||||
|
@ -177,9 +291,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",
|
||||||
|
@ -196,15 +310,21 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "once_cell"
|
||||||
version = "0.17.5"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba"
|
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
|
@ -225,6 +345,12 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.136"
|
version = "1.0.136"
|
||||||
|
@ -245,6 +371,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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"
|
||||||
|
@ -270,3 +402,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"
|
||||||
|
|
|
@ -15,8 +15,7 @@ lto = true
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["alloc"]
|
default = []
|
||||||
alloc = []
|
|
||||||
freq18157 = ["agb_sound_converter/freq18157"]
|
freq18157 = ["agb_sound_converter/freq18157"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -26,6 +25,9 @@ agb_sound_converter = { version = "0.1.0", path = "../agb-sound-converter" }
|
||||||
agb_macros = { version = "0.1.0", path = "../agb-macros" }
|
agb_macros = { version = "0.1.0", path = "../agb-macros" }
|
||||||
agb_fixnum = { version = "0.1.0", path = "../agb-fixnum" }
|
agb_fixnum = { version = "0.1.0", path = "../agb-fixnum" }
|
||||||
bare-metal = "1.0"
|
bare-metal = "1.0"
|
||||||
|
hashbrown = "0.12.0"
|
||||||
|
modular-bitfield = "0.11.2"
|
||||||
|
rustc-hash = { version = "1.0", default-features = false }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
default-target = "thumbv6m-none-eabi"
|
default-target = "thumbv6m-none-eabi"
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use agb::{
|
use agb::{
|
||||||
display::{background::Map, object::ObjectStandard, HEIGHT, WIDTH},
|
display::{
|
||||||
|
background::Map,
|
||||||
|
object::{Object, ObjectController, Size, Sprite},
|
||||||
|
palette16::Palette16,
|
||||||
|
HEIGHT, WIDTH,
|
||||||
|
},
|
||||||
input::Button,
|
input::Button,
|
||||||
};
|
};
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
@ -15,7 +20,7 @@ enum State {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Character<'a> {
|
struct Character<'a> {
|
||||||
object: ObjectStandard<'a>,
|
object: Object<'a, 'a>,
|
||||||
position: Vector2D,
|
position: Vector2D,
|
||||||
velocity: Vector2D,
|
velocity: Vector2D,
|
||||||
}
|
}
|
||||||
|
@ -30,8 +35,8 @@ fn tile_is_collidable(tile: u16) -> bool {
|
||||||
masked == 0 || masked == 4
|
masked == 0 || masked == 4
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_ranger(count: u32, start: u32, end: u32, delay: u32) -> u16 {
|
fn frame_ranger(count: u32, start: u32, end: u32, delay: u32) -> usize {
|
||||||
(((count / delay) % (end + 1 - start)) + start) as u16
|
(((count / delay) % (end + 1 - start)) + start) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
#[agb::entry]
|
#[agb::entry]
|
||||||
|
@ -54,14 +59,11 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
background.show();
|
background.show();
|
||||||
background.commit();
|
background.commit();
|
||||||
|
|
||||||
let mut object = gba.display.object.get();
|
let object = gba.display.object.get();
|
||||||
|
|
||||||
object.set_sprite_palette_raw(&CHICKEN_PALETTE);
|
let sprite = object.get_sprite(&ChickenSprites[0]).unwrap();
|
||||||
object.set_sprite_tilemap(&CHICKEN_TILES);
|
|
||||||
|
|
||||||
object.enable();
|
|
||||||
let mut chicken = Character {
|
let mut chicken = Character {
|
||||||
object: object.get_object_standard(),
|
object: object.get_object(sprite).unwrap(),
|
||||||
position: Vector2D {
|
position: Vector2D {
|
||||||
x: (6 * 8) << 8,
|
x: (6 * 8) << 8,
|
||||||
y: ((7 * 8) - 4) << 8,
|
y: ((7 * 8) - 4) << 8,
|
||||||
|
@ -69,7 +71,6 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
velocity: Vector2D { x: 0, y: 0 },
|
velocity: Vector2D { x: 0, y: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
chicken.object.set_tile_id(0);
|
|
||||||
chicken
|
chicken
|
||||||
.object
|
.object
|
||||||
.set_x((chicken.position.x >> 8).try_into().unwrap());
|
.set_x((chicken.position.x >> 8).try_into().unwrap());
|
||||||
|
@ -120,14 +121,19 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
restrict_to_screen(&mut chicken);
|
restrict_to_screen(&mut chicken);
|
||||||
update_chicken_object(&mut chicken, state, frame_count);
|
update_chicken_object(&mut chicken, &object, state, frame_count);
|
||||||
|
|
||||||
// Commit the chicken to vram
|
// Commit the chicken to vram
|
||||||
chicken.object.commit();
|
chicken.object.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_chicken_object(chicken: &mut Character, state: State, frame_count: u32) {
|
fn update_chicken_object<'a>(
|
||||||
|
chicken: &'_ mut Character<'a>,
|
||||||
|
object: &'a ObjectController,
|
||||||
|
state: State,
|
||||||
|
frame_count: u32,
|
||||||
|
) {
|
||||||
if chicken.velocity.x > 1 {
|
if chicken.velocity.x > 1 {
|
||||||
chicken.object.set_hflip(false);
|
chicken.object.set_hflip(false);
|
||||||
} else if chicken.velocity.x < -1 {
|
} else if chicken.velocity.x < -1 {
|
||||||
|
@ -136,18 +142,24 @@ fn update_chicken_object(chicken: &mut Character, state: State, frame_count: u32
|
||||||
match state {
|
match state {
|
||||||
State::Ground => {
|
State::Ground => {
|
||||||
if chicken.velocity.x.abs() > 1 << 4 {
|
if chicken.velocity.x.abs() > 1 << 4 {
|
||||||
|
chicken.object.set_sprite(
|
||||||
|
object
|
||||||
|
.get_sprite(&ChickenSprites[frame_ranger(frame_count, 1, 3, 10)])
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
chicken
|
chicken
|
||||||
.object
|
.object
|
||||||
.set_tile_id(frame_ranger(frame_count, 1, 3, 10));
|
.set_sprite(object.get_sprite(&ChickenSprites[0]).unwrap());
|
||||||
} else {
|
|
||||||
chicken.object.set_tile_id(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::Upwards => {}
|
State::Upwards => {}
|
||||||
State::Flapping => {
|
State::Flapping => {
|
||||||
chicken
|
chicken.object.set_sprite(
|
||||||
.object
|
object
|
||||||
.set_tile_id(frame_ranger(frame_count, 4, 5, 5));
|
.get_sprite(&ChickenSprites[frame_ranger(frame_count, 4, 5, 5)])
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,16 +244,65 @@ fn handle_collision(
|
||||||
|
|
||||||
// Below is the data for the sprites
|
// Below is the data for the sprites
|
||||||
|
|
||||||
static CHICKEN_TILES: [u32; 8 * 6] = [
|
static ChickenPalette: Palette16 =
|
||||||
0x01100000, 0x11100000, 0x01100010, 0x01111110, 0x01111110, 0x00001000, 0x00001000, 0x00011000,
|
Palette16::new([0x7C1E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
0x01100000, 0x11100000, 0x01100010, 0x01111110, 0x01111110, 0x00010100, 0x00100100, 0x00000010,
|
|
||||||
0x01100000, 0x11100000, 0x01100010, 0x01111110, 0x01111110, 0x00011000, 0x00100110, 0x00100000,
|
|
||||||
0x01100000, 0x11100000, 0x01100010, 0x01111110, 0x01111110, 0x00011000, 0x00011100, 0x00001000,
|
|
||||||
0x01100000, 0x11111100, 0x01111010, 0x01111110, 0x01111110, 0x00011000, 0x00010000, 0x00000000,
|
|
||||||
0x01100000, 0x11100000, 0x01111110, 0x01111110, 0x01111110, 0x00011000, 0x00010000, 0x00000000,
|
|
||||||
];
|
|
||||||
|
|
||||||
static CHICKEN_PALETTE: [u16; 1] = [0x7C1E];
|
static ChickenSprites: &[Sprite] = &[
|
||||||
|
Sprite::new(
|
||||||
|
&ChickenPalette,
|
||||||
|
&[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x00, 0x10, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
||||||
|
0x00, 0x10, 0x01, 0x00,
|
||||||
|
],
|
||||||
|
Size::S8x8,
|
||||||
|
),
|
||||||
|
Sprite::new(
|
||||||
|
&ChickenPalette,
|
||||||
|
&[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x00, 0x10, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x10, 0x00,
|
||||||
|
0x10, 0x00, 0x00, 0x00,
|
||||||
|
],
|
||||||
|
Size::S8x8,
|
||||||
|
),
|
||||||
|
Sprite::new(
|
||||||
|
&ChickenPalette,
|
||||||
|
&[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x00, 0x10, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x01, 0x00, 0x10, 0x01, 0x10, 0x00,
|
||||||
|
0x00, 0x00, 0x10, 0x00,
|
||||||
|
],
|
||||||
|
Size::S8x8,
|
||||||
|
),
|
||||||
|
Sprite::new(
|
||||||
|
&ChickenPalette,
|
||||||
|
&[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x00, 0x10, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00,
|
||||||
|
0x00, 0x10, 0x00, 0x00,
|
||||||
|
],
|
||||||
|
Size::S8x8,
|
||||||
|
),
|
||||||
|
Sprite::new(
|
||||||
|
&ChickenPalette,
|
||||||
|
&[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x11, 0x11, 0x11, 0x10, 0x10, 0x11, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
],
|
||||||
|
Size::S8x8,
|
||||||
|
),
|
||||||
|
Sprite::new(
|
||||||
|
&ChickenPalette,
|
||||||
|
&[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x11, 0x11, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
],
|
||||||
|
Size::S8x8,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
static MAP_TILES: [u32; 8 * 17] = [
|
static MAP_TILES: [u32; 8 * 17] = [
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
|
109
agb/examples/sprites.rs
Normal file
109
agb/examples/sprites.rs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use agb::display::object::{Graphics, ObjectController, Sprite, TagMap};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
const GRAPHICS: &Graphics = agb::include_aseprite!(
|
||||||
|
"../examples/the-purple-night/gfx/objects.aseprite",
|
||||||
|
"../examples/the-purple-night/gfx/boss.aseprite"
|
||||||
|
);
|
||||||
|
const SPRITES: &[Sprite] = GRAPHICS.sprites();
|
||||||
|
const TAG_MAP: &TagMap = GRAPHICS.tags();
|
||||||
|
|
||||||
|
fn all_sprites(gfx: &ObjectController) {
|
||||||
|
let mut input = agb::input::ButtonController::new();
|
||||||
|
let mut objs = Vec::new();
|
||||||
|
|
||||||
|
for y in 0..9 {
|
||||||
|
for x in 0..14 {
|
||||||
|
let mut obj = gfx
|
||||||
|
.get_object(gfx.get_sprite(&SPRITES[0]).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
obj.show();
|
||||||
|
obj.set_position((x * 16 + 8, y * 16 + 8).into());
|
||||||
|
objs.push(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
let mut image = 0;
|
||||||
|
|
||||||
|
let vblank = agb::interrupt::VBlank::get();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
vblank.wait_for_vblank();
|
||||||
|
input.update();
|
||||||
|
|
||||||
|
if input.is_just_pressed(agb::input::Button::A) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
|
||||||
|
if count % 5 == 0 {
|
||||||
|
image += 1;
|
||||||
|
image %= SPRITES.len();
|
||||||
|
let objs_len = objs.len();
|
||||||
|
for (i, obj) in objs.iter_mut().enumerate() {
|
||||||
|
let this_image = (image + i * SPRITES.len() / objs_len) % SPRITES.len();
|
||||||
|
obj.set_sprite(gfx.get_sprite(&SPRITES[this_image]).unwrap());
|
||||||
|
obj.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_tags(gfx: &ObjectController) {
|
||||||
|
let mut input = agb::input::ButtonController::new();
|
||||||
|
let mut objs = Vec::new();
|
||||||
|
|
||||||
|
for (i, v) in TAG_MAP.values().enumerate() {
|
||||||
|
let x = (i % 7) as i32;
|
||||||
|
let y = (i / 7) as i32;
|
||||||
|
let sprite = v.get_sprite(0);
|
||||||
|
let (size_x, size_y) = sprite.size().to_width_height();
|
||||||
|
let (size_x, size_y) = (size_x as i32, size_y as i32);
|
||||||
|
let mut obj = gfx.get_object(gfx.get_sprite(sprite).unwrap()).unwrap();
|
||||||
|
obj.show();
|
||||||
|
obj.set_position((x * 32 + 16 - size_x / 2, y * 32 + 16 - size_y / 2).into());
|
||||||
|
objs.push((obj, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
let mut image = 0;
|
||||||
|
|
||||||
|
let vblank = agb::interrupt::VBlank::get();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
vblank.wait_for_vblank();
|
||||||
|
|
||||||
|
input.update();
|
||||||
|
|
||||||
|
if input.is_just_pressed(agb::input::Button::A) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
|
||||||
|
if count % 5 == 0 {
|
||||||
|
image += 1;
|
||||||
|
for (obj, tag) in objs.iter_mut() {
|
||||||
|
obj.set_sprite(gfx.get_sprite(tag.get_animation_sprite(image)).unwrap());
|
||||||
|
obj.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[agb::entry]
|
||||||
|
fn main(mut gba: agb::Gba) -> ! {
|
||||||
|
let gfx = gba.display.object.get();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
all_tags(&gfx);
|
||||||
|
all_sprites(&gfx);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ use core::ptr::NonNull;
|
||||||
use crate::interrupt::free;
|
use crate::interrupt::free;
|
||||||
use bare_metal::{CriticalSection, Mutex};
|
use bare_metal::{CriticalSection, Mutex};
|
||||||
|
|
||||||
use super::bump_allocator::BumpAllocator;
|
use super::bump_allocator::{BumpAllocator, StartEnd};
|
||||||
use super::SendNonNull;
|
use super::SendNonNull;
|
||||||
|
|
||||||
struct Block {
|
struct Block {
|
||||||
|
@ -49,9 +49,9 @@ pub(crate) struct BlockAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockAllocator {
|
impl BlockAllocator {
|
||||||
pub(super) const unsafe fn new() -> Self {
|
pub const unsafe fn new(start: StartEnd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner_allocator: BumpAllocator::new(),
|
inner_allocator: BumpAllocator::new(start),
|
||||||
state: Mutex::new(RefCell::new(BlockAllocatorState {
|
state: Mutex::new(RefCell::new(BlockAllocatorState {
|
||||||
first_free_block: None,
|
first_free_block: None,
|
||||||
})),
|
})),
|
||||||
|
@ -76,7 +76,7 @@ impl BlockAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Requests a brand new block from the inner bump allocator
|
/// Requests a brand new block from the inner bump allocator
|
||||||
fn new_block(&self, layout: Layout, cs: &CriticalSection) -> *mut u8 {
|
fn new_block(&self, layout: Layout, cs: &CriticalSection) -> Option<NonNull<u8>> {
|
||||||
let overall_layout = Block::either_layout(layout);
|
let overall_layout = Block::either_layout(layout);
|
||||||
self.inner_allocator.alloc_critical(overall_layout, cs)
|
self.inner_allocator.alloc_critical(overall_layout, cs)
|
||||||
}
|
}
|
||||||
|
@ -111,10 +111,8 @@ impl BlockAllocator {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl GlobalAlloc for BlockAllocator {
|
pub unsafe fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
|
||||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
|
||||||
// find a block that this current request fits in
|
// find a block that this current request fits in
|
||||||
let full_layout = Block::either_layout(layout);
|
let full_layout = Block::either_layout(layout);
|
||||||
|
|
||||||
|
@ -133,7 +131,7 @@ unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
let curr_block = curr.as_mut();
|
let curr_block = curr.as_mut();
|
||||||
if curr_block.size == full_layout.size() {
|
if curr_block.size == full_layout.size() {
|
||||||
*list_ptr = curr_block.next;
|
*list_ptr = curr_block.next;
|
||||||
return curr.as_ptr().cast();
|
return Some(curr.cast());
|
||||||
} else if curr_block.size >= block_after_layout.size() {
|
} else if curr_block.size >= block_after_layout.size() {
|
||||||
// can split block
|
// can split block
|
||||||
let split_block = Block {
|
let split_block = Block {
|
||||||
|
@ -148,7 +146,7 @@ unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
*split_ptr = split_block;
|
*split_ptr = split_block;
|
||||||
*list_ptr = NonNull::new(split_ptr).map(SendNonNull);
|
*list_ptr = NonNull::new(split_ptr).map(SendNonNull);
|
||||||
|
|
||||||
return curr.as_ptr().cast();
|
return Some(curr.cast());
|
||||||
}
|
}
|
||||||
current_block = curr_block.next;
|
current_block = curr_block.next;
|
||||||
list_ptr = &mut curr_block.next;
|
list_ptr = &mut curr_block.next;
|
||||||
|
@ -158,7 +156,7 @@ unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
pub unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
let new_layout = Block::either_layout(layout).pad_to_align();
|
let new_layout = Block::either_layout(layout).pad_to_align();
|
||||||
free(|key| {
|
free(|key| {
|
||||||
let mut state = self.state.borrow(*key).borrow_mut();
|
let mut state = self.state.borrow(*key).borrow_mut();
|
||||||
|
@ -200,3 +198,16 @@ unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
self.normalise();
|
self.normalise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
match self.alloc(layout) {
|
||||||
|
None => core::ptr::null_mut(),
|
||||||
|
Some(p) => p.as_ptr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
|
self.dealloc(ptr, layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,26 +6,33 @@ use super::SendNonNull;
|
||||||
use crate::interrupt::free;
|
use crate::interrupt::free;
|
||||||
use bare_metal::{CriticalSection, Mutex};
|
use bare_metal::{CriticalSection, Mutex};
|
||||||
|
|
||||||
|
pub(crate) struct StartEnd {
|
||||||
|
pub start: fn() -> usize,
|
||||||
|
pub end: fn() -> usize,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct BumpAllocator {
|
pub(crate) struct BumpAllocator {
|
||||||
current_ptr: Mutex<RefCell<Option<SendNonNull<u8>>>>,
|
current_ptr: Mutex<RefCell<Option<SendNonNull<u8>>>>,
|
||||||
|
start_end: Mutex<StartEnd>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BumpAllocator {
|
impl BumpAllocator {
|
||||||
pub const fn new() -> Self {
|
pub const fn new(start_end: StartEnd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
current_ptr: Mutex::new(RefCell::new(None)),
|
current_ptr: Mutex::new(RefCell::new(None)),
|
||||||
|
start_end: Mutex::new(start_end),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BumpAllocator {
|
impl BumpAllocator {
|
||||||
pub fn alloc_critical(&self, layout: Layout, cs: &CriticalSection) -> *mut u8 {
|
pub fn alloc_critical(&self, layout: Layout, cs: &CriticalSection) -> Option<NonNull<u8>> {
|
||||||
let mut current_ptr = self.current_ptr.borrow(*cs).borrow_mut();
|
let mut current_ptr = self.current_ptr.borrow(*cs).borrow_mut();
|
||||||
|
|
||||||
let ptr = if let Some(c) = *current_ptr {
|
let ptr = if let Some(c) = *current_ptr {
|
||||||
c.as_ptr() as usize
|
c.as_ptr() as usize
|
||||||
} else {
|
} else {
|
||||||
get_data_end()
|
(self.start_end.borrow(*cs).start)()
|
||||||
};
|
};
|
||||||
|
|
||||||
let alignment_bitmask = layout.align() - 1;
|
let alignment_bitmask = layout.align() - 1;
|
||||||
|
@ -36,53 +43,26 @@ impl BumpAllocator {
|
||||||
let resulting_ptr = ptr + amount_to_add;
|
let resulting_ptr = ptr + amount_to_add;
|
||||||
let new_current_ptr = resulting_ptr + layout.size();
|
let new_current_ptr = resulting_ptr + layout.size();
|
||||||
|
|
||||||
if new_current_ptr as usize >= super::EWRAM_END {
|
if new_current_ptr as usize >= (self.start_end.borrow(*cs).end)() {
|
||||||
return core::ptr::null_mut();
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
*current_ptr = NonNull::new(new_current_ptr as *mut _).map(SendNonNull);
|
*current_ptr = NonNull::new(new_current_ptr as *mut _).map(SendNonNull);
|
||||||
|
|
||||||
resulting_ptr as *mut _
|
NonNull::new(resulting_ptr as *mut _)
|
||||||
}
|
}
|
||||||
pub fn alloc_safe(&self, layout: Layout) -> *mut u8 {
|
pub fn alloc_safe(&self, layout: Layout) -> Option<NonNull<u8>> {
|
||||||
free(|key| self.alloc_critical(layout, key))
|
free(|key| self.alloc_critical(layout, key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl GlobalAlloc for BumpAllocator {
|
unsafe impl GlobalAlloc for BumpAllocator {
|
||||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
self.alloc_safe(layout)
|
match self.alloc_safe(layout) {
|
||||||
|
None => core::ptr::null_mut(),
|
||||||
|
Some(p) => p.as_ptr(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
|
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_data_end() -> usize {
|
|
||||||
extern "C" {
|
|
||||||
static __ewram_data_end: usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This seems completely wrong, but without the &, rust generates
|
|
||||||
// a double dereference :/. Maybe a bug in nightly?
|
|
||||||
(unsafe { &__ewram_data_end }) as *const _ as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test_case]
|
|
||||||
fn should_return_data_end_somewhere_in_ewram(_gba: &mut crate::Gba) {
|
|
||||||
let data_end = get_data_end();
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
0x0200_0000 <= data_end,
|
|
||||||
"data end should be bigger than 0x0200_0000, got {}",
|
|
||||||
data_end
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
0x0204_0000 > data_end,
|
|
||||||
"data end should be smaller than 0x0203_0000"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,11 +2,13 @@ use core::alloc::Layout;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
mod block_allocator;
|
pub(crate) mod block_allocator;
|
||||||
mod bump_allocator;
|
pub(crate) mod bump_allocator;
|
||||||
|
|
||||||
use block_allocator::BlockAllocator;
|
use block_allocator::BlockAllocator;
|
||||||
|
|
||||||
|
use self::bump_allocator::StartEnd;
|
||||||
|
|
||||||
struct SendNonNull<T>(NonNull<T>);
|
struct SendNonNull<T>(NonNull<T>);
|
||||||
unsafe impl<T> Send for SendNonNull<T> {}
|
unsafe impl<T> Send for SendNonNull<T> {}
|
||||||
|
|
||||||
|
@ -33,7 +35,12 @@ impl<T> DerefMut for SendNonNull<T> {
|
||||||
const EWRAM_END: usize = 0x0204_0000;
|
const EWRAM_END: usize = 0x0204_0000;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static GLOBAL_ALLOC: BlockAllocator = unsafe { BlockAllocator::new() };
|
static GLOBAL_ALLOC: BlockAllocator = unsafe {
|
||||||
|
BlockAllocator::new(StartEnd {
|
||||||
|
start: get_data_end,
|
||||||
|
end: || EWRAM_END,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub unsafe fn number_of_blocks() -> u32 {
|
pub unsafe fn number_of_blocks() -> u32 {
|
||||||
|
@ -49,6 +56,16 @@ fn alloc_error(layout: Layout) -> ! {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_data_end() -> usize {
|
||||||
|
extern "C" {
|
||||||
|
static __ewram_data_end: usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This seems completely wrong, but without the &, rust generates
|
||||||
|
// a double dereference :/. Maybe a bug in nightly?
|
||||||
|
(unsafe { &__ewram_data_end }) as *const _ as usize
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
const EWRAM_START: usize = 0x0200_0000;
|
const EWRAM_START: usize = 0x0200_0000;
|
||||||
|
@ -118,4 +135,19 @@ mod test {
|
||||||
assert_eq!(v1[40], 137);
|
assert_eq!(v1[40], 137);
|
||||||
assert_eq!(v2[78], 1075);
|
assert_eq!(v2[78], 1075);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn should_return_data_end_somewhere_in_ewram(_gba: &mut crate::Gba) {
|
||||||
|
let data_end = get_data_end();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
0x0200_0000 <= data_end,
|
||||||
|
"data end should be bigger than 0x0200_0000, got {}",
|
||||||
|
data_end
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
0x0204_0000 > data_end,
|
||||||
|
"data end should be smaller than 0x0203_0000"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::memory_mapped::MemoryMapped;
|
use crate::memory_mapped::MemoryMapped;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
|
use modular_bitfield::BitfieldSpecifier;
|
||||||
use video::Video;
|
use video::Video;
|
||||||
|
|
||||||
use self::object::ObjectControl;
|
use self::object::ObjectController;
|
||||||
|
|
||||||
/// Graphics mode 0. Four regular backgrounds.
|
/// Graphics mode 0. Four regular backgrounds.
|
||||||
pub mod background;
|
pub mod background;
|
||||||
|
@ -69,8 +70,8 @@ pub struct Display {
|
||||||
pub struct ObjectDistribution {}
|
pub struct ObjectDistribution {}
|
||||||
|
|
||||||
impl ObjectDistribution {
|
impl ObjectDistribution {
|
||||||
pub fn get(&mut self) -> ObjectControl {
|
pub fn get(&mut self) -> ObjectController {
|
||||||
ObjectControl::new()
|
ObjectController::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +110,7 @@ pub fn busy_wait_for_vblank() {
|
||||||
while VCOUNT.get() < 160 {}
|
while VCOUNT.get() < 160 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(BitfieldSpecifier)]
|
||||||
pub enum Priority {
|
pub enum Priority {
|
||||||
P0 = 0,
|
P0 = 0,
|
||||||
P1 = 1,
|
P1 = 1,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,4 @@
|
||||||
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Palette16 {
|
pub struct Palette16 {
|
||||||
pub(crate) colours: [u16; 16],
|
pub(crate) colours: [u16; 16],
|
||||||
|
|
|
@ -112,6 +112,8 @@
|
||||||
/// ```
|
/// ```
|
||||||
pub use agb_image_converter::include_gfx;
|
pub use agb_image_converter::include_gfx;
|
||||||
|
|
||||||
|
pub use agb_image_converter::include_aseprite_inner;
|
||||||
|
|
||||||
/// This macro declares the entry point to your game written using `agb`.
|
/// This macro declares the entry point to your game written using `agb`.
|
||||||
///
|
///
|
||||||
/// It is already included in the template, but your `main` function must be annotated with `#[agb::entry]`, takes 1 argument and never returns.
|
/// It is already included in the template, but your `main` function must be annotated with `#[agb::entry]`, takes 1 argument and never returns.
|
||||||
|
@ -133,9 +135,7 @@ pub use agb_macros::entry;
|
||||||
|
|
||||||
pub use agb_sound_converter::include_wav;
|
pub use agb_sound_converter::include_wav;
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
mod agb_alloc;
|
mod agb_alloc;
|
||||||
|
|
||||||
mod arena;
|
mod arena;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
||||||
use crate::display::object::AffineMatrixAttributes;
|
// use crate::display::object::AffineMatrixAttributes;
|
||||||
use crate::fixnum::Num;
|
use crate::fixnum::Num;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -113,55 +113,55 @@ pub fn arc_tan2(x: i16, y: i32) -> i16 {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn affine_matrix(
|
// pub fn affine_matrix(
|
||||||
x_scale: Num<i16, 8>,
|
// x_scale: Num<i16, 8>,
|
||||||
y_scale: Num<i16, 8>,
|
// y_scale: Num<i16, 8>,
|
||||||
rotation: u8,
|
// rotation: u8,
|
||||||
) -> AffineMatrixAttributes {
|
// ) -> AffineMatrixAttributes {
|
||||||
let mut result = AffineMatrixAttributes {
|
// let mut result = AffineMatrixAttributes {
|
||||||
p_a: 0,
|
// p_a: 0,
|
||||||
p_b: 0,
|
// p_b: 0,
|
||||||
p_c: 0,
|
// p_c: 0,
|
||||||
p_d: 0,
|
// p_d: 0,
|
||||||
};
|
// };
|
||||||
|
|
||||||
#[allow(dead_code)]
|
// #[allow(dead_code)]
|
||||||
#[repr(C, packed)]
|
// #[repr(C, packed)]
|
||||||
struct Input {
|
// struct Input {
|
||||||
x_scale: i16,
|
// x_scale: i16,
|
||||||
y_scale: i16,
|
// y_scale: i16,
|
||||||
rotation: u16,
|
// rotation: u16,
|
||||||
}
|
// }
|
||||||
|
|
||||||
let input = Input {
|
// let input = Input {
|
||||||
y_scale: x_scale.to_raw(),
|
// y_scale: x_scale.to_raw(),
|
||||||
x_scale: y_scale.to_raw(),
|
// x_scale: y_scale.to_raw(),
|
||||||
rotation: rotation as u16,
|
// rotation: rotation as u16,
|
||||||
};
|
// };
|
||||||
|
|
||||||
unsafe {
|
// unsafe {
|
||||||
asm!("swi 0x0F",
|
// asm!("swi 0x0F",
|
||||||
in("r0") &input as *const Input as usize,
|
// in("r0") &input as *const Input as usize,
|
||||||
in("r1") &mut result as *mut AffineMatrixAttributes as usize,
|
// in("r1") &mut result as *mut AffineMatrixAttributes as usize,
|
||||||
in("r2") 1,
|
// in("r2") 1,
|
||||||
in("r3") 2,
|
// in("r3") 2,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
result
|
// result
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[cfg(test)]
|
// #[cfg(test)]
|
||||||
mod tests {
|
// mod tests {
|
||||||
use super::*;
|
// use super::*;
|
||||||
|
|
||||||
#[test_case]
|
// #[test_case]
|
||||||
fn affine(_gba: &mut crate::Gba) {
|
// fn affine(_gba: &mut crate::Gba) {
|
||||||
// expect identity matrix
|
// // expect identity matrix
|
||||||
let one: Num<i16, 8> = 1.into();
|
// let one: Num<i16, 8> = 1.into();
|
||||||
|
|
||||||
let aff = affine_matrix(one, one, 0);
|
// let aff = affine_matrix(one, one, 0);
|
||||||
assert_eq!(aff.p_a, one.to_raw());
|
// assert_eq!(aff.p_a, one.to_raw());
|
||||||
assert_eq!(aff.p_d, one.to_raw());
|
// assert_eq!(aff.p_d, one.to_raw());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
170
book/games/pong/Cargo.lock
generated
170
book/games/pong/Cargo.lock
generated
|
@ -24,6 +24,9 @@ dependencies = [
|
||||||
"agb_sound_converter",
|
"agb_sound_converter",
|
||||||
"bare-metal",
|
"bare-metal",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"hashbrown",
|
||||||
|
"modular-bitfield",
|
||||||
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -37,6 +40,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 +68,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 +146,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 +194,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",
|
||||||
|
@ -146,14 +208,66 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[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"
|
||||||
|
@ -177,9 +291,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",
|
||||||
|
@ -196,15 +310,21 @@ 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 = "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]]
|
[[package]]
|
||||||
|
@ -232,6 +352,12 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.136"
|
version = "1.0.136"
|
||||||
|
@ -252,6 +378,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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"
|
||||||
|
@ -277,3 +409,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.
Binary file not shown.
Before Width: | Height: | Size: 438 B |
|
@ -1,6 +0,0 @@
|
||||||
version = "1.0"
|
|
||||||
|
|
||||||
[image.sprites]
|
|
||||||
filename = "sprites.png"
|
|
||||||
tile_size = "16x16"
|
|
||||||
transparent_colour = "ff0044"
|
|
|
@ -10,42 +10,27 @@
|
||||||
// which won't be a particularly clear error message.
|
// which won't be a particularly clear error message.
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use agb::display::object::Size;
|
use agb::display::object::{Graphics, Tag};
|
||||||
use agb::Gba;
|
use agb::Gba;
|
||||||
|
|
||||||
// Put all the graphics related code in the gfx module
|
const GRAPHICS: &Graphics = agb::include_aseprite!("gfx/sprites.aseprite");
|
||||||
mod gfx {
|
|
||||||
use agb::display::object::ObjectControl;
|
|
||||||
|
|
||||||
// Import the sprites into this module. This will create a `sprites` module
|
|
||||||
// and within that will be a constant called `sprites` which houses all the
|
|
||||||
// palette and tile data.
|
|
||||||
agb::include_gfx!("gfx/sprites.toml");
|
|
||||||
|
|
||||||
// Loads the sprites tile data and palette data into VRAM
|
|
||||||
pub fn load_sprite_data(object: &mut ObjectControl) {
|
|
||||||
object.set_sprite_palettes(sprites::sprites.palettes);
|
|
||||||
object.set_sprite_tilemap(sprites::sprites.tiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The main function must take 0 arguments and never return. The agb::entry decorator
|
// The main function must take 0 arguments and never return. The agb::entry decorator
|
||||||
// ensures that everything is in order. `agb` will call this after setting up the stack
|
// ensures that everything is in order. `agb` will call this after setting up the stack
|
||||||
// and interrupt handlers correctly.
|
// and interrupt handlers correctly.
|
||||||
#[agb::entry]
|
#[agb::entry]
|
||||||
fn main(mut gba: Gba) -> ! {
|
fn main(mut gba: Gba) -> ! {
|
||||||
let _tiled = gba.display.video.tiled0();
|
let object = gba.display.object.get();
|
||||||
let mut object = gba.display.object.get();
|
|
||||||
gfx::load_sprite_data(&mut object);
|
|
||||||
object.enable();
|
|
||||||
|
|
||||||
let mut ball = object.get_object_standard();
|
const BALL: &Tag = GRAPHICS.tags().get("Ball");
|
||||||
|
let ball_sprite = object
|
||||||
|
.get_sprite(BALL.get_sprite(0))
|
||||||
|
.expect("We should be able to load a sprite");
|
||||||
|
let mut ball = object
|
||||||
|
.get_object(ball_sprite)
|
||||||
|
.expect("We should have enoguh space to store an object");
|
||||||
|
|
||||||
ball.set_x(50)
|
ball.set_x(50).set_y(50).show();
|
||||||
.set_y(50)
|
|
||||||
.set_sprite_size(Size::S16x16)
|
|
||||||
.set_tile_id(4 * 2)
|
|
||||||
.show();
|
|
||||||
|
|
||||||
let mut ball_x = 50;
|
let mut ball_x = 50;
|
||||||
let mut ball_y = 50;
|
let mut ball_y = 50;
|
||||||
|
|
|
@ -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"
|
||||||
|
]
|
||||||
}
|
}
|
170
examples/the-hat-chooses-the-wizard/Cargo.lock
generated
170
examples/the-hat-chooses-the-wizard/Cargo.lock
generated
|
@ -24,6 +24,9 @@ dependencies = [
|
||||||
"agb_sound_converter",
|
"agb_sound_converter",
|
||||||
"bare-metal",
|
"bare-metal",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"hashbrown",
|
||||||
|
"modular-bitfield",
|
||||||
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -37,6 +40,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 +68,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 +146,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 +194,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 +214,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 +297,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,15 +316,21 @@ 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 = "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]]
|
[[package]]
|
||||||
|
@ -231,6 +351,12 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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 +394,12 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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 +434,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 |
|
@ -1,6 +0,0 @@
|
||||||
version = "1.0"
|
|
||||||
|
|
||||||
[image.object_sheet]
|
|
||||||
filename = "object_sheet.png"
|
|
||||||
tile_size = "8x8"
|
|
||||||
transparent_colour = "2ce8f4"
|
|
BIN
examples/the-hat-chooses-the-wizard/gfx/sprites.aseprite
Normal file
BIN
examples/the-hat-chooses-the-wizard/gfx/sprites.aseprite
Normal file
Binary file not shown.
|
@ -1,9 +1,20 @@
|
||||||
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, Tag},
|
||||||
fixnum::Vector2D,
|
fixnum::Vector2D,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SLIME_IDLE: &Tag = TAG_MAP.get("Slime Idle");
|
||||||
|
const SLIME_JUMP: &Tag = TAG_MAP.get("Slime Jump");
|
||||||
|
const SLIME_SPLAT: &Tag = TAG_MAP.get("Slime splat");
|
||||||
|
|
||||||
|
const SNAIL_EMERGE: &Tag = TAG_MAP.get("Snail Emerge");
|
||||||
|
const SNAIL_MOVE: &Tag = TAG_MAP.get("Snail Move");
|
||||||
|
const SNAIL_DEATH: &Tag = TAG_MAP.get("Snail Death");
|
||||||
|
const SNAIL_IDLE: &Tag = TAG_MAP.get("Snail Idle");
|
||||||
|
|
||||||
enum UpdateState {
|
enum UpdateState {
|
||||||
Nothing,
|
Nothing,
|
||||||
KillPlayer,
|
KillPlayer,
|
||||||
|
@ -28,11 +39,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 +56,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 +64,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 +98,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 +139,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 +162,12 @@ 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 frame = SLIME_IDLE.get_animation_sprite(offset);
|
||||||
.sprite
|
let sprite = controller.get_sprite(frame).unwrap();
|
||||||
.set_tile_id(object_tiles::SLIME_IDLE_START + offset as u16);
|
|
||||||
|
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 +194,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 +204,10 @@ 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 frame = SLIME_JUMP.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 +223,17 @@ 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 frame = SLIME_SPLAT.get_animation_sprite(offset);
|
||||||
.entity
|
let sprite = controller.get_sprite(frame).unwrap();
|
||||||
.sprite
|
|
||||||
.set_tile_id(object_tiles::SLIME_SPLAT_START + (offset * 4) as u16);
|
self.enemy_info.entity.sprite.set_sprite(sprite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,14 +261,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 +276,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 +301,10 @@ impl<'a> Snail<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enemy_info
|
let frame = SNAIL_IDLE.get_animation_sprite(0);
|
||||||
.entity
|
let sprite = controller.get_sprite(frame).unwrap();
|
||||||
.sprite
|
|
||||||
.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 +314,17 @@ 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 frame = SNAIL_EMERGE.get_animation_sprite(offset);
|
||||||
.entity
|
let sprite = controller.get_sprite(frame).unwrap();
|
||||||
.sprite
|
|
||||||
.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 +341,12 @@ 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 frame = SNAIL_MOVE.get_animation_sprite(offset);
|
||||||
.entity
|
let sprite = controller.get_sprite(frame).unwrap();
|
||||||
.sprite
|
|
||||||
.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 +371,16 @@ 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 frame = SNAIL_EMERGE.get_animation_sprite(offset);
|
||||||
.entity
|
let sprite = controller.get_sprite(frame).unwrap();
|
||||||
.sprite
|
|
||||||
.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 +396,20 @@ 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
|
SNAIL_EMERGE.get_animation_sprite(5 - offset)
|
||||||
} else if offset == 5 {
|
} else if offset == 5 {
|
||||||
object_tiles::SNAIL_IDLE_START
|
SNAIL_IDLE.get_animation_sprite(0)
|
||||||
} else if offset < 5 + 7 {
|
} else if offset < 5 + 7 {
|
||||||
object_tiles::SNAIL_DEATH_START + ((offset - 5) * 4) as u16
|
SNAIL_DEATH.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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,37 @@ agb::include_gfx!("gfx/tile_sheet.toml");
|
||||||
use agb::{
|
use agb::{
|
||||||
display::{
|
display::{
|
||||||
background::BackgroundRegular,
|
background::BackgroundRegular,
|
||||||
object::{ObjectControl, ObjectStandard, Size},
|
object::{Graphics, Object, ObjectController, Sprite, Tag, TagMap},
|
||||||
Priority, HEIGHT, WIDTH,
|
Priority, HEIGHT, WIDTH,
|
||||||
},
|
},
|
||||||
fixnum::{FixedNum, Vector2D},
|
fixnum::{FixedNum, Vector2D},
|
||||||
input::{self, Button, ButtonController},
|
input::{self, Button, ButtonController},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const GRAPHICS: &Graphics = agb::include_aseprite!("gfx/sprites.aseprite");
|
||||||
|
const TAG_MAP: &TagMap = GRAPHICS.tags();
|
||||||
|
|
||||||
|
const WALKING: &Tag = TAG_MAP.get("Walking");
|
||||||
|
const JUMPING: &Tag = TAG_MAP.get("Jumping");
|
||||||
|
const FALLING: &Tag = TAG_MAP.get("Falling");
|
||||||
|
const PLAYER_DEATH: &Tag = TAG_MAP.get("Player Death");
|
||||||
|
const HAT_SPIN_1: &Tag = TAG_MAP.get("HatSpin");
|
||||||
|
const HAT_SPIN_2: &Tag = TAG_MAP.get("HatSpin2");
|
||||||
|
const HAT_SPIN_3: &Tag = TAG_MAP.get("HatSpin3");
|
||||||
|
|
||||||
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(WALKING.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 +351,16 @@ 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(HAT_SPIN_1.get_sprite(0)).unwrap());
|
||||||
|
hat.sprite
|
||||||
|
.set_sprite(controller.get_sprite(HAT_SPIN_1.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,27 @@ 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 frame = WALKING.get_animation_sprite(offset);
|
||||||
.sprite
|
let sprite = controller.get_sprite(frame).unwrap();
|
||||||
.set_tile_id(object_tiles::WIZARD_TILE_START + offset * 4);
|
|
||||||
|
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 frame = JUMPING.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 +489,10 @@ impl<'a> Player<'a> {
|
||||||
|
|
||||||
self.wizard_frame = 0;
|
self.wizard_frame = 0;
|
||||||
|
|
||||||
self.wizard
|
let frame = FALLING.get_animation_sprite(offset);
|
||||||
.sprite
|
let sprite = controller.get_sprite(frame).unwrap();
|
||||||
.set_tile_id(object_tiles::WIZARD_FALL_START + offset * 4);
|
|
||||||
|
self.wizard.sprite.set_sprite(sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.x_tri() != agb::input::Tri::Zero {
|
if input.x_tri() != agb::input::Tri::Zero {
|
||||||
|
@ -502,19 +501,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 => HAT_SPIN_1,
|
||||||
1 => object_tiles::HAT_TILE_START_SECOND,
|
1 => HAT_SPIN_2,
|
||||||
_ => object_tiles::HAT_TILE_START_THIRD,
|
_ => HAT_SPIN_3,
|
||||||
};
|
};
|
||||||
|
|
||||||
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 +546,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 +583,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 +624,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 +683,26 @@ 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 frame = PLAYER_DEATH.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 +710,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 +719,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 +797,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 +804,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 +866,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();
|
||||||
|
|
170
examples/the-purple-night/Cargo.lock
generated
170
examples/the-purple-night/Cargo.lock
generated
|
@ -24,6 +24,9 @@ dependencies = [
|
||||||
"agb_sound_converter",
|
"agb_sound_converter",
|
||||||
"bare-metal",
|
"bare-metal",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"hashbrown",
|
||||||
|
"modular-bitfield",
|
||||||
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -37,6 +40,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 +68,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"
|
||||||
|
@ -132,11 +161,24 @@ 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 1.0.0",
|
||||||
|
"crc32fast",
|
||||||
|
"libc",
|
||||||
|
"miniz_oxide 0.4.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -148,6 +190,26 @@ dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"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]]
|
||||||
name = "hound"
|
name = "hound"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
|
@ -156,9 +218,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",
|
||||||
|
@ -169,6 +231,12 @@ dependencies = [
|
||||||
"png",
|
"png",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.119"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libflate"
|
name = "libflate"
|
||||||
version = "0.1.27"
|
version = "0.1.27"
|
||||||
|
@ -182,14 +250,60 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "log"
|
||||||
version = "0.5.1"
|
version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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"
|
||||||
|
@ -213,9 +327,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",
|
||||||
|
@ -232,15 +346,21 @@ 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 = "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]]
|
[[package]]
|
||||||
|
@ -267,6 +387,12 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
|
checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.136"
|
version = "1.0.136"
|
||||||
|
@ -287,6 +413,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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"
|
||||||
|
@ -340,6 +472,18 @@ 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"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xml-rs"
|
name = "xml-rs"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
|
|
Binary file not shown.
|
@ -15,7 +15,7 @@ use rng::get_random;
|
||||||
use agb::{
|
use agb::{
|
||||||
display::{
|
display::{
|
||||||
background::{BackgroundDistributor, BackgroundRegular},
|
background::{BackgroundDistributor, BackgroundRegular},
|
||||||
object::{ObjectControl, ObjectStandard},
|
object::{Graphics, Object, ObjectController, Sprite, Tag, TagMap},
|
||||||
Priority, HEIGHT, WIDTH,
|
Priority, HEIGHT, WIDTH,
|
||||||
},
|
},
|
||||||
fixnum::{FixedNum, Rect, Vector2D},
|
fixnum::{FixedNum, Rect, Vector2D},
|
||||||
|
@ -23,7 +23,33 @@ use agb::{
|
||||||
};
|
};
|
||||||
use generational_arena::Arena;
|
use generational_arena::Arena;
|
||||||
|
|
||||||
agb::include_gfx!("gfx/objects.toml");
|
const GRAPHICS: &Graphics = agb::include_aseprite!("gfx/objects.aseprite", "gfx/boss.aseprite");
|
||||||
|
const TAG_MAP: &TagMap = GRAPHICS.tags();
|
||||||
|
|
||||||
|
const LONGSWORD_IDLE: &Tag = TAG_MAP.get("Idle - longsword");
|
||||||
|
const LONGSWORD_WALK: &Tag = TAG_MAP.get("Walk - longsword");
|
||||||
|
const LONGSWORD_JUMP: &Tag = TAG_MAP.get("Jump - longsword");
|
||||||
|
const LONGSWORD_ATTACK: &Tag = TAG_MAP.get("Attack - longsword");
|
||||||
|
const LONGSWORD_JUMP_ATTACK: &Tag = TAG_MAP.get("Jump attack - longsword");
|
||||||
|
|
||||||
|
const SHORTSWORD_IDLE: &Tag = TAG_MAP.get("Idle - shortsword");
|
||||||
|
const SHORTSWORD_WALK: &Tag = TAG_MAP.get("Walk - shortsword");
|
||||||
|
const SHORTSWORD_JUMP: &Tag = TAG_MAP.get("jump - shortsword");
|
||||||
|
const SHORTSWORD_ATTACK: &Tag = TAG_MAP.get("attack - shortsword");
|
||||||
|
const SHORTSWORD_JUMP_ATTACK: &Tag = TAG_MAP.get("jump attack - shortsword");
|
||||||
|
|
||||||
|
const KNIFE_IDLE: &Tag = TAG_MAP.get("idle - knife");
|
||||||
|
const KNIFE_WALK: &Tag = TAG_MAP.get("walk - knife");
|
||||||
|
const KNIFE_JUMP: &Tag = TAG_MAP.get("jump - knife");
|
||||||
|
const KNIFE_ATTACK: &Tag = TAG_MAP.get("attack - knife");
|
||||||
|
const KNIFE_JUMP_ATTACK: &Tag = TAG_MAP.get("jump attack - knife");
|
||||||
|
|
||||||
|
const SWORDLESS_IDLE: &Tag = TAG_MAP.get("idle swordless");
|
||||||
|
const SWORDLESS_WALK: &Tag = TAG_MAP.get("walk swordless");
|
||||||
|
const SWORDLESS_JUMP: &Tag = TAG_MAP.get("jump swordless");
|
||||||
|
const SWORDLESS_ATTACK: &Tag = KNIFE_ATTACK;
|
||||||
|
const SWORDLESS_JUMP_ATTACK: &Tag = KNIFE_JUMP_ATTACK;
|
||||||
|
|
||||||
agb::include_gfx!("gfx/background.toml");
|
agb::include_gfx!("gfx/background.toml");
|
||||||
|
|
||||||
type Number = FixedNum<8>;
|
type Number = FixedNum<8>;
|
||||||
|
@ -127,7 +153,7 @@ impl Level {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Entity<'a> {
|
struct Entity<'a> {
|
||||||
sprite: ObjectStandard<'a>,
|
sprite: Object<'a, 'a>,
|
||||||
position: Vector2D<Number>,
|
position: Vector2D<Number>,
|
||||||
velocity: Vector2D<Number>,
|
velocity: Vector2D<Number>,
|
||||||
collision_mask: Rect<u16>,
|
collision_mask: Rect<u16>,
|
||||||
|
@ -135,8 +161,11 @@ struct Entity<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Entity<'a> {
|
impl<'a> Entity<'a> {
|
||||||
fn new(object_controller: &'a ObjectControl, collision_mask: Rect<u16>) -> Self {
|
fn new(object_controller: &'a ObjectController, collision_mask: Rect<u16>) -> Self {
|
||||||
let mut sprite = object_controller.get_object_standard();
|
let s = object_controller
|
||||||
|
.get_sprite(LONGSWORD_IDLE.get_sprite(0))
|
||||||
|
.unwrap();
|
||||||
|
let mut sprite = object_controller.get_object(s).unwrap();
|
||||||
sprite.set_priority(Priority::P1);
|
sprite.set_priority(Priority::P1);
|
||||||
Entity {
|
Entity {
|
||||||
sprite,
|
sprite,
|
||||||
|
@ -321,34 +350,30 @@ impl SwordState {
|
||||||
SwordState::Swordless => Number::new(6) / 256,
|
SwordState::Swordless => Number::new(6) / 256,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn idle_animation(self, counter: &mut u16) -> u16 {
|
fn idle_animation(self, counter: u16) -> &'static Sprite {
|
||||||
if *counter >= 4 * 8 {
|
let counter = counter as usize;
|
||||||
*counter = 0;
|
|
||||||
}
|
|
||||||
match self {
|
match self {
|
||||||
SwordState::LongSword => (*counter / 8) * 4,
|
SwordState::LongSword => LONGSWORD_IDLE.get_animation_sprite(counter / 8),
|
||||||
SwordState::ShortSword => (41 + *counter / 8) * 4,
|
SwordState::ShortSword => SHORTSWORD_IDLE.get_animation_sprite(counter / 8),
|
||||||
SwordState::Dagger => (96 + *counter / 8) * 4,
|
SwordState::Dagger => KNIFE_IDLE.get_animation_sprite(counter / 8),
|
||||||
SwordState::Swordless => (154 + *counter / 8) * 4,
|
SwordState::Swordless => SWORDLESS_IDLE.get_animation_sprite(counter / 8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn jump_offset(self) -> u16 {
|
fn jump_tag(self) -> &'static Tag {
|
||||||
match self {
|
match self {
|
||||||
SwordState::LongSword => 10,
|
SwordState::LongSword => LONGSWORD_JUMP,
|
||||||
SwordState::ShortSword => 51,
|
SwordState::ShortSword => SHORTSWORD_JUMP,
|
||||||
SwordState::Dagger => 106,
|
SwordState::Dagger => KNIFE_JUMP,
|
||||||
SwordState::Swordless => 164,
|
SwordState::Swordless => SWORDLESS_JUMP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn walk_animation(self, counter: &mut u16) -> u16 {
|
fn walk_animation(self, counter: u16) -> &'static Sprite {
|
||||||
if *counter >= 6 * 4 {
|
let counter = counter as usize;
|
||||||
*counter = 0;
|
|
||||||
}
|
|
||||||
match self {
|
match self {
|
||||||
SwordState::LongSword => (4 + *counter / 4) * 4,
|
SwordState::LongSword => LONGSWORD_WALK.get_animation_sprite(counter / 4),
|
||||||
SwordState::ShortSword => (45 + *counter / 4) * 4,
|
SwordState::ShortSword => SHORTSWORD_WALK.get_animation_sprite(counter / 4),
|
||||||
SwordState::Dagger => (100 + *counter / 4) * 4,
|
SwordState::Dagger => KNIFE_WALK.get_animation_sprite(counter / 4),
|
||||||
SwordState::Swordless => (158 + *counter / 4) * 4,
|
SwordState::Swordless => SWORDLESS_WALK.get_animation_sprite(counter / 4),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn attack_duration(self) -> u16 {
|
fn attack_duration(self) -> u16 {
|
||||||
|
@ -375,20 +400,20 @@ impl SwordState {
|
||||||
SwordState::Swordless => (self.attack_duration() - timer) / 8,
|
SwordState::Swordless => (self.attack_duration() - timer) / 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn jump_attack_tag(self) -> &'static Tag {
|
||||||
|
match self {
|
||||||
|
SwordState::LongSword => LONGSWORD_JUMP_ATTACK,
|
||||||
|
SwordState::ShortSword => SHORTSWORD_JUMP_ATTACK,
|
||||||
|
SwordState::Dagger => KNIFE_JUMP_ATTACK,
|
||||||
|
SwordState::Swordless => SWORDLESS_JUMP_ATTACK,
|
||||||
|
}
|
||||||
|
}
|
||||||
fn jump_attack_frame(self, timer: u16) -> u16 {
|
fn jump_attack_frame(self, timer: u16) -> u16 {
|
||||||
(self.jump_attack_duration() - timer) / 8
|
(self.jump_attack_duration() - timer) / 8
|
||||||
}
|
}
|
||||||
fn hold_frame(self) -> u16 {
|
fn hold_frame(self) -> u16 {
|
||||||
7
|
7
|
||||||
}
|
}
|
||||||
fn jump_attack_hold_frame(self) -> u16 {
|
|
||||||
match self {
|
|
||||||
SwordState::LongSword => 13,
|
|
||||||
SwordState::ShortSword => 54,
|
|
||||||
SwordState::Dagger => 109,
|
|
||||||
SwordState::Swordless => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cooldown_time(self) -> u16 {
|
fn cooldown_time(self) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
|
@ -398,26 +423,15 @@ impl SwordState {
|
||||||
SwordState::Swordless => 0,
|
SwordState::Swordless => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn to_sprite_id(self, frame: u16) -> u16 {
|
fn attack_tag(self) -> &'static Tag {
|
||||||
match self {
|
match self {
|
||||||
SwordState::LongSword => (16 + frame) * 4,
|
SwordState::LongSword => LONGSWORD_ATTACK,
|
||||||
SwordState::ShortSword => (57 + frame) * 4,
|
SwordState::ShortSword => SHORTSWORD_ATTACK,
|
||||||
SwordState::Dagger => (112 + frame) * 4,
|
SwordState::Dagger => KNIFE_ATTACK,
|
||||||
SwordState::Swordless => 0,
|
SwordState::Swordless => SWORDLESS_ATTACK,
|
||||||
}
|
|
||||||
}
|
|
||||||
fn to_jump_sprite_id(self, frame: u16) -> u16 {
|
|
||||||
if frame == self.jump_attack_hold_frame() {
|
|
||||||
frame * 4
|
|
||||||
} else {
|
|
||||||
match self {
|
|
||||||
SwordState::LongSword => (24 + frame) * 4,
|
|
||||||
SwordState::ShortSword => (65 + frame) * 4,
|
|
||||||
SwordState::Dagger => (120 + frame) * 4,
|
|
||||||
SwordState::Swordless => 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fudge(self, frame: u16) -> i32 {
|
fn fudge(self, frame: u16) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
SwordState::LongSword => long_sword_fudge(frame),
|
SwordState::LongSword => long_sword_fudge(frame),
|
||||||
|
@ -520,15 +534,15 @@ struct Player<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Player<'a> {
|
impl<'a> Player<'a> {
|
||||||
fn new(object_controller: &'a ObjectControl) -> Player {
|
fn new(object_controller: &'a ObjectController) -> Player {
|
||||||
let mut entity = Entity::new(
|
let mut entity = Entity::new(
|
||||||
object_controller,
|
object_controller,
|
||||||
Rect::new((0_u16, 0_u16).into(), (4_u16, 12_u16).into()),
|
Rect::new((0_u16, 0_u16).into(), (4_u16, 12_u16).into()),
|
||||||
);
|
);
|
||||||
entity
|
let s = object_controller
|
||||||
.sprite
|
.get_sprite(LONGSWORD_IDLE.get_sprite(0))
|
||||||
.set_sprite_size(agb::display::object::Size::S16x16);
|
.unwrap();
|
||||||
entity.sprite.set_tile_id(0);
|
entity.sprite.set_sprite(s);
|
||||||
entity.sprite.show();
|
entity.sprite.show();
|
||||||
entity.position = (144, 0).into();
|
entity.position = (144, 0).into();
|
||||||
entity.sprite.commit();
|
entity.sprite.commit();
|
||||||
|
@ -549,6 +563,7 @@ impl<'a> Player<'a> {
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
controller: &'a ObjectController,
|
||||||
buttons: &ButtonController,
|
buttons: &ButtonController,
|
||||||
level: &Level,
|
level: &Level,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
|
@ -580,13 +595,15 @@ impl<'a> Player<'a> {
|
||||||
self.entity.sprite.set_hflip(self.facing == Tri::Negative);
|
self.entity.sprite.set_hflip(self.facing == Tri::Negative);
|
||||||
self.entity.velocity.x += self.sword.ground_walk_force() * x as i32;
|
self.entity.velocity.x += self.sword.ground_walk_force() * x as i32;
|
||||||
if self.entity.velocity.x.abs() > Number::new(1) / 10 {
|
if self.entity.velocity.x.abs() > Number::new(1) / 10 {
|
||||||
self.entity
|
let sprite = controller
|
||||||
.sprite
|
.get_sprite(self.sword.walk_animation(self.sprite_offset))
|
||||||
.set_tile_id(self.sword.walk_animation(&mut self.sprite_offset));
|
.unwrap();
|
||||||
|
self.entity.sprite.set_sprite(sprite);
|
||||||
} else {
|
} else {
|
||||||
self.entity
|
let sprite = controller
|
||||||
.sprite
|
.get_sprite(self.sword.idle_animation(self.sprite_offset))
|
||||||
.set_tile_id(self.sword.idle_animation(&mut self.sprite_offset));
|
.unwrap();
|
||||||
|
self.entity.sprite.set_sprite(sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
if b_press && self.sword != SwordState::Swordless {
|
if b_press && self.sword != SwordState::Swordless {
|
||||||
|
@ -604,9 +621,11 @@ impl<'a> Player<'a> {
|
||||||
*a -= 1;
|
*a -= 1;
|
||||||
let frame = self.sword.attack_frame(*a);
|
let frame = self.sword.attack_frame(*a);
|
||||||
self.fudge_factor.x = self.sword.fudge(frame) * self.facing as i32;
|
self.fudge_factor.x = self.sword.fudge(frame) * self.facing as i32;
|
||||||
self.entity
|
let tag = self.sword.attack_tag();
|
||||||
.sprite
|
let sprite = controller
|
||||||
.set_tile_id(self.sword.to_sprite_id(frame));
|
.get_sprite(tag.get_animation_sprite(frame as usize))
|
||||||
|
.unwrap();
|
||||||
|
self.entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
hurtbox = self.sword.ground_attack_hurtbox(frame);
|
hurtbox = self.sword.ground_attack_hurtbox(frame);
|
||||||
|
|
||||||
|
@ -618,9 +637,11 @@ impl<'a> Player<'a> {
|
||||||
*a -= 1;
|
*a -= 1;
|
||||||
let frame = self.sword.hold_frame();
|
let frame = self.sword.hold_frame();
|
||||||
self.fudge_factor.x = self.sword.fudge(frame) * self.facing as i32;
|
self.fudge_factor.x = self.sword.fudge(frame) * self.facing as i32;
|
||||||
self.entity
|
let tag = self.sword.attack_tag();
|
||||||
.sprite
|
let sprite = controller
|
||||||
.set_tile_id(self.sword.to_sprite_id(frame));
|
.get_sprite(tag.get_animation_sprite(frame as usize))
|
||||||
|
.unwrap();
|
||||||
|
self.entity.sprite.set_sprite(sprite);
|
||||||
if *a == 0 {
|
if *a == 0 {
|
||||||
self.attack_timer = AttackTimer::Idle;
|
self.attack_timer = AttackTimer::Idle;
|
||||||
}
|
}
|
||||||
|
@ -632,7 +653,7 @@ impl<'a> Player<'a> {
|
||||||
|
|
||||||
match &mut self.attack_timer {
|
match &mut self.attack_timer {
|
||||||
AttackTimer::Idle => {
|
AttackTimer::Idle => {
|
||||||
let sprite = if self.sprite_offset < 3 * 4 {
|
let frame = if self.sprite_offset < 3 * 4 {
|
||||||
self.sprite_offset / 4
|
self.sprite_offset / 4
|
||||||
} else if self.entity.velocity.y.abs() < Number::new(1) / 5 {
|
} else if self.entity.velocity.y.abs() < Number::new(1) / 5 {
|
||||||
3
|
3
|
||||||
|
@ -643,9 +664,11 @@ impl<'a> Player<'a> {
|
||||||
} else {
|
} else {
|
||||||
2
|
2
|
||||||
};
|
};
|
||||||
self.entity
|
let tag = self.sword.jump_tag();
|
||||||
.sprite
|
let sprite = controller
|
||||||
.set_tile_id((sprite + self.sword.jump_offset()) * 4);
|
.get_sprite(tag.get_animation_sprite(frame as usize))
|
||||||
|
.unwrap();
|
||||||
|
self.entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
if x != Tri::Zero {
|
if x != Tri::Zero {
|
||||||
self.facing = x;
|
self.facing = x;
|
||||||
|
@ -665,9 +688,11 @@ impl<'a> Player<'a> {
|
||||||
AttackTimer::Attack(a) => {
|
AttackTimer::Attack(a) => {
|
||||||
*a -= 1;
|
*a -= 1;
|
||||||
let frame = self.sword.jump_attack_frame(*a);
|
let frame = self.sword.jump_attack_frame(*a);
|
||||||
self.entity
|
let tag = self.sword.jump_attack_tag();
|
||||||
.sprite
|
let sprite = controller
|
||||||
.set_tile_id(self.sword.to_jump_sprite_id(frame));
|
.get_sprite(tag.get_animation_sprite(frame as usize))
|
||||||
|
.unwrap();
|
||||||
|
self.entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
hurtbox = self.sword.air_attack_hurtbox(frame);
|
hurtbox = self.sword.air_attack_hurtbox(frame);
|
||||||
|
|
||||||
|
@ -799,9 +824,10 @@ impl BatData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entity: &mut Entity,
|
controller: &'a ObjectController,
|
||||||
|
entity: &mut Entity<'a>,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
level: &Level,
|
level: &Level,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
|
@ -814,6 +840,8 @@ impl BatData {
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
let should_damage = entity.collider().touches(player.entity.collider());
|
let should_damage = entity.collider().touches(player.entity.collider());
|
||||||
|
|
||||||
|
const BAT_IDLE: &Tag = TAG_MAP.get("bat");
|
||||||
|
|
||||||
match &mut self.bat_state {
|
match &mut self.bat_state {
|
||||||
BatState::Idle => {
|
BatState::Idle => {
|
||||||
self.sprite_offset += 1;
|
self.sprite_offset += 1;
|
||||||
|
@ -825,7 +853,10 @@ impl BatData {
|
||||||
sfx.bat_flap();
|
sfx.bat_flap();
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.sprite.set_tile_id((78 + self.sprite_offset / 8) * 4);
|
let sprite = BAT_IDLE.get_sprite(self.sprite_offset as usize / 8);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
if (entity.position - player.entity.position).manhattan_distance() < 50.into() {
|
if (entity.position - player.entity.position).manhattan_distance() < 50.into() {
|
||||||
self.bat_state = BatState::Chasing(300);
|
self.bat_state = BatState::Chasing(300);
|
||||||
|
@ -856,7 +887,11 @@ impl BatData {
|
||||||
if self.sprite_offset >= 9 * 2 {
|
if self.sprite_offset >= 9 * 2 {
|
||||||
self.sprite_offset = 0;
|
self.sprite_offset = 0;
|
||||||
}
|
}
|
||||||
entity.sprite.set_tile_id((78 + self.sprite_offset / 2) * 4);
|
|
||||||
|
let sprite = BAT_IDLE.get_sprite(self.sprite_offset as usize / 2);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
if self.sprite_offset == 2 * 5 {
|
if self.sprite_offset == 2 * 5 {
|
||||||
sfx.bat_flap();
|
sfx.bat_flap();
|
||||||
|
@ -879,7 +914,12 @@ impl BatData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BatState::Dead => {
|
BatState::Dead => {
|
||||||
entity.sprite.set_tile_id(87 * 4);
|
const BAT_DEAD: &Tag = TAG_MAP.get("bat dead");
|
||||||
|
let sprite = BAT_DEAD.get_sprite(0);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
let gravity: Number = 1.into();
|
let gravity: Number = 1.into();
|
||||||
let gravity = gravity / 16;
|
let gravity = gravity / 16;
|
||||||
entity.velocity.x = 0.into();
|
entity.velocity.x = 0.into();
|
||||||
|
@ -917,9 +957,10 @@ impl SlimeData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entity: &mut Entity,
|
controller: &'a ObjectController,
|
||||||
|
entity: &mut Entity<'a>,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
level: &Level,
|
level: &Level,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
|
@ -940,9 +981,12 @@ impl SlimeData {
|
||||||
self.sprite_offset = 0;
|
self.sprite_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity
|
const IDLE: &Tag = TAG_MAP.get("slime idle");
|
||||||
.sprite
|
|
||||||
.set_tile_id((29 + self.sprite_offset / 16) * 4);
|
let sprite = IDLE.get_sprite(self.sprite_offset as usize / 16);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
if (player.entity.position - entity.position).manhattan_distance() < 40.into() {
|
if (player.entity.position - entity.position).manhattan_distance() < 40.into() {
|
||||||
let direction = match player.entity.position.x.cmp(&entity.position.x) {
|
let direction = match player.entity.position.x.cmp(&entity.position.x) {
|
||||||
|
@ -977,7 +1021,12 @@ impl SlimeData {
|
||||||
sfx.slime_boing();
|
sfx.slime_boing();
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.sprite.set_tile_id((frame + 31) * 4);
|
const CHASE: &Tag = TAG_MAP.get("Slime jump");
|
||||||
|
|
||||||
|
let sprite = CHASE.get_sprite(frame as usize);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
entity.velocity.x = match frame {
|
entity.velocity.x = match frame {
|
||||||
2 | 3 | 4 => (Number::new(1) / 5) * Number::new(*direction as i32),
|
2 | 3 | 4 => (Number::new(1) / 5) * Number::new(*direction as i32),
|
||||||
|
@ -1003,7 +1052,11 @@ impl SlimeData {
|
||||||
}
|
}
|
||||||
SlimeState::Dead(count) => {
|
SlimeState::Dead(count) => {
|
||||||
if *count < 5 * 4 {
|
if *count < 5 * 4 {
|
||||||
entity.sprite.set_tile_id((36 + *count / 4) * 4);
|
const DEATH: &Tag = TAG_MAP.get("Slime death");
|
||||||
|
let sprite = DEATH.get_sprite(*count as usize / 4);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
*count += 1;
|
*count += 1;
|
||||||
} else {
|
} else {
|
||||||
return UpdateInstruction::Remove;
|
return UpdateInstruction::Remove;
|
||||||
|
@ -1033,9 +1086,10 @@ impl MiniFlameData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entity: &mut Entity,
|
controller: &'a ObjectController,
|
||||||
|
entity: &mut Entity<'a>,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
_level: &Level,
|
_level: &Level,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
|
@ -1051,6 +1105,8 @@ impl MiniFlameData {
|
||||||
|
|
||||||
self.sprite_offset += 1;
|
self.sprite_offset += 1;
|
||||||
|
|
||||||
|
const ANGRY: &Tag = TAG_MAP.get("angry boss");
|
||||||
|
|
||||||
match &mut self.state {
|
match &mut self.state {
|
||||||
MiniFlameState::Idle(frames) => {
|
MiniFlameState::Idle(frames) => {
|
||||||
*frames -= 1;
|
*frames -= 1;
|
||||||
|
@ -1065,13 +1121,9 @@ impl MiniFlameData {
|
||||||
entity.velocity = resulting_direction.normalise() * Number::new(2);
|
entity.velocity = resulting_direction.normalise() * Number::new(2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.sprite_offset >= 12 * 8 {
|
let sprite = ANGRY.get_animation_sprite(self.sprite_offset as usize / 8);
|
||||||
self.sprite_offset = 0;
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
}
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
entity
|
|
||||||
.sprite
|
|
||||||
.set_tile_id((137 + self.sprite_offset / 8) * 4);
|
|
||||||
|
|
||||||
entity.velocity = (0.into(), Number::new(-1) / Number::new(4)).into();
|
entity.velocity = (0.into(), Number::new(-1) / Number::new(4)).into();
|
||||||
}
|
}
|
||||||
|
@ -1113,17 +1165,13 @@ impl MiniFlameData {
|
||||||
instruction = UpdateInstruction::DamagePlayer;
|
instruction = UpdateInstruction::DamagePlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.sprite_offset >= 12 * 2 {
|
|
||||||
self.sprite_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if entity.velocity.manhattan_distance() < Number::new(1) / Number::new(4) {
|
if entity.velocity.manhattan_distance() < Number::new(1) / Number::new(4) {
|
||||||
self.state = MiniFlameState::Idle(90);
|
self.state = MiniFlameState::Idle(90);
|
||||||
}
|
}
|
||||||
|
|
||||||
entity
|
let sprite = ANGRY.get_animation_sprite(self.sprite_offset as usize / 2);
|
||||||
.sprite
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
.set_tile_id((137 + self.sprite_offset / 2) * 4);
|
entity.sprite.set_sprite(sprite);
|
||||||
}
|
}
|
||||||
MiniFlameState::Dead => {
|
MiniFlameState::Dead => {
|
||||||
entity.velocity = (0, 0).into();
|
entity.velocity = (0, 0).into();
|
||||||
|
@ -1131,9 +1179,11 @@ impl MiniFlameData {
|
||||||
instruction = UpdateInstruction::Remove;
|
instruction = UpdateInstruction::Remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity
|
const DEATH: &Tag = TAG_MAP.get("angry boss dead");
|
||||||
.sprite
|
|
||||||
.set_tile_id((148 + self.sprite_offset / 12) * 4);
|
let sprite = DEATH.get_animation_sprite(self.sprite_offset as usize / 12);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
self.sprite_offset += 1;
|
self.sprite_offset += 1;
|
||||||
}
|
}
|
||||||
|
@ -1165,9 +1215,10 @@ impl EmuData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entity: &mut Entity,
|
controller: &'a ObjectController,
|
||||||
|
entity: &mut Entity<'a>,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
level: &Level,
|
level: &Level,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
|
@ -1189,9 +1240,11 @@ impl EmuData {
|
||||||
self.sprite_offset = 0;
|
self.sprite_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity
|
const IDLE: &Tag = TAG_MAP.get("emu - idle");
|
||||||
.sprite
|
|
||||||
.set_tile_id((170 + self.sprite_offset / 16) * 4);
|
let sprite = IDLE.get_sprite(self.sprite_offset as usize / 16);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
if (entity.position.y - player.entity.position.y).abs() < 10.into() {
|
if (entity.position.y - player.entity.position.y).abs() < 10.into() {
|
||||||
let velocity = Number::new(1)
|
let velocity = Number::new(1)
|
||||||
|
@ -1234,9 +1287,11 @@ impl EmuData {
|
||||||
sfx.emu_step();
|
sfx.emu_step();
|
||||||
}
|
}
|
||||||
|
|
||||||
entity
|
const WALK: &Tag = TAG_MAP.get("emu-walk");
|
||||||
.sprite
|
|
||||||
.set_tile_id((173 + self.sprite_offset / 2) * 4);
|
let sprite = WALK.get_sprite(self.sprite_offset as usize / 2);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
let gravity: Number = 1.into();
|
let gravity: Number = 1.into();
|
||||||
let gravity = gravity / 16;
|
let gravity = gravity / 16;
|
||||||
|
@ -1287,9 +1342,12 @@ impl EmuData {
|
||||||
instruction = UpdateInstruction::Remove;
|
instruction = UpdateInstruction::Remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity
|
const DEATH: &Tag = TAG_MAP.get("emu - die");
|
||||||
.sprite
|
|
||||||
.set_tile_id((177 + self.sprite_offset / 4) * 4);
|
let sprite = DEATH.get_animation_sprite(self.sprite_offset as usize / 4);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
self.sprite_offset += 1;
|
self.sprite_offset += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1317,27 +1375,32 @@ impl EnemyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tile_id(&self) -> u16 {
|
fn sprite(&self) -> &'static Sprite {
|
||||||
|
const SLIME: &Tag = TAG_MAP.get("slime idle");
|
||||||
|
const BAT: &Tag = TAG_MAP.get("bat");
|
||||||
|
const MINI_FLAME: &Tag = TAG_MAP.get("angry boss");
|
||||||
|
const EMU: &Tag = TAG_MAP.get("emu - idle");
|
||||||
match self {
|
match self {
|
||||||
EnemyData::Slime(_) => 29,
|
EnemyData::Slime(_) => SLIME.get_sprite(0),
|
||||||
EnemyData::Bat(_) => 78,
|
EnemyData::Bat(_) => BAT.get_sprite(0),
|
||||||
EnemyData::MiniFlame(_) => 137,
|
EnemyData::MiniFlame(_) => MINI_FLAME.get_sprite(0),
|
||||||
EnemyData::Emu(_) => 170,
|
EnemyData::Emu(_) => EMU.get_sprite(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entity: &mut Entity,
|
controller: &'a ObjectController,
|
||||||
|
entity: &mut Entity<'a>,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
level: &Level,
|
level: &Level,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
) -> UpdateInstruction {
|
) -> UpdateInstruction {
|
||||||
match self {
|
match self {
|
||||||
EnemyData::Slime(data) => data.update(entity, player, level, sfx),
|
EnemyData::Slime(data) => data.update(controller, entity, player, level, sfx),
|
||||||
EnemyData::Bat(data) => data.update(entity, player, level, sfx),
|
EnemyData::Bat(data) => data.update(controller, entity, player, level, sfx),
|
||||||
EnemyData::MiniFlame(data) => data.update(entity, player, level, sfx),
|
EnemyData::MiniFlame(data) => data.update(controller, entity, player, level, sfx),
|
||||||
EnemyData::Emu(data) => data.update(entity, player, level, sfx),
|
EnemyData::Emu(data) => data.update(controller, entity, player, level, sfx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1348,13 +1411,13 @@ struct Enemy<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Enemy<'a> {
|
impl<'a> Enemy<'a> {
|
||||||
fn new(object_controller: &'a ObjectControl, enemy_data: EnemyData) -> Self {
|
fn new(object_controller: &'a ObjectController, enemy_data: EnemyData) -> Self {
|
||||||
let mut entity = Entity::new(object_controller, enemy_data.collision_mask());
|
let mut entity = Entity::new(object_controller, enemy_data.collision_mask());
|
||||||
|
|
||||||
entity
|
let sprite = enemy_data.sprite();
|
||||||
.sprite
|
let sprite = object_controller.get_sprite(sprite).unwrap();
|
||||||
.set_sprite_size(agb::display::object::Size::S16x16);
|
|
||||||
entity.sprite.set_tile_id(enemy_data.tile_id());
|
entity.sprite.set_sprite(sprite);
|
||||||
entity.sprite.show();
|
entity.sprite.show();
|
||||||
|
|
||||||
entity.sprite.commit();
|
entity.sprite.commit();
|
||||||
|
@ -1362,8 +1425,15 @@ impl<'a> Enemy<'a> {
|
||||||
Self { entity, enemy_data }
|
Self { entity, enemy_data }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, player: &Player, level: &Level, sfx: &mut sfx::Sfx) -> UpdateInstruction {
|
fn update(
|
||||||
self.enemy_data.update(&mut self.entity, player, level, sfx)
|
&mut self,
|
||||||
|
controller: &'a ObjectController,
|
||||||
|
player: &Player,
|
||||||
|
level: &Level,
|
||||||
|
sfx: &mut sfx::Sfx,
|
||||||
|
) -> UpdateInstruction {
|
||||||
|
self.enemy_data
|
||||||
|
.update(controller, &mut self.entity, player, level, sfx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1394,9 +1464,10 @@ impl ParticleData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entity: &mut Entity,
|
controller: &'a ObjectController,
|
||||||
|
entity: &mut Entity<'a>,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
_level: &Level,
|
_level: &Level,
|
||||||
) -> UpdateInstruction {
|
) -> UpdateInstruction {
|
||||||
|
@ -1406,7 +1477,11 @@ impl ParticleData {
|
||||||
return UpdateInstruction::Remove;
|
return UpdateInstruction::Remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.sprite.set_tile_id((70 + *frame / 3) * 4);
|
const DUST: &Tag = TAG_MAP.get("dust");
|
||||||
|
let sprite = DUST.get_sprite(*frame as usize / 3);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
*frame += 1;
|
*frame += 1;
|
||||||
UpdateInstruction::None
|
UpdateInstruction::None
|
||||||
|
@ -1416,7 +1491,11 @@ impl ParticleData {
|
||||||
return UpdateInstruction::Remove; // have played the animation 6 times
|
return UpdateInstruction::Remove; // have played the animation 6 times
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.sprite.set_tile_id((88 + (*frame / 3) % 8) * 4);
|
const HEALTH: &Tag = TAG_MAP.get("Heath");
|
||||||
|
let sprite = HEALTH.get_animation_sprite(*frame as usize / 3);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
if *frame < 8 * 3 * 3 {
|
if *frame < 8 * 3 * 3 {
|
||||||
entity.velocity.y = Number::new(-1) / 2;
|
entity.velocity.y = Number::new(-1) / 2;
|
||||||
|
@ -1438,7 +1517,11 @@ impl ParticleData {
|
||||||
UpdateInstruction::None
|
UpdateInstruction::None
|
||||||
}
|
}
|
||||||
ParticleData::BossHealer(frame, target) => {
|
ParticleData::BossHealer(frame, target) => {
|
||||||
entity.sprite.set_tile_id((88 + (*frame / 3) % 8) * 4);
|
const HEALTH: &Tag = TAG_MAP.get("Heath");
|
||||||
|
let sprite = HEALTH.get_animation_sprite(*frame as usize / 3);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
if *frame < 8 * 3 * 3 {
|
if *frame < 8 * 3 * 3 {
|
||||||
entity.velocity.y = Number::new(-1) / 2;
|
entity.velocity.y = Number::new(-1) / 2;
|
||||||
|
@ -1471,7 +1554,7 @@ struct Particle<'a> {
|
||||||
|
|
||||||
impl<'a> Particle<'a> {
|
impl<'a> Particle<'a> {
|
||||||
fn new(
|
fn new(
|
||||||
object_controller: &'a ObjectControl,
|
object_controller: &'a ObjectController,
|
||||||
particle_data: ParticleData,
|
particle_data: ParticleData,
|
||||||
position: Vector2D<Number>,
|
position: Vector2D<Number>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -1480,11 +1563,6 @@ impl<'a> Particle<'a> {
|
||||||
Rect::new((0u16, 0u16).into(), (0u16, 0u16).into()),
|
Rect::new((0u16, 0u16).into(), (0u16, 0u16).into()),
|
||||||
);
|
);
|
||||||
|
|
||||||
entity
|
|
||||||
.sprite
|
|
||||||
.set_sprite_size(agb::display::object::Size::S16x16);
|
|
||||||
entity.sprite.set_tile_id(particle_data.tile_id() * 4);
|
|
||||||
entity.sprite.show();
|
|
||||||
entity.position = position;
|
entity.position = position;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -1493,8 +1571,15 @@ impl<'a> Particle<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, player: &Player, level: &Level) -> UpdateInstruction {
|
fn update(
|
||||||
self.particle_data.update(&mut self.entity, player, level)
|
&mut self,
|
||||||
|
controller: &'a ObjectController,
|
||||||
|
player: &Player,
|
||||||
|
level: &Level,
|
||||||
|
) -> UpdateInstruction {
|
||||||
|
self.entity.sprite.show();
|
||||||
|
self.particle_data
|
||||||
|
.update(controller, &mut self.entity, player, level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1515,14 +1600,14 @@ impl<'a> BossState<'a> {
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
enemies: &mut Arena<Enemy<'a>>,
|
enemies: &mut Arena<Enemy<'a>>,
|
||||||
object_controller: &'a ObjectControl,
|
object_controller: &'a ObjectController,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
) -> BossInstruction {
|
) -> BossInstruction {
|
||||||
match self {
|
match self {
|
||||||
BossState::Active(boss) => boss.update(enemies, object_controller, player, sfx),
|
BossState::Active(boss) => boss.update(enemies, object_controller, player, sfx),
|
||||||
BossState::Following(boss) => {
|
BossState::Following(boss) => {
|
||||||
boss.update(player);
|
boss.update(object_controller, player);
|
||||||
BossInstruction::None
|
BossInstruction::None
|
||||||
}
|
}
|
||||||
BossState::NotSpawned => BossInstruction::None,
|
BossState::NotSpawned => BossInstruction::None,
|
||||||
|
@ -1550,15 +1635,13 @@ struct FollowingBoss<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FollowingBoss<'a> {
|
impl<'a> FollowingBoss<'a> {
|
||||||
fn new(object_controller: &'a ObjectControl, position: Vector2D<Number>) -> Self {
|
fn new(object_controller: &'a ObjectController, position: Vector2D<Number>) -> Self {
|
||||||
let mut entity = Entity::new(
|
let mut entity = Entity::new(
|
||||||
object_controller,
|
object_controller,
|
||||||
Rect::new((0_u16, 0_u16).into(), (0_u16, 0_u16).into()),
|
Rect::new((0_u16, 0_u16).into(), (0_u16, 0_u16).into()),
|
||||||
);
|
);
|
||||||
entity.position = position;
|
entity.position = position;
|
||||||
entity
|
|
||||||
.sprite
|
|
||||||
.set_sprite_size(agb::display::object::Size::S16x16);
|
|
||||||
Self {
|
Self {
|
||||||
entity,
|
entity,
|
||||||
following: true,
|
following: true,
|
||||||
|
@ -1567,11 +1650,11 @@ impl<'a> FollowingBoss<'a> {
|
||||||
gone: false,
|
gone: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn update(&mut self, player: &Player) {
|
fn update(&mut self, controller: &'a ObjectController, player: &Player) {
|
||||||
let difference = player.entity.position - self.entity.position;
|
let difference = player.entity.position - self.entity.position;
|
||||||
self.timer += 1;
|
self.timer += 1;
|
||||||
|
|
||||||
if self.to_hole {
|
let frame = if self.to_hole {
|
||||||
let target: Vector2D<Number> = (17 * 8, -3 * 8).into();
|
let target: Vector2D<Number> = (17 * 8, -3 * 8).into();
|
||||||
let difference = target - self.entity.position;
|
let difference = target - self.entity.position;
|
||||||
if difference.manhattan_distance() < 1.into() {
|
if difference.manhattan_distance() < 1.into() {
|
||||||
|
@ -1580,26 +1663,30 @@ impl<'a> FollowingBoss<'a> {
|
||||||
self.entity.velocity = difference.normalise() * 2;
|
self.entity.velocity = difference.normalise() * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = (self.timer / 8) % 12;
|
self.timer / 8
|
||||||
self.entity.sprite.set_tile_id((125 + frame as u16) * 4);
|
|
||||||
} else if self.timer < 120 {
|
} else if self.timer < 120 {
|
||||||
let frame = (self.timer / 20) % 12;
|
self.timer / 20
|
||||||
self.entity.sprite.set_tile_id((125 + frame as u16) * 4);
|
|
||||||
} else if self.following {
|
} else if self.following {
|
||||||
self.entity.velocity = difference / 16;
|
self.entity.velocity = difference / 16;
|
||||||
if difference.manhattan_distance() < 20.into() {
|
if difference.manhattan_distance() < 20.into() {
|
||||||
self.following = false;
|
self.following = false;
|
||||||
}
|
}
|
||||||
let frame = (self.timer / 8) % 12;
|
self.timer / 8
|
||||||
self.entity.sprite.set_tile_id((125 + frame as u16) * 4);
|
|
||||||
} else {
|
} else {
|
||||||
self.entity.velocity = (0, 0).into();
|
self.entity.velocity = (0, 0).into();
|
||||||
if difference.manhattan_distance() > 60.into() {
|
if difference.manhattan_distance() > 60.into() {
|
||||||
self.following = true;
|
self.following = true;
|
||||||
}
|
}
|
||||||
let frame = (self.timer / 16) % 12;
|
self.timer / 16
|
||||||
self.entity.sprite.set_tile_id((125 + frame as u16) * 4);
|
};
|
||||||
}
|
|
||||||
|
const BOSS: &Tag = TAG_MAP.get("happy boss");
|
||||||
|
|
||||||
|
let sprite = BOSS.get_animation_sprite(frame as usize);
|
||||||
|
let sprite = controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
self.entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
self.entity.update_position_without_collision();
|
self.entity.update_position_without_collision();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1632,15 +1719,11 @@ enum BossInstruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Boss<'a> {
|
impl<'a> Boss<'a> {
|
||||||
fn new(object_controller: &'a ObjectControl, screen_coords: Vector2D<Number>) -> Self {
|
fn new(object_controller: &'a ObjectController, screen_coords: Vector2D<Number>) -> Self {
|
||||||
let mut entity = Entity::new(
|
let mut entity = Entity::new(
|
||||||
object_controller,
|
object_controller,
|
||||||
Rect::new((0_u16, 0_u16).into(), (28_u16, 28_u16).into()),
|
Rect::new((0_u16, 0_u16).into(), (28_u16, 28_u16).into()),
|
||||||
);
|
);
|
||||||
entity
|
|
||||||
.sprite
|
|
||||||
.set_sprite_size(agb::display::object::Size::S32x32);
|
|
||||||
entity.sprite.set_palette(1);
|
|
||||||
entity.position = screen_coords + (144, 136).into();
|
entity.position = screen_coords + (144, 136).into();
|
||||||
Self {
|
Self {
|
||||||
entity,
|
entity,
|
||||||
|
@ -1655,7 +1738,7 @@ impl<'a> Boss<'a> {
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
enemies: &mut Arena<Enemy<'a>>,
|
enemies: &mut Arena<Enemy<'a>>,
|
||||||
object_controller: &'a ObjectControl,
|
object_controller: &'a ObjectController,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
) -> BossInstruction {
|
) -> BossInstruction {
|
||||||
|
@ -1731,8 +1814,14 @@ impl<'a> Boss<'a> {
|
||||||
BossActiveState::WaitUntilKilled => 3.into(),
|
BossActiveState::WaitUntilKilled => 3.into(),
|
||||||
};
|
};
|
||||||
self.timer += 1;
|
self.timer += 1;
|
||||||
let frame = (self.timer / animation_rate) % 12;
|
let frame = self.timer / animation_rate;
|
||||||
self.entity.sprite.set_tile_id(784 + (frame as u16) * 16);
|
|
||||||
|
const BOSS: &Tag = TAG_MAP.get("Boss");
|
||||||
|
|
||||||
|
let sprite = BOSS.get_animation_sprite(frame as usize);
|
||||||
|
let sprite = object_controller.get_sprite(sprite).unwrap();
|
||||||
|
|
||||||
|
self.entity.sprite.set_sprite(sprite);
|
||||||
|
|
||||||
self.entity.update_position_without_collision();
|
self.entity.update_position_without_collision();
|
||||||
instruction
|
instruction
|
||||||
|
@ -1753,7 +1842,7 @@ impl<'a> Boss<'a> {
|
||||||
self.entity
|
self.entity
|
||||||
.commit_with_size(offset + shake, (32, 32).into());
|
.commit_with_size(offset + shake, (32, 32).into());
|
||||||
}
|
}
|
||||||
fn explode(&self, enemies: &mut Arena<Enemy<'a>>, object_controller: &'a ObjectControl) {
|
fn explode(&self, enemies: &mut Arena<Enemy<'a>>, object_controller: &'a ObjectController) {
|
||||||
for _ in 0..(6 - self.health) {
|
for _ in 0..(6 - self.health) {
|
||||||
let x_offset: Number = Number::from_raw(get_random()).rem_euclid(2.into()) - 1;
|
let x_offset: Number = Number::from_raw(get_random()).rem_euclid(2.into()) - 1;
|
||||||
let y_offset: Number = Number::from_raw(get_random()).rem_euclid(2.into()) - 1;
|
let y_offset: Number = Number::from_raw(get_random()).rem_euclid(2.into()) - 1;
|
||||||
|
@ -1825,7 +1914,7 @@ impl<'a> Game<'a> {
|
||||||
|
|
||||||
fn advance_frame(
|
fn advance_frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
object_controller: &'a ObjectControl,
|
object_controller: &'a ObjectController,
|
||||||
sfx: &mut sfx::Sfx,
|
sfx: &mut sfx::Sfx,
|
||||||
) -> GameStatus {
|
) -> GameStatus {
|
||||||
let mut state = GameStatus::Continue;
|
let mut state = GameStatus::Continue;
|
||||||
|
@ -1921,7 +2010,8 @@ impl<'a> Game<'a> {
|
||||||
|
|
||||||
self.input.update();
|
self.input.update();
|
||||||
if let UpdateInstruction::CreateParticle(data, position) =
|
if let UpdateInstruction::CreateParticle(data, position) =
|
||||||
self.player.update(&self.input, &self.level, sfx)
|
self.player
|
||||||
|
.update(object_controller, &self.input, &self.level, sfx)
|
||||||
{
|
{
|
||||||
let new_particle = Particle::new(object_controller, data, position);
|
let new_particle = Particle::new(object_controller, data, position);
|
||||||
|
|
||||||
|
@ -1935,7 +2025,7 @@ impl<'a> Game<'a> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match enemy.update(&self.player, &self.level, sfx) {
|
match enemy.update(object_controller, &self.player, &self.level, sfx) {
|
||||||
UpdateInstruction::Remove => {
|
UpdateInstruction::Remove => {
|
||||||
remove.push(idx);
|
remove.push(idx);
|
||||||
}
|
}
|
||||||
|
@ -1989,7 +2079,7 @@ impl<'a> Game<'a> {
|
||||||
let mut remove = Vec::with_capacity(10);
|
let mut remove = Vec::with_capacity(10);
|
||||||
|
|
||||||
for (idx, particle) in self.particles.iter_mut() {
|
for (idx, particle) in self.particles.iter_mut() {
|
||||||
match particle.update(&self.player, &self.level) {
|
match particle.update(object_controller, &self.player, &self.level) {
|
||||||
UpdateInstruction::Remove => remove.push(idx),
|
UpdateInstruction::Remove => remove.push(idx),
|
||||||
UpdateInstruction::HealBossAndRemove => {
|
UpdateInstruction::HealBossAndRemove => {
|
||||||
sfx.sunrise();
|
sfx.sunrise();
|
||||||
|
@ -2040,7 +2130,7 @@ impl<'a> Game<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_enemies(&mut self, object_controller: &'a ObjectControl) {
|
fn load_enemies(&mut self, object_controller: &'a ObjectController) {
|
||||||
if self.slime_load < self.level.slime_spawns.len() {
|
if self.slime_load < self.level.slime_spawns.len() {
|
||||||
for (idx, slime_spawn) in self
|
for (idx, slime_spawn) in self
|
||||||
.level
|
.level
|
||||||
|
@ -2111,7 +2201,7 @@ impl<'a> Game<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
object: &'a ObjectControl,
|
object: &'a ObjectController,
|
||||||
level: Level,
|
level: Level,
|
||||||
background_distributor: &'a mut BackgroundDistributor,
|
background_distributor: &'a mut BackgroundDistributor,
|
||||||
start_at_boss: bool,
|
start_at_boss: bool,
|
||||||
|
@ -2146,16 +2236,6 @@ impl<'a> Game<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn game_with_level(gba: &mut agb::Gba) {
|
fn game_with_level(gba: &mut agb::Gba) {
|
||||||
{
|
|
||||||
let object = gba.display.object.get();
|
|
||||||
object.set_sprite_palettes(&[
|
|
||||||
objects::objects.palettes[0].clone(),
|
|
||||||
objects::boss.palettes[0].clone(),
|
|
||||||
]);
|
|
||||||
object.set_sprite_tilemap(objects::objects.tiles);
|
|
||||||
object.set_sprite_tilemap_at_idx(8192 - objects::boss.tiles.len(), objects::boss.tiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
let vblank = agb::interrupt::VBlank::get();
|
let vblank = agb::interrupt::VBlank::get();
|
||||||
vblank.wait_for_vblank();
|
vblank.wait_for_vblank();
|
||||||
|
|
||||||
|
@ -2172,8 +2252,7 @@ fn game_with_level(gba: &mut agb::Gba) {
|
||||||
let mut background = gba.display.video.tiled0();
|
let mut background = gba.display.video.tiled0();
|
||||||
background.set_background_palettes(background::background.palettes);
|
background.set_background_palettes(background::background.palettes);
|
||||||
background.set_background_tilemap(0, background::background.tiles);
|
background.set_background_tilemap(0, background::background.tiles);
|
||||||
let mut object = gba.display.object.get();
|
let object = gba.display.object.get();
|
||||||
object.enable();
|
|
||||||
|
|
||||||
let mut game = Game::new(
|
let mut game = Game::new(
|
||||||
&object,
|
&object,
|
||||||
|
|
Loading…
Reference in a new issue