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.

178 lines
6.2 KiB
Rust

use std::{f32::consts::PI, ops::RangeInclusive};
use bevy::{
animation::{animated_field, AnimationTarget, AnimationTargetId},
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);
}
}
#[derive(Event, Clone)]
struct AnimationComplete;
#[derive(Resource, Default)]
pub(crate) struct AnimationStore {
pub store: HashMap<String, AnimationNodeIndex>,
pub graph: AnimationGraphHandle,
}
#[derive(Component)]
pub(crate) struct DelayedAnimation {
pub graph: AnimationGraphHandle,
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(-200.0, 0.0, 0.0);
let b = play::card_placement(&play::PlayLocation { x, y });
let c = Vec3::new(200.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.graph = AnimationGraphHandle(graphs.add(animation_graph));
commands.insert_resource(animation_store);
// TODO: (example: https://bevyengine.org/examples/animation/animated-transform/)
// Button Animations:
// active_button_animation = AnimationClip::default() // color and size
}
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)
.insert(delayed_animation.graph.clone())
.remove::<DelayedAnimation>();
}
});
}