Skip to content
Snippets Groups Projects
query.rs 6.97 KiB
Newer Older
Louis's avatar
Louis committed
use crate::definitions::{
	AnimationHandle, AnimationOverride, AnimationPaused, AnimationSet, AnimationStatus,
	OverrideData, SimpleAnimation, SimpleAnimationStatus, SyncToParent,
Louis's avatar
Louis committed
};
use crate::directionality::Directionality;
Louis's avatar
Louis committed
use crate::systems::AnimationCompleted;
Louis's avatar
Louis committed
use bevy::ecs::query::{QueryData, QueryFilter};
use bevy::prelude::{Commands, Entity, EventWriter, Parent, Query, Res, Time, With, Without};
use bevy::sprite::Sprite;
Louis's avatar
Louis committed
#[derive(QueryData)]
#[query_data(mutable)]
pub struct AnimationComponents {
	handle: &'static AnimationHandle,
	status: &'static mut AnimationStatus,
	sprite: &'static mut Sprite,
Louis's avatar
Louis committed
#[derive(QueryData)]
#[query_data(mutable)]
pub struct DirectionalAnimationComponents {
	handle: &'static AnimationHandle,
	direction: &'static Directionality,
	status: &'static mut AnimationStatus,
	sprite: &'static mut Sprite,
Louis's avatar
Louis committed
#[derive(QueryData)]
#[query_data(mutable)]
pub struct OverrideAnimationComponents {
	handle: &'static AnimationHandle,
	data: Option<&'static OverrideData>,
	status: &'static mut AnimationOverride,
	sprite: &'static mut Sprite,
#[derive(QueryData)]
#[query_data(mutable)]
pub struct DirectionalOverrideAnimationComponents {
	handle: &'static AnimationHandle,
	direction: &'static Directionality,
	data: Option<&'static OverrideData>,
	status: &'static mut AnimationOverride,
	sprite: &'static mut Sprite,
Louis's avatar
Louis committed
#[derive(QueryData)]
#[query_data(mutable)]
pub struct SimpleAnimationComponents {
	anim: &'static SimpleAnimation,
	status: &'static mut SimpleAnimationStatus,
	sprite: &'static mut Sprite,
Louis's avatar
Louis committed
#[derive(QueryFilter)]
pub struct OnlyAnimations {
	_status: With<AnimationStatus>,
	_override: Without<AnimationOverride>,
	_direction: Without<Directionality>,
	_paused: Without<AnimationPaused>,
}
Louis's avatar
Louis committed
#[derive(QueryFilter)]
pub struct OnlyDirectionalAnimations {
	_status: With<AnimationStatus>,
	_direction: With<Directionality>,
	_override: Without<AnimationOverride>,
	_paused: Without<AnimationPaused>,
}
Louis's avatar
Louis committed
#[derive(QueryFilter)]
pub struct OnlyOverrideAnimations {
	_override: With<AnimationOverride>,
	_direction: Without<Directionality>,
	_paused: Without<AnimationPaused>,
}
Louis's avatar
Louis committed
#[derive(QueryFilter)]
pub struct OnlyDirectionalOverrideAnimations {
	_override: With<AnimationOverride>,
	_direction: With<Directionality>,
	_paused: Without<AnimationPaused>,
}
Louis's avatar
Louis committed

macro_rules! get_current_anim {
	($anims: expr, $handle: expr, $name: expr) => {
		match $anims.get($handle.id()) {
			Some(active) => match active.get(&$name) {
				Some(inner) => inner,
				None => continue,
			},
			None => continue,
Louis's avatar
Louis committed
		}
	};
	($anims: expr, $handle: expr, $name: expr, $($also: expr),+) => {
		match $anims.get($handle.id()) {
			Some(active) => match active.get(&$name)$(.or_else(|| active.get(&$also)))+ {
				Some(inner) => inner,
				None => continue,
			},
			None => continue,
		}
	};
}
	($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
				};
			}
			if current_frame != $anim.frames[$status.active_step] {
				atlas.index = $anim.frames[$status.active_step];
			}
			has_looped
		} else {
			false
		}
pub fn play_animations(
	time: Res<Time>,
	mut anim_query: Query<AnimationComponents, OnlyAnimations>,
	animations: Res<Assets<AnimationSet>>,
) {
	let delta = time.delta();
	for AnimationComponentsItem {
		mut status,
		handle,
	} in &mut anim_query
	{
		let anim = get_current_anim!(animations, handle, status.active_name);
		tick_animation!(delta, anim, status, sprite);
Louis's avatar
Louis committed
	}
pub fn play_directional_animations(
	time: Res<Time>,
	mut anim_query: Query<DirectionalAnimationComponents, OnlyDirectionalAnimations>,
	animations: Res<Assets<AnimationSet>>,
) {
	let delta = time.delta();
	for DirectionalAnimationComponentsItem {
		mut status,
		handle,
		direction,
	} in &mut anim_query
	{
		let anim = get_current_anim!(
			animations,
			handle,
			format!("{}_{}", status.active_name, direction),
			status.active_name
		);

		tick_animation!(delta, anim, status, sprite);
Louis's avatar
Louis committed
	}
pub fn play_override_animation(
	time: Res<Time>,
	mut commands: Commands,
	mut anim_query: Query<(Entity, OverrideAnimationComponents), OnlyOverrideAnimations>,
	animations: Res<Assets<AnimationSet>>,
	mut events: EventWriter<AnimationCompleted>,
) {
	let delta = time.delta();
	for (
		entity,
		OverrideAnimationComponentsItem {
			mut status,
			handle,
			data,
		},
	) in &mut anim_query
	{
		let anim = get_current_anim!(animations, handle, status.active_name);
		let looped = tick_animation!(delta, anim, status, sprite);
		if looped {
			commands
				.entity(entity)
				.remove::<(AnimationOverride, OverrideData)>();

			if let Some(data) = data {
				events.send(AnimationCompleted {
					entity,
					user_data: **data,
				});
pub fn play_directional_override_animation(
	time: Res<Time>,
	mut commands: Commands,
	mut anim_query: Query<
		(Entity, DirectionalOverrideAnimationComponents),
		OnlyDirectionalOverrideAnimations,
	>,
	animations: Res<Assets<AnimationSet>>,
	mut events: EventWriter<AnimationCompleted>,
) {
	let delta = time.delta();
	for (
		entity,
		DirectionalOverrideAnimationComponentsItem {
			mut status,
			direction,
			handle,
			data,
		},
	) in &mut anim_query
	{
		let anim = get_current_anim!(
			animations,
			handle,
			format!("{}_{}", status.active_name, direction),
			status.active_name
		);

		let looped = tick_animation!(delta, anim, status, sprite);
		if looped {
			commands
				.entity(entity)
				.remove::<(AnimationOverride, OverrideData)>();

			if let Some(data) = data {
				events.send(AnimationCompleted {
					entity,
					user_data: **data,
				});
			}
		}
	}
}

pub fn play_simple_animation(
	time: Res<Time>,
	mut anim_query: Query<SimpleAnimationComponents, Without<AnimationPaused>>,
) {
	let delta = time.delta();
	for SimpleAnimationComponentsItem {
		mut status,
		tick_animation!(delta, *anim, status, sprite);
Louis's avatar
Louis committed
	}
	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) {
			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());
				}
				_ => {}