use crate::prelude::*;
use beet_core::prelude::*;
use beet_flow::prelude::*;
use bevy::prelude::Interval;
use std::f32::consts::FRAC_PI_2;
use std::ops::Range;
#[action(set_curve_on_run)]
#[derive(Debug, Clone, PartialEq, Component, Reflect)]
#[reflect(Default, Component)]
#[require(PlayProceduralAnimation)]
pub enum SetCurveOnRun {
EaseRangeDir2 {
range: Range<f32>,
func: EaseFunction,
},
PingPongPause {
target: Vec3,
pause: f32,
func: EaseFunction,
},
}
impl Default for SetCurveOnRun {
fn default() -> Self {
Self::EaseRangeDir2 {
range: -FRAC_PI_2..FRAC_PI_2,
func: EaseFunction::CubicInOut,
}
}
}
impl SetCurveOnRun {}
fn set_curve_on_run(
ev: On<GetOutcome>,
transforms: AgentQuery<&Transform>,
mut rng: ResMut<RandomSource>,
mut query: Query<(&SetCurveOnRun, &mut PlayProceduralAnimation)>,
) -> Result {
let (action, mut anim) = query.get_mut(ev.target())?;
let transform = transforms.get(ev.target())?;
anim.curve = match action {
SetCurveOnRun::EaseRangeDir2 { func, range } => {
let start = Dir2::new(transform.translation.xy())
.unwrap_or_else(|_| Dir2::X);
let angle =
range.start + (range.end - range.start) * rng.random::<f32>();
let end = Dir2::new_unchecked(Vec2::new(angle.cos(), angle.sin()));
EasingCurve::new(start, end, *func).into()
}
SetCurveOnRun::PingPongPause {
target,
func,
pause,
} => {
let start = transform.translation;
let from = EasingCurve::new(start, *target, *func);
let pause =
FunctionCurve::new(Interval::new(0., *pause).unwrap(), |_| {
*target
});
let to = EasingCurve::new(*target, start, *func);
from.chain(pause)
.unwrap()
.chain(to)
.unwrap()
.reparametrize_linear(Interval::UNIT)
.unwrap()
.resample_auto(32)
.unwrap()
.into()
}
};
Ok(())
}