diff --git a/examples/basic.rs b/examples/basic.rs index 6debe1f4f903273756487a4992f6346994a27bb7..1a122a75d9f37392b98cd9fe6561af54aff76858 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use bevy::render::camera::ScalingMode; -use micro_banimate::definitions::{AnimationSet, AnimationStatus, DirectionalAnimationBundle}; +use micro_banimate::definitions::{create_directional_animation, AnimationSet, AnimationStatus}; use micro_banimate::directionality::{Directionality, Horizontal}; fn main() { @@ -48,23 +48,20 @@ fn spawn_assets(mut commands: Commands, assets: Res<ExampleAssets>) { const HEIGHT: f32 = 320.0; commands.spawn(( - TextureAtlas { - layout: assets.atlas.clone_weak(), - index: 0, - }, - SpriteBundle { - texture: assets.sprites.clone_weak(), - ..Default::default() - }, - DirectionalAnimationBundle::with_direction( - "idle", - assets.animations.clone_weak(), - Directionality::Right, + Sprite::from_atlas_image( + assets.sprites.clone_weak(), + TextureAtlas { + layout: assets.atlas.clone_weak(), + index: 0, + }, ), + create_directional_animation(assets.animations.clone_weak(), "idle"), + Directionality::Right, )); - commands.spawn(Camera2dBundle { - projection: OrthographicProjection { + commands.spawn(( + Camera2d::default(), + OrthographicProjection { area: Rect::new(-(WIDTH / 2.0), -(HEIGHT / 2.0), WIDTH / 2.0, HEIGHT / 2.0), scaling_mode: ScalingMode::AutoMin { min_height: HEIGHT, @@ -72,10 +69,9 @@ fn spawn_assets(mut commands: Commands, assets: Res<ExampleAssets>) { }, far: 1000., near: -1000., - ..Default::default() + ..OrthographicProjection::default_2d() }, - ..Default::default() - }); + )); } fn process_input( diff --git a/src/definitions.rs b/src/definitions.rs index 5a2b43b3cc8060d5353fcc3cbcc8d606068b9788..b3f0eb6df1119d6b6965f3af961a66efb024a409 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -27,6 +27,9 @@ impl AnimationFrames { )] pub struct AnimationSet(pub HashMap<String, AnimationFrames>); +#[derive(Clone, Debug, Component, PartialEq, Default, Deref, DerefMut)] +pub struct AnimationHandle(pub Handle<AnimationSet>); + #[derive(Copy, Clone, Debug, Component, PartialEq, Eq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SyncToParent; @@ -59,7 +62,7 @@ pub enum AnimationMode { }, } -#[derive(Clone, Debug, Component, PartialEq, PartialOrd, Default)] +#[derive(Clone, Debug, Component, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct AnimationStatus { pub active_name: String, @@ -67,6 +70,16 @@ pub struct AnimationStatus { pub frame_time: f32, } +impl Default for AnimationStatus { + fn default() -> Self { + Self { + active_name: String::from("idle"), + active_step: 0, + frame_time: 0.0, + } + } +} + impl From<String> for AnimationStatus { fn from(value: String) -> Self { AnimationStatus { @@ -78,6 +91,13 @@ impl From<String> for AnimationStatus { } impl AnimationStatus { + pub fn new(name: impl ToString) -> Self { + AnimationStatus { + active_name: name.to_string(), + active_step: 0, + frame_time: 0.0, + } + } pub fn set_animation(&mut self, name: impl ToString) { self.active_name = name.to_string(); } @@ -94,64 +114,44 @@ impl AnimationStatus { } } -#[derive(Clone, Debug, Bundle, Default)] -pub struct DirectionalAnimationBundle { - pub animation_handle: Handle<AnimationSet>, - pub mode: AnimationMode, - pub status: AnimationStatus, - pub direction: Directionality, -} - -impl DirectionalAnimationBundle { - pub fn new(initial_anim: impl ToString, handle: Handle<AnimationSet>) -> Self { - Self { - animation_handle: handle, - status: AnimationStatus { - active_name: initial_anim.to_string(), - active_step: 0, - frame_time: 0.0, - }, - mode: AnimationMode::Loop, - direction: Directionality::default(), - } - } - pub fn with_direction( - initial_anim: impl ToString, - handle: Handle<AnimationSet>, - direction: Directionality, - ) -> Self { - Self { - animation_handle: handle, - status: AnimationStatus { - active_name: initial_anim.to_string(), - active_step: 0, - frame_time: 0.0, - }, - mode: AnimationMode::Loop, - direction, - } - } -} - -#[derive(Clone, Debug, Bundle, Default)] -pub struct SpriteAnimationBundle { - pub animation_handle: Handle<AnimationSet>, - pub mode: AnimationMode, - pub status: AnimationStatus, -} - -impl SpriteAnimationBundle { - pub fn new(initial_anim: impl ToString, handle: Handle<AnimationSet>) -> Self { - Self { - animation_handle: handle, - status: AnimationStatus { - active_name: initial_anim.to_string(), - active_step: 0, - frame_time: 0.0, - }, - mode: AnimationMode::Loop, - } - } +#[derive(Component)] +#[require(AnimationHandle, AnimationStatus, AnimationMode, Sprite)] +pub struct SpriteAnimation; +pub fn create_sprite_animation( + handle: Handle<AnimationSet>, + initial_anim: impl ToString, +) -> impl Bundle { + ( + SpriteAnimation, + AnimationHandle(handle), + AnimationStatus::new(initial_anim), + ) +} + +#[derive(Component)] +#[require( + AnimationHandle, + AnimationStatus, + AnimationMode, + Directionality, + Sprite +)] +pub struct DirectionalAnimation; +pub fn create_directional_animation( + handle: Handle<AnimationSet>, + initial_anim: impl ToString, +) -> impl Bundle { + ( + DirectionalAnimation, + AnimationHandle(handle), + AnimationStatus::new(initial_anim), + ) +} +#[derive(Component)] +#[require(Sprite, SyncToParent)] +pub struct ChildAnimation; +pub fn create_child_animation() -> impl Bundle { + (ChildAnimation,) } #[derive(Clone, Debug, Component, PartialEq, PartialOrd, Default, Deref, DerefMut)] @@ -160,6 +160,7 @@ impl SpriteAnimationBundle { derive(serde::Serialize, serde::Deserialize), serde(transparent) )] +#[require(SimpleAnimationStatus)] pub struct SimpleAnimation(pub AnimationFrames); impl From<AnimationFrames> for SimpleAnimation { fn from(value: AnimationFrames) -> Self { @@ -174,21 +175,9 @@ pub struct SimpleAnimationStatus { pub frame_time: f32, } -#[derive(Clone, Debug, Bundle, PartialEq, PartialOrd, Default)] -pub struct SimpleAnimationBundle { - pub anim: SimpleAnimation, - pub status: SimpleAnimationStatus, -} - -impl SimpleAnimationBundle { +impl SimpleAnimation { pub fn new(frames: Vec<usize>, frame_secs: f32) -> Self { - SimpleAnimationBundle { - anim: AnimationFrames { frames, frame_secs }.into(), - status: SimpleAnimationStatus { - active_step: 0, - frame_time: 0.0, - }, - } + AnimationFrames { frames, frame_secs }.into() } } @@ -202,6 +191,7 @@ pub struct OverrideData(pub u128); derive(serde::Serialize, serde::Deserialize), serde(transparent) )] +#[require(OverrideData)] pub struct AnimationOverride(pub AnimationStatus); impl AnimationOverride { @@ -234,8 +224,3 @@ impl AnimationOverrideBundle { } } } - -#[derive(Clone, Debug, Bundle, Default)] -pub struct ChildAnimationBundle { - marker: SyncToParent, -} diff --git a/src/loader.rs b/src/loader.rs index 1484e640705748e9858600c57c7f871d1af223ee..3eb340d19b8a8f0b1bbede747086693e723749ba 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -27,7 +27,7 @@ impl Error for LoaderError {} #[cfg(feature = "json_loader")] mod json_loader { use bevy::asset::io::Reader; - use bevy::asset::{AssetLoader, AsyncReadExt, LoadContext}; + use bevy::asset::{AssetLoader, LoadContext}; use crate::definitions::AnimationSet; use crate::loader::LoaderError; @@ -38,11 +38,11 @@ mod json_loader { type Settings = (); type Error = LoaderError; - async fn load<'a>( - &'a self, - reader: &'a mut Reader<'_>, - _settings: &'a Self::Settings, - _load_context: &'a mut LoadContext<'_>, + async fn load( + &self, + reader: &mut dyn Reader, + _settings: &Self::Settings, + _load_context: &mut LoadContext<'_>, ) -> Result<Self::Asset, Self::Error> { let mut bytes = Vec::new(); reader @@ -74,11 +74,11 @@ mod toml_loader { type Settings = (); type Error = LoaderError; - async fn load<'a>( - &'a self, - reader: &'a mut Reader<'_>, - _settings: &'a Self::Settings, - _load_context: &'a mut LoadContext<'_>, + async fn load( + &self, + reader: &mut dyn Reader, + _settings: &Self::Settings, + _load_context: &mut LoadContext<'_>, ) -> Result<Self::Asset, Self::Error> { let mut bytes = String::new(); reader diff --git a/src/query.rs b/src/query.rs index aca0e35664f9027acaa421fd76f47af7a5c76b6a..fdff10755e3e37b53c81adb48dd47e62fbb1a542 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,50 +1,48 @@ use crate::definitions::{ - AnimationOverride, AnimationPaused, AnimationSet, AnimationStatus, OverrideData, - SimpleAnimation, SimpleAnimationStatus, SyncToParent, + AnimationHandle, AnimationOverride, AnimationPaused, AnimationSet, AnimationStatus, + OverrideData, SimpleAnimation, SimpleAnimationStatus, SyncToParent, }; use crate::directionality::Directionality; use crate::systems::AnimationCompleted; use bevy::asset::Assets; use bevy::ecs::query::{QueryData, QueryFilter}; -use bevy::prelude::{ - Commands, Entity, EventWriter, Handle, Parent, Query, Res, Time, With, Without, -}; -use bevy::sprite::TextureAtlas; +use bevy::prelude::{Commands, Entity, EventWriter, Parent, Query, Res, Time, With, Without}; +use bevy::sprite::Sprite; #[derive(QueryData)] #[query_data(mutable)] pub struct AnimationComponents { - handle: &'static Handle<AnimationSet>, + handle: &'static AnimationHandle, status: &'static mut AnimationStatus, - atlas: &'static mut TextureAtlas, + sprite: &'static mut Sprite, } #[derive(QueryData)] #[query_data(mutable)] pub struct DirectionalAnimationComponents { - handle: &'static Handle<AnimationSet>, + handle: &'static AnimationHandle, direction: &'static Directionality, status: &'static mut AnimationStatus, - atlas: &'static mut TextureAtlas, + sprite: &'static mut Sprite, } #[derive(QueryData)] #[query_data(mutable)] pub struct OverrideAnimationComponents { - handle: &'static Handle<AnimationSet>, + handle: &'static AnimationHandle, data: Option<&'static OverrideData>, status: &'static mut AnimationOverride, - atlas: &'static mut TextureAtlas, + sprite: &'static mut Sprite, } #[derive(QueryData)] #[query_data(mutable)] pub struct DirectionalOverrideAnimationComponents { - handle: &'static Handle<AnimationSet>, + handle: &'static AnimationHandle, direction: &'static Directionality, data: Option<&'static OverrideData>, status: &'static mut AnimationOverride, - atlas: &'static mut TextureAtlas, + sprite: &'static mut Sprite, } #[derive(QueryData)] @@ -52,7 +50,7 @@ pub struct DirectionalOverrideAnimationComponents { pub struct SimpleAnimationComponents { anim: &'static SimpleAnimation, status: &'static mut SimpleAnimationStatus, - atlas: &'static mut TextureAtlas, + sprite: &'static mut Sprite, } #[derive(QueryFilter)] pub struct OnlyAnimations { @@ -83,7 +81,7 @@ pub struct OnlyDirectionalOverrideAnimations { macro_rules! get_current_anim { ($anims: expr, $handle: expr, $name: expr) => { - match $anims.get($handle) { + match $anims.get($handle.id()) { Some(active) => match active.get(&$name) { Some(inner) => inner, None => continue, @@ -92,7 +90,7 @@ macro_rules! get_current_anim { } }; ($anims: expr, $handle: expr, $name: expr, $($also: expr),+) => { - match $anims.get($handle) { + match $anims.get($handle.id()) { Some(active) => match active.get(&$name)$(.or_else(|| active.get(&$also)))+ { Some(inner) => inner, None => continue, @@ -103,27 +101,31 @@ macro_rules! get_current_anim { } macro_rules! tick_animation { - ($delta: expr, $anim: expr, $status: expr, $atlas: expr) => {{ - let current_frame = $atlas.index; - let mut has_looped = false; + ($delta: expr, $anim: expr, $status: expr, $sprite: expr) => {{ + if let Some(atlas) = $sprite.texture_atlas.as_mut() { + let current_frame = atlas.index; + let mut has_looped = false; - $status.frame_time += $delta.as_secs_f32(); - while $status.frame_time >= $anim.frame_secs { - $status.frame_time = ($status.frame_time - $anim.frame_secs).max(0.0); - let next_frame = $status.active_step.saturating_add(1); - $status.active_step = if next_frame >= $anim.frames.len() { - has_looped = true; - 0 - } else { - next_frame - }; - } + $status.frame_time += $delta.as_secs_f32(); + while $status.frame_time >= $anim.frame_secs { + $status.frame_time = ($status.frame_time - $anim.frame_secs).max(0.0); + let next_frame = $status.active_step.saturating_add(1); + $status.active_step = if next_frame >= $anim.frames.len() { + has_looped = true; + 0 + } else { + next_frame + }; + } - if current_frame != $anim.frames[$status.active_step] { - $atlas.index = $anim.frames[$status.active_step]; - } + if current_frame != $anim.frames[$status.active_step] { + atlas.index = $anim.frames[$status.active_step]; + } - has_looped + has_looped + } else { + false + } }}; } @@ -136,11 +138,11 @@ pub fn play_animations( for AnimationComponentsItem { mut status, handle, - mut atlas, + mut sprite, } in &mut anim_query { let anim = get_current_anim!(animations, handle, status.active_name); - tick_animation!(delta, anim, status, atlas); + tick_animation!(delta, anim, status, sprite); } } @@ -153,7 +155,7 @@ pub fn play_directional_animations( for DirectionalAnimationComponentsItem { mut status, handle, - mut atlas, + mut sprite, direction, } in &mut anim_query { @@ -164,7 +166,7 @@ pub fn play_directional_animations( status.active_name ); - tick_animation!(delta, anim, status, atlas); + tick_animation!(delta, anim, status, sprite); } } @@ -181,13 +183,13 @@ pub fn play_override_animation( OverrideAnimationComponentsItem { mut status, handle, - mut atlas, + mut sprite, data, }, ) in &mut anim_query { let anim = get_current_anim!(animations, handle, status.active_name); - let looped = tick_animation!(delta, anim, status, atlas); + let looped = tick_animation!(delta, anim, status, sprite); if looped { commands .entity(entity) @@ -220,7 +222,7 @@ pub fn play_directional_override_animation( mut status, direction, handle, - mut atlas, + mut sprite, data, }, ) in &mut anim_query @@ -232,7 +234,7 @@ pub fn play_directional_override_animation( status.active_name ); - let looped = tick_animation!(delta, anim, status, atlas); + let looped = tick_animation!(delta, anim, status, sprite); if looped { commands .entity(entity) @@ -255,22 +257,33 @@ pub fn play_simple_animation( let delta = time.delta(); for SimpleAnimationComponentsItem { mut status, - mut atlas, + mut sprite, anim, } in &mut anim_query { - tick_animation!(delta, *anim, status, atlas); + tick_animation!(delta, *anim, status, sprite); } } pub fn sync_child_animation( - mut children: Query<(&Parent, &mut TextureAtlas), With<SyncToParent>>, - parents: Query<&TextureAtlas, Without<SyncToParent>>, + mut children: Query<(&Parent, &mut Sprite), With<SyncToParent>>, + parents: Query<&Sprite, Without<SyncToParent>>, ) { for (parent, mut child_sprite) in &mut children { if let Ok(parent_sprite) = parents.get(**parent) { - if parent_sprite.index != child_sprite.index { - child_sprite.index = parent_sprite.index; + match ( + parent_sprite.texture_atlas.as_ref(), + child_sprite.texture_atlas.as_mut(), + ) { + (Some(parent_value), Some(child_value)) => { + if child_value.index != parent_value.index { + *child_value = parent_value.clone(); + } + } + (Some(parent_value), None) => { + child_sprite.texture_atlas = Some(parent_value.clone()); + } + _ => {} } } }