color_animation/
color_animation.rs1use bevy::{math::VectorSpace, prelude::*};
4
5trait CurveColor: VectorSpace<Scalar = f32> + Into<Color> + Send + Sync + 'static {}
7
8impl<T: VectorSpace<Scalar = f32> + Into<Color> + Send + Sync + 'static> CurveColor for T {}
9
10trait MixedColor: Mix + Into<Color> + Send + Sync + 'static {}
12
13impl<T: Mix + Into<Color> + Send + Sync + 'static> MixedColor for T {}
14
15#[derive(Debug, Component)]
16struct Curve<T: CurveColor>(CubicCurve<T>);
17
18#[derive(Debug, Component)]
19struct Mixed<T: MixedColor>([T; 4]);
20
21fn main() {
22 App::new()
23 .add_plugins(DefaultPlugins)
24 .add_systems(Startup, setup)
25 .add_systems(
26 Update,
27 (
28 animate_curve::<LinearRgba>,
29 animate_curve::<Oklaba>,
30 animate_curve::<Xyza>,
31 animate_mixed::<Hsla>,
32 animate_mixed::<Srgba>,
33 animate_mixed::<Oklcha>,
34 ),
35 )
36 .run();
37}
38
39fn setup(mut commands: Commands) {
40 commands.spawn(Camera2d);
41
42 let colors = [
48 LinearRgba::WHITE,
49 LinearRgba::rgb(1., 1., 0.), LinearRgba::RED,
51 LinearRgba::BLACK,
52 ];
53 spawn_curve_sprite(&mut commands, 275., colors);
55
56 spawn_curve_sprite(&mut commands, 175., colors.map(Xyza::from));
58
59 spawn_curve_sprite(&mut commands, 75., colors.map(Oklaba::from));
60
61 spawn_mixed_sprite(&mut commands, -75., colors.map(Hsla::from));
67
68 spawn_mixed_sprite(&mut commands, -175., colors.map(Srgba::from));
69
70 spawn_mixed_sprite(&mut commands, -275., colors.map(Oklcha::from));
71}
72
73fn spawn_curve_sprite<T: CurveColor>(commands: &mut Commands, y: f32, points: [T; 4]) {
74 commands.spawn((
75 Sprite::sized(Vec2::new(75., 75.)),
76 Transform::from_xyz(0., y, 0.),
77 Curve(CubicBezier::new([points]).to_curve().unwrap()),
78 ));
79}
80
81fn spawn_mixed_sprite<T: MixedColor>(commands: &mut Commands, y: f32, colors: [T; 4]) {
82 commands.spawn((
83 Transform::from_xyz(0., y, 0.),
84 Sprite::sized(Vec2::new(75., 75.)),
85 Mixed(colors),
86 ));
87}
88
89fn animate_curve<T: CurveColor>(
90 time: Res<Time>,
91 mut query: Query<(&mut Transform, &mut Sprite, &Curve<T>)>,
92) {
93 let t = (ops::sin(time.elapsed_secs()) + 1.) / 2.;
94
95 for (mut transform, mut sprite, cubic_curve) in &mut query {
96 sprite.color = cubic_curve.0.position(t).into();
99 transform.translation.x = 600. * (t - 0.5);
100 }
101}
102
103fn animate_mixed<T: MixedColor>(
104 time: Res<Time>,
105 mut query: Query<(&mut Transform, &mut Sprite, &Mixed<T>)>,
106) {
107 let t = (ops::sin(time.elapsed_secs()) + 1.) / 2.;
108
109 for (mut transform, mut sprite, mixed) in &mut query {
110 sprite.color = {
111 let intervals = (mixed.0.len() - 1) as f32;
114
115 let start_i = (t * intervals).floor().min(intervals - 1.);
117
118 let local_t = (t * intervals) - start_i;
120
121 let color = mixed.0[start_i as usize].mix(&mixed.0[start_i as usize + 1], local_t);
122 color.into()
123 };
124 transform.translation.x = 600. * (t - 0.5);
125 }
126}