You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.9 KiB
Rust
203 lines
6.9 KiB
Rust
use std::{f32::consts::PI, ops::RangeInclusive};
|
|
|
|
use bevy::{
|
|
animation::{animated_field, AnimationTarget, AnimationTargetId},
|
|
color::palettes::css::{BLACK, BLUE, GREEN, PINK, RED},
|
|
prelude::*,
|
|
utils::HashMap,
|
|
};
|
|
|
|
use crate::{
|
|
deck::Deck,
|
|
play::{self, Selected},
|
|
};
|
|
|
|
pub struct AnimationPlugin;
|
|
|
|
impl Plugin for AnimationPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.add_systems(Update, delayed_animation).add_systems(
|
|
Update,
|
|
animate_button.run_if(any_with_component::<AnimateButton>),
|
|
);
|
|
}
|
|
}
|
|
|
|
#[derive(Event, Clone)]
|
|
struct AnimationComplete;
|
|
|
|
#[derive(Resource, Default)]
|
|
pub(crate) struct AnimationStore {
|
|
pub store: HashMap<String, AnimationNodeIndex>,
|
|
pub card_graph: AnimationGraphHandle,
|
|
}
|
|
|
|
#[derive(Component)]
|
|
pub(crate) struct DelayedAnimation {
|
|
pub animation_index: AnimationNodeIndex,
|
|
pub delay: Timer,
|
|
}
|
|
|
|
pub(crate) fn setup_animations(
|
|
mut clips: ResMut<Assets<AnimationClip>>,
|
|
mut graphs: ResMut<Assets<AnimationGraph>>,
|
|
mut commands: Commands,
|
|
) {
|
|
let mut animation_store = AnimationStore::default();
|
|
|
|
let mut animation_graph = AnimationGraph::new();
|
|
|
|
let targets: Vec<AnimationTargetId> = Deck::iter_cards()
|
|
.map(|c| Name::new(format!("{}", c)))
|
|
.map(|n| AnimationTargetId::from_name(&n))
|
|
.collect();
|
|
|
|
// Rotation Animation
|
|
{
|
|
let mut animation = AnimationClip::default();
|
|
targets.iter().for_each(|target| {
|
|
let curve = AnimatableCurve::new(
|
|
animated_field!(Transform::rotation),
|
|
AnimatableKeyframeCurve::new([0.0, 5.0, 10.0, 15.0, 20.0].into_iter().zip([
|
|
Quat::IDENTITY,
|
|
Quat::from_axis_angle(Vec3::Z, PI / 2.),
|
|
Quat::from_axis_angle(Vec3::Z, PI / 2. * 2.),
|
|
Quat::from_axis_angle(Vec3::Z, PI / 2. * 3.),
|
|
Quat::IDENTITY,
|
|
]))
|
|
.expect("Rotation animation"),
|
|
);
|
|
animation.add_curve_to_target(*target, curve);
|
|
});
|
|
let animation_handle = clips.add(animation);
|
|
let animation_index = animation_graph.add_clip(animation_handle, 1.0, animation_graph.root);
|
|
animation_store
|
|
.store
|
|
.insert("rotate".into(), animation_index);
|
|
}
|
|
|
|
{
|
|
// For each spot on board
|
|
RangeInclusive::<u8>::new(0, 3).for_each(|x| {
|
|
RangeInclusive::<u8>::new(0, 3).for_each(|y| {
|
|
let a = Vec3::new(-125.0, 0.0, 2.0);
|
|
let b = play::card_placement(&play::PlayLocation { x, y });
|
|
let c = Vec3::new(125.0, 0.0, 0.0);
|
|
|
|
// Serve Deck -> Spot Animation
|
|
{
|
|
let mut animation = AnimationClip::default();
|
|
targets.iter().for_each(|target| {
|
|
let curve = AnimatableCurve::new(
|
|
animated_field!(Transform::translation),
|
|
AnimatableKeyframeCurve::new([0.0, 1.0].into_iter().zip([a, b]))
|
|
.expect("Serve Card animation"),
|
|
);
|
|
animation.add_curve_to_target(*target, curve);
|
|
});
|
|
animation.set_duration(1.0);
|
|
animation.add_event(1.0, AnimationComplete);
|
|
let animation_handle = clips.add(animation);
|
|
let animation_index =
|
|
animation_graph.add_clip(animation_handle, 1.0, animation_graph.root);
|
|
animation_store
|
|
.store
|
|
.insert(format!("deck->{:?}", (x, y)), animation_index);
|
|
}
|
|
|
|
// Spot -> Discard Animation
|
|
{
|
|
let mut animation = AnimationClip::default();
|
|
targets.iter().for_each(|target| {
|
|
let curve = AnimatableCurve::new(
|
|
animated_field!(Transform::translation),
|
|
AnimatableKeyframeCurve::new([0.0, 1.0].into_iter().zip([b, c]))
|
|
.expect("Serve Card animation"),
|
|
);
|
|
animation.add_curve_to_target(*target, curve);
|
|
});
|
|
animation.set_duration(1.0);
|
|
animation.add_event(1.0, AnimationComplete);
|
|
let animation_handle = clips.add(animation);
|
|
let animation_index =
|
|
animation_graph.add_clip(animation_handle, 1.0, animation_graph.root);
|
|
animation_store
|
|
.store
|
|
.insert(format!("{:?}->discard", (x, y)), animation_index);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
animation_store.card_graph = AnimationGraphHandle(graphs.add(animation_graph));
|
|
|
|
commands.insert_resource(animation_store);
|
|
}
|
|
|
|
pub(crate) fn play_selected_animation(
|
|
trigger: Trigger<OnInsert, Selected>,
|
|
mut query: Query<&mut AnimationPlayer>,
|
|
store: Res<AnimationStore>,
|
|
) {
|
|
let ai = store.store.get("rotate".into()).unwrap();
|
|
query
|
|
.get_mut(trigger.entity())
|
|
.unwrap()
|
|
.start(ai.clone())
|
|
.repeat();
|
|
}
|
|
|
|
pub(crate) fn stop_selected_animation(
|
|
trigger: Trigger<OnRemove, Selected>,
|
|
mut query: Query<(&mut Transform, &mut AnimationPlayer)>,
|
|
) {
|
|
let (mut t, mut ap) = query.get_mut(trigger.entity()).unwrap();
|
|
ap.rewind_all().stop_all();
|
|
t.rotation = Quat::default();
|
|
}
|
|
|
|
fn delayed_animation(
|
|
mut query: Query<(Entity, &mut DelayedAnimation, &mut AnimationPlayer), With<AnimationTarget>>,
|
|
mut commands: Commands,
|
|
time: Res<Time>,
|
|
) {
|
|
query
|
|
.iter_mut()
|
|
.for_each(|(entity, mut delayed_animation, mut animation_player)| {
|
|
delayed_animation.delay.tick(time.delta());
|
|
if delayed_animation.delay.just_finished() {
|
|
animation_player.start(delayed_animation.animation_index);
|
|
commands.entity(entity).remove::<DelayedAnimation>();
|
|
}
|
|
});
|
|
}
|
|
|
|
#[derive(Component)]
|
|
pub(crate) struct AnimateButton;
|
|
|
|
pub(crate) fn animate_button(
|
|
query: Single<(&mut BackgroundColor, &mut Transform), With<AnimateButton>>,
|
|
time: Res<Time>,
|
|
) {
|
|
// t is a value in the range (0..=1)
|
|
let t = (f32::cos(time.elapsed_secs_wrapped()) + 1.0) / 2.0;
|
|
let (mut bg, mut tr) = query.into_inner();
|
|
|
|
// We want values from 0..3 for picking a color
|
|
bg.0 = match t * 3.0 {
|
|
0.0..=1.0 => Srgba::interpolate(&RED, &GREEN, t % 1.0).into(),
|
|
1.0..=2.0 => Srgba::interpolate(&GREEN, &BLUE, t % 1.0).into(),
|
|
2.0..=3.0 => Srgba::interpolate(&BLUE, &RED, t % 1.0).into(),
|
|
_ => todo!(),
|
|
};
|
|
|
|
// We want angles from -0.5..0.5 for angle
|
|
tr.rotation = Quat::from_axis_angle(Vec3::Z, (t / 2.0) - 0.25);
|
|
|
|
if t > 0.5 {
|
|
tr.scale += time.delta_secs() / 20.0;
|
|
} else {
|
|
tr.scale -= time.delta_secs() / 20.0;
|
|
}
|
|
}
|