diff --git a/src/lib.rs b/src/lib.rs index 6a04cef..e1839c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -177,6 +177,9 @@ pub use tween::resource_tween_system; #[allow(deprecated)] pub use tween::resource_tween_system_full; +pub use tween::tween_event_system; +pub use tween::tween_event_taking_system; + /// Default plugins for using crate. /// /// Plugins: @@ -193,7 +196,8 @@ impl PluginGroup for DefaultTweenPlugins { .add(TweenCorePlugin::default()) .add(interpolate::DefaultInterpolatorsPlugin) .add(interpolate::DefaultDynInterpolatorsPlugin) - .add(interpolation::EaseFunctionPlugin); + .add(interpolation::EaseFunctionPlugin) + .add(tween::TweenEventPlugin); #[cfg(feature = "span_tween")] let p = p.add(span_tween::SpanTweenPlugin); p diff --git a/src/tween.rs b/src/tween.rs index 15577d0..dd9d3c3 100644 --- a/src/tween.rs +++ b/src/tween.rs @@ -235,6 +235,7 @@ use bevy::prelude::*; use crate::interpolate::Interpolator; use crate::tween_timer::AnimationDirection; +use crate::BevyTweenRegisterSystems; mod systems; #[allow(deprecated)] @@ -252,6 +253,7 @@ pub use systems::{ resource_dyn_tween_system, resource_tween_system, resource_tween_system_full, }; +pub use systems::{tween_event_system, tween_event_taking_system}; /// Skip a tween from tweening. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Component, Reflect)] @@ -614,3 +616,48 @@ impl From<&[Handle; N]> for TargetAsset { TargetAsset::assets(value.iter().cloned()) } } + +/// Currently only just registers `tween_event_system::<()>` +pub struct TweenEventPlugin; + +impl Plugin for TweenEventPlugin { + fn build(&self, app: &mut App) { + app.add_tween_systems(systems::tween_event_system::<()>); + } +} + +/// Fires [`TweenEvent`] whenever [`TweenProgressed`] and [`TweenEventData`] exist in the same entity. +#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Component, Reflect)] +#[reflect(Component)] +pub struct TweenEventData(pub Option) +where + Data: Send + Sync + 'static; + +impl TweenEventData { + /// Create new [`TweenEventData`] with custom user data. + pub fn new(data: Data) -> Self { + TweenEventData(Some(data)) + } +} + +impl TweenEventData<()> { + /// Create new [`TweenEventData`] with no custom user data. + pub fn no_data() -> Self { + TweenEventData(Some(())) + } +} + +/// Fires whenever [`TweenProgressed`] and [`TweenEventData`] exist in the same entity. +#[derive(Debug, Clone, PartialEq, Event, Reflect)] +pub struct TweenEvent { + /// Custom user data + pub data: Data, + /// Progress percentage of the tween + pub progressed: f32, + /// Sampled value of an interpolation. + pub interpolation_value: Option, + /// Direction + pub direction: AnimationDirection, + /// The entity + pub entity: Entity, +} diff --git a/src/tween/systems.rs b/src/tween/systems.rs index a305078..fb40766 100644 --- a/src/tween/systems.rs +++ b/src/tween/systems.rs @@ -272,3 +272,69 @@ where { asset_tween_system::>>.into_configs() } + +/// Fires [`TweenEvent`] with optional user data whenever [`TweenProgressed`] +/// and [`TweenEventData`] exist in the same entity and data is `Some`, +/// cloning the data. +#[allow(clippy::type_complexity)] +pub fn tween_event_system( + q_tween_event_data: Query< + ( + Entity, + &TweenEventData, + &TweenProgressed, + Option<&TweenInterpolationValue>, + ), + Without, + >, + mut event_writer: EventWriter>, +) where + Data: Clone + Send + Sync + 'static, +{ + q_tween_event_data.iter().for_each( + |(entity, event_data, progressed, interpolation_value)| { + if let Some(data) = event_data.0.as_ref() { + event_writer.send(TweenEvent { + data: data.clone(), + progressed: progressed.0, + interpolation_value: interpolation_value.map(|v| v.0), + direction: progressed.1, + entity, + }); + } + }, + ); +} + +/// Fires [`TweenEvent`] with optional user data whenever [`TweenProgressed`] +/// and [`TweenEventData`] exist in the same entity and data is `Some`, +/// taking the data and leaves the value `None`. +#[allow(clippy::type_complexity)] +pub fn tween_event_taking_system( + mut q_tween_event_data: Query< + ( + Entity, + &mut TweenEventData, + &TweenProgressed, + Option<&TweenInterpolationValue>, + ), + Without, + >, + mut event_writer: EventWriter>, +) where + Data: Send + Sync + 'static, +{ + q_tween_event_data.iter_mut().for_each( + |(entity, mut event_data, progressed, interpolation_value)| { + if let Some(data) = event_data.0.take() { + event_writer.send(TweenEvent { + data, + progressed: progressed.0, + interpolation_value: interpolation_value.map(|v| v.0), + direction: progressed.1, + entity, + }); + } + }, + ); +}