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.
164 lines
5.8 KiB
Rust
164 lines
5.8 KiB
Rust
use bevy::{
|
|
animation::{animated_field, AnimationTarget, AnimationTargetId},
|
|
input::{keyboard::KeyboardInput, ButtonState},
|
|
prelude::*,
|
|
utils::HashMap,
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_systems(Startup, init)
|
|
.add_systems(Update, switch)
|
|
.run();
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
struct AnimationStore(HashMap<String, (AnimationGraphHandle, AnimationNodeIndex)>);
|
|
|
|
fn init(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
mut animations: ResMut<Assets<AnimationClip>>,
|
|
mut graphs: ResMut<Assets<AnimationGraph>>,
|
|
) {
|
|
commands.spawn(Camera2d);
|
|
|
|
commands.spawn((
|
|
Text2d("Press 1/2/3 to trigger animation".into()),
|
|
Node {
|
|
top: Val::Px(-50.0),
|
|
height: Val::Percent(100.0),
|
|
..default()
|
|
},
|
|
));
|
|
|
|
let mut hash_map = HashMap::new();
|
|
{
|
|
let mut a = AnimationClip::default();
|
|
let animatable_curve = AnimatableCurve::new(
|
|
animated_field!(Transform::translation),
|
|
UnevenSampleAutoCurve::new([0.0, 1.0, 2.0, 3.0, 4.0].into_iter().zip([
|
|
Vec3::new(200.0, 200.0, 0.0),
|
|
Vec3::new(-200.0, 200.0, 0.0),
|
|
Vec3::new(-200.0, -200.0, 0.0),
|
|
Vec3::new(200.0, -200.0, 0.0),
|
|
// in case seamless looping is wanted, the last keyframe should
|
|
// be the same as the first one
|
|
Vec3::new(200.0, 200.0, 0.0),
|
|
]))
|
|
.expect("should be able to build translation curve because we pass in valid samples"),
|
|
);
|
|
a.add_curve_to_target(
|
|
AnimationTargetId::from_name(&Name::new("Circle")),
|
|
animatable_curve,
|
|
);
|
|
let (graph, animation_index) = AnimationGraph::from_clip(animations.add(a));
|
|
let graph_handle = AnimationGraphHandle(graphs.add(graph));
|
|
hash_map.insert("Box".into(), (graph_handle, animation_index));
|
|
};
|
|
{
|
|
let mut a = AnimationClip::default();
|
|
let animatable_curve = AnimatableCurve::new(
|
|
animated_field!(Transform::translation),
|
|
UnevenSampleAutoCurve::new([0.0, 1.0, 2.0].into_iter().zip([
|
|
Vec3::new(200.0, 200.0, 0.0),
|
|
Vec3::new(-200.0, -200.0, 0.0),
|
|
Vec3::new(200.0, 200.0, 0.0),
|
|
]))
|
|
.expect("should be able to build translation curve because we pass in valid samples"),
|
|
);
|
|
a.add_curve_to_target(
|
|
AnimationTargetId::from_name(&Name::new("Circle")),
|
|
animatable_curve,
|
|
);
|
|
let (graph, animation_index) = AnimationGraph::from_clip(animations.add(a));
|
|
let graph_handle = AnimationGraphHandle(graphs.add(graph));
|
|
hash_map.insert("Diag1".into(), (graph_handle, animation_index));
|
|
};
|
|
{
|
|
let mut a = AnimationClip::default();
|
|
let animatable_curve = AnimatableCurve::new(
|
|
animated_field!(Transform::translation),
|
|
UnevenSampleAutoCurve::new([0.0, 1.0, 2.0].into_iter().zip([
|
|
Vec3::new(-200.0, 200.0, 0.0),
|
|
Vec3::new(200.0, -200.0, 0.0),
|
|
// in case seamless looping is wanted, the last keyframe should
|
|
// be the same as the first one
|
|
Vec3::new(-200.0, 200.0, 0.0),
|
|
]))
|
|
.expect("should be able to build translation curve because we pass in valid samples"),
|
|
);
|
|
a.add_curve_to_target(
|
|
AnimationTargetId::from_name(&Name::new("Circle")),
|
|
animatable_curve,
|
|
);
|
|
let (graph, animation_index) = AnimationGraph::from_clip(animations.add(a));
|
|
let graph_handle = AnimationGraphHandle(graphs.add(graph));
|
|
hash_map.insert("Diag2".into(), (graph_handle, animation_index));
|
|
};
|
|
|
|
let store = AnimationStore(hash_map);
|
|
commands.insert_resource(store);
|
|
|
|
let shape = meshes.add(Circle::new(50.0));
|
|
let material = materials.add(Color::WHITE);
|
|
commands.spawn((
|
|
Mesh2d(shape),
|
|
MeshMaterial2d(material),
|
|
Name::new("Circle"),
|
|
AnimationPlayer::default(),
|
|
));
|
|
}
|
|
|
|
fn switch(
|
|
mut commands: Commands,
|
|
mut evr_kbd: EventReader<KeyboardInput>,
|
|
mut query: Query<(Entity, &Name, &mut AnimationPlayer)>,
|
|
store: Res<AnimationStore>,
|
|
) {
|
|
evr_kbd
|
|
.read()
|
|
.filter(|ev| ev.state == ButtonState::Pressed)
|
|
.for_each(|ev| match ev.key_code {
|
|
KeyCode::Digit1 => {
|
|
let (g, ai) = store.0.get("Box".into()).unwrap();
|
|
let (e, n, mut ap) = query.single_mut();
|
|
ap.stop_all().play(ai.clone());
|
|
commands.entity(e).insert((
|
|
g.clone(),
|
|
AnimationTarget {
|
|
id: AnimationTargetId::from_name(n),
|
|
player: e,
|
|
},
|
|
));
|
|
}
|
|
KeyCode::Digit2 => {
|
|
let (g, ai) = store.0.get("Diag1".into()).unwrap();
|
|
let (e, n, mut ap) = query.single_mut();
|
|
ap.stop_all().play(ai.clone());
|
|
commands.entity(e).insert((
|
|
g.clone(),
|
|
AnimationTarget {
|
|
id: AnimationTargetId::from_name(n),
|
|
player: e,
|
|
},
|
|
));
|
|
}
|
|
KeyCode::Digit3 => {
|
|
let (g, ai) = store.0.get("Diag2".into()).unwrap();
|
|
let (e, n, mut ap) = query.single_mut();
|
|
ap.stop_all().play(ai.clone());
|
|
commands.entity(e).insert((
|
|
g.clone(),
|
|
AnimationTarget {
|
|
id: AnimationTargetId::from_name(n),
|
|
player: e,
|
|
},
|
|
));
|
|
}
|
|
_ => (),
|
|
});
|
|
}
|