mirror of
https://github.com/bevyengine/bevy
synced 2024-11-29 08:00:20 +00:00
efda7f3f9c
Takes the first two commits from #15375 and adds suggestions from this comment: https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300 See #15375 for more reasoning/motivation. ## Rebasing (rerunning) ```rust git switch simpler-lint-fixes git reset --hard main cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate cargo fmt --all git add --update git commit --message "rustfmt" cargo clippy --workspace --all-targets --all-features --fix cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate cargo fmt --all git add --update git commit --message "clippy" git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887 ```
182 lines
6.3 KiB
Rust
182 lines
6.3 KiB
Rust
//! Create and play an animation defined by code that operates on the [`Transform`] component.
|
|
|
|
use std::f32::consts::PI;
|
|
|
|
use bevy::{
|
|
animation::{AnimationTarget, AnimationTargetId},
|
|
prelude::*,
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.insert_resource(AmbientLight {
|
|
color: Color::WHITE,
|
|
brightness: 150.0,
|
|
})
|
|
.add_systems(Startup, setup)
|
|
.run();
|
|
}
|
|
|
|
fn setup(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
mut animations: ResMut<Assets<AnimationClip>>,
|
|
mut graphs: ResMut<Assets<AnimationGraph>>,
|
|
) {
|
|
// Camera
|
|
commands.spawn(Camera3dBundle {
|
|
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
..default()
|
|
});
|
|
|
|
// Light
|
|
commands.spawn(PointLightBundle {
|
|
point_light: PointLight {
|
|
intensity: 500_000.0,
|
|
..default()
|
|
},
|
|
transform: Transform::from_xyz(0.0, 2.5, 0.0),
|
|
..default()
|
|
});
|
|
|
|
// Let's use the `Name` component to target entities. We can use anything we
|
|
// like, but names are convenient.
|
|
let planet = Name::new("planet");
|
|
let orbit_controller = Name::new("orbit_controller");
|
|
let satellite = Name::new("satellite");
|
|
|
|
// Creating the animation
|
|
let mut animation = AnimationClip::default();
|
|
// A curve can modify a single part of a transform, here the translation
|
|
let planet_animation_target_id = AnimationTargetId::from_name(&planet);
|
|
animation.add_curve_to_target(
|
|
planet_animation_target_id,
|
|
VariableCurve::linear::<TranslationKeyframes>(
|
|
[0.0, 1.0, 2.0, 3.0, 4.0],
|
|
[
|
|
Vec3::new(1.0, 0.0, 1.0),
|
|
Vec3::new(-1.0, 0.0, 1.0),
|
|
Vec3::new(-1.0, 0.0, -1.0),
|
|
Vec3::new(1.0, 0.0, -1.0),
|
|
// in case seamless looping is wanted, the last keyframe should
|
|
// be the same as the first one
|
|
Vec3::new(1.0, 0.0, 1.0),
|
|
],
|
|
),
|
|
);
|
|
// Or it can modify the rotation of the transform.
|
|
// To find the entity to modify, the hierarchy will be traversed looking for
|
|
// an entity with the right name at each level
|
|
let orbit_controller_animation_target_id =
|
|
AnimationTargetId::from_names([planet.clone(), orbit_controller.clone()].iter());
|
|
animation.add_curve_to_target(
|
|
orbit_controller_animation_target_id,
|
|
VariableCurve::linear::<RotationKeyframes>(
|
|
[0.0, 1.0, 2.0, 3.0, 4.0],
|
|
[
|
|
Quat::IDENTITY,
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2.),
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2. * 2.),
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2. * 3.),
|
|
Quat::IDENTITY,
|
|
],
|
|
),
|
|
);
|
|
// If a curve in an animation is shorter than the other, it will not repeat
|
|
// until all other curves are finished. In that case, another animation should
|
|
// be created for each part that would have a different duration / period
|
|
let satellite_animation_target_id = AnimationTargetId::from_names(
|
|
[planet.clone(), orbit_controller.clone(), satellite.clone()].iter(),
|
|
);
|
|
animation.add_curve_to_target(
|
|
satellite_animation_target_id,
|
|
VariableCurve::linear::<ScaleKeyframes>(
|
|
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0],
|
|
[
|
|
Vec3::splat(0.8),
|
|
Vec3::splat(1.2),
|
|
Vec3::splat(0.8),
|
|
Vec3::splat(1.2),
|
|
Vec3::splat(0.8),
|
|
Vec3::splat(1.2),
|
|
Vec3::splat(0.8),
|
|
Vec3::splat(1.2),
|
|
Vec3::splat(0.8),
|
|
],
|
|
),
|
|
);
|
|
// There can be more than one curve targeting the same entity path
|
|
animation.add_curve_to_target(
|
|
AnimationTargetId::from_names(
|
|
[planet.clone(), orbit_controller.clone(), satellite.clone()].iter(),
|
|
),
|
|
VariableCurve::linear::<RotationKeyframes>(
|
|
[0.0, 1.0, 2.0, 3.0, 4.0],
|
|
[
|
|
Quat::IDENTITY,
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2.),
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2. * 2.),
|
|
Quat::from_axis_angle(Vec3::Y, PI / 2. * 3.),
|
|
Quat::IDENTITY,
|
|
],
|
|
),
|
|
);
|
|
|
|
// Create the animation graph
|
|
let (graph, animation_index) = AnimationGraph::from_clip(animations.add(animation));
|
|
|
|
// Create the animation player, and set it to repeat
|
|
let mut player = AnimationPlayer::default();
|
|
player.play(animation_index).repeat();
|
|
|
|
// Create the scene that will be animated
|
|
// First entity is the planet
|
|
let planet_entity = commands
|
|
.spawn((
|
|
PbrBundle {
|
|
mesh: meshes.add(Sphere::default()),
|
|
material: materials.add(Color::srgb(0.8, 0.7, 0.6)),
|
|
..default()
|
|
},
|
|
// Add the animation graph and player
|
|
planet,
|
|
graphs.add(graph),
|
|
player,
|
|
))
|
|
.id();
|
|
commands
|
|
.entity(planet_entity)
|
|
.insert(AnimationTarget {
|
|
id: planet_animation_target_id,
|
|
player: planet_entity,
|
|
})
|
|
.with_children(|p| {
|
|
// This entity is just used for animation, but doesn't display anything
|
|
p.spawn((
|
|
SpatialBundle::INHERITED_IDENTITY,
|
|
orbit_controller,
|
|
AnimationTarget {
|
|
id: orbit_controller_animation_target_id,
|
|
player: planet_entity,
|
|
},
|
|
))
|
|
.with_children(|p| {
|
|
// The satellite, placed at a distance of the planet
|
|
p.spawn((
|
|
PbrBundle {
|
|
transform: Transform::from_xyz(1.5, 0.0, 0.0),
|
|
mesh: meshes.add(Cuboid::new(0.5, 0.5, 0.5)),
|
|
material: materials.add(Color::srgb(0.3, 0.9, 0.3)),
|
|
..default()
|
|
},
|
|
AnimationTarget {
|
|
id: satellite_animation_target_id,
|
|
player: planet_entity,
|
|
},
|
|
satellite,
|
|
));
|
|
});
|
|
});
|
|
}
|