use bevy::{math::VectorSpace, prelude::*};
trait CurveColor: VectorSpace + Into<Color> + Send + Sync + 'static {}
impl<T: VectorSpace + Into<Color> + Send + Sync + 'static> CurveColor for T {}
trait MixedColor: Mix + Into<Color> + Send + Sync + 'static {}
impl<T: Mix + Into<Color> + Send + Sync + 'static> MixedColor for T {}
#[derive(Debug, Component)]
struct Curve<T: CurveColor>(CubicCurve<T>);
#[derive(Debug, Component)]
struct Mixed<T: MixedColor>([T; 4]);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(
Update,
(
animate_curve::<LinearRgba>,
animate_curve::<Oklaba>,
animate_curve::<Xyza>,
animate_mixed::<Hsla>,
animate_mixed::<Srgba>,
animate_mixed::<Oklcha>,
),
)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
let colors = [
LinearRgba::WHITE,
LinearRgba::rgb(1., 1., 0.), LinearRgba::RED,
LinearRgba::BLACK,
];
spawn_curve_sprite(&mut commands, 275., colors);
spawn_curve_sprite(&mut commands, 175., colors.map(Xyza::from));
spawn_curve_sprite(&mut commands, 75., colors.map(Oklaba::from));
spawn_mixed_sprite(&mut commands, -75., colors.map(Hsla::from));
spawn_mixed_sprite(&mut commands, -175., colors.map(Srgba::from));
spawn_mixed_sprite(&mut commands, -275., colors.map(Oklcha::from));
}
fn spawn_curve_sprite<T: CurveColor>(commands: &mut Commands, y: f32, points: [T; 4]) {
commands.spawn((
Sprite::sized(Vec2::new(75., 75.)),
Transform::from_xyz(0., y, 0.),
Curve(CubicBezier::new([points]).to_curve().unwrap()),
));
}
fn spawn_mixed_sprite<T: MixedColor>(commands: &mut Commands, y: f32, colors: [T; 4]) {
commands.spawn((
Transform::from_xyz(0., y, 0.),
Sprite::sized(Vec2::new(75., 75.)),
Mixed(colors),
));
}
fn animate_curve<T: CurveColor>(
time: Res<Time>,
mut query: Query<(&mut Transform, &mut Sprite, &Curve<T>)>,
) {
let t = (ops::sin(time.elapsed_secs()) + 1.) / 2.;
for (mut transform, mut sprite, cubic_curve) in &mut query {
sprite.color = cubic_curve.0.position(t).into();
transform.translation.x = 600. * (t - 0.5);
}
}
fn animate_mixed<T: MixedColor>(
time: Res<Time>,
mut query: Query<(&mut Transform, &mut Sprite, &Mixed<T>)>,
) {
let t = (ops::sin(time.elapsed_secs()) + 1.) / 2.;
for (mut transform, mut sprite, mixed) in &mut query {
sprite.color = {
let intervals = (mixed.0.len() - 1) as f32;
let start_i = (t * intervals).floor().min(intervals - 1.);
let local_t = (t * intervals) - start_i;
let color = mixed.0[start_i as usize].mix(&mixed.0[start_i as usize + 1], local_t);
color.into()
};
transform.translation.x = 600. * (t - 0.5);
}
}