mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
example on how to create an animation in code (#4399)
# Objective - Animation can be used outside of glTF, but are not obvious on how to create them ## Solution - Add an example creating an animation
This commit is contained in:
parent
01bdf67c33
commit
3555603df1
3 changed files with 146 additions and 0 deletions
|
@ -241,6 +241,10 @@ path = "examples/3d/wireframe.rs"
|
|||
name = "animated_fox"
|
||||
path = "examples/animation/animated_fox.rs"
|
||||
|
||||
[[example]]
|
||||
name = "animated_transform"
|
||||
path = "examples/animation/animated_transform.rs"
|
||||
|
||||
[[example]]
|
||||
name = "custom_skinned_mesh"
|
||||
path = "examples/animation/custom_skinned_mesh.rs"
|
||||
|
|
|
@ -123,6 +123,7 @@ Example | File | Description
|
|||
Example | File | Description
|
||||
--- | --- | ---
|
||||
`animated_fox` | [`animation/animated_fox.rs`](./animation/animated_fox.rs) | Plays an animation from a skinned glTF.
|
||||
`animated_transform` | [`animation/animated_transform.rs`](./animation/animated_transform.rs) | Create and play an animation defined by code that operates on the `Transform` component.
|
||||
`custom_skinned_mesh` | [`animation/custom_skinned_mesh.rs`](./animation/custom_skinned_mesh.rs) | Skinned mesh example with mesh and joints data defined in code.
|
||||
`gltf_skinned_mesh` | [`animation/gltf_skinned_mesh.rs`](./animation/gltf_skinned_mesh.rs) | Skinned mesh example with mesh and joints data loaded from a glTF file.
|
||||
|
||||
|
|
141
examples/animation/animated_transform.rs
Normal file
141
examples/animation/animated_transform.rs
Normal file
|
@ -0,0 +1,141 @@
|
|||
use std::f32::consts::{FRAC_PI_2, PI};
|
||||
|
||||
use bevy::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.insert_resource(AmbientLight {
|
||||
color: Color::WHITE,
|
||||
brightness: 1.0,
|
||||
})
|
||||
.add_startup_system(setup)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut animations: ResMut<Assets<AnimationClip>>,
|
||||
) {
|
||||
// Camera
|
||||
commands.spawn_bundle(PerspectiveCameraBundle {
|
||||
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..default()
|
||||
});
|
||||
|
||||
// The animation API uses the `Name` component to target entities
|
||||
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
|
||||
animation.add_curve_to_path(
|
||||
EntityPath {
|
||||
parts: vec![planet.clone()],
|
||||
},
|
||||
VariableCurve {
|
||||
keyframe_timestamps: vec![0.0, 1.0, 2.0, 3.0, 4.0],
|
||||
keyframes: Keyframes::Translation(vec![
|
||||
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
|
||||
animation.add_curve_to_path(
|
||||
EntityPath {
|
||||
parts: vec![planet.clone(), orbit_controller.clone()],
|
||||
},
|
||||
VariableCurve {
|
||||
keyframe_timestamps: vec![0.0, 1.0, 2.0, 3.0, 4.0],
|
||||
keyframes: Keyframes::Rotation(vec![
|
||||
Quat::from_axis_angle(Vec3::Y, 0.0),
|
||||
Quat::from_axis_angle(Vec3::Y, FRAC_PI_2),
|
||||
Quat::from_axis_angle(Vec3::Y, PI),
|
||||
Quat::from_axis_angle(Vec3::Y, 3.0 * FRAC_PI_2),
|
||||
Quat::from_axis_angle(Vec3::Y, 0.0),
|
||||
]),
|
||||
},
|
||||
);
|
||||
// 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
|
||||
animation.add_curve_to_path(
|
||||
EntityPath {
|
||||
parts: vec![planet.clone(), orbit_controller.clone(), satellite.clone()],
|
||||
},
|
||||
VariableCurve {
|
||||
keyframe_timestamps: vec![0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0],
|
||||
keyframes: Keyframes::Scale(vec![
|
||||
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_path(
|
||||
EntityPath {
|
||||
parts: vec![planet.clone(), orbit_controller.clone(), satellite.clone()],
|
||||
},
|
||||
VariableCurve {
|
||||
keyframe_timestamps: vec![0.0, 1.0, 2.0, 3.0, 4.0],
|
||||
keyframes: Keyframes::Rotation(vec![
|
||||
Quat::from_axis_angle(Vec3::Y, 0.0),
|
||||
Quat::from_axis_angle(Vec3::Y, FRAC_PI_2),
|
||||
Quat::from_axis_angle(Vec3::Y, PI),
|
||||
Quat::from_axis_angle(Vec3::Y, 3.0 * FRAC_PI_2),
|
||||
Quat::from_axis_angle(Vec3::Y, 0.0),
|
||||
]),
|
||||
},
|
||||
);
|
||||
|
||||
// Create the animation player, and set it to repeat
|
||||
let mut player = AnimationPlayer::default();
|
||||
player.play(animations.add(animation)).repeat();
|
||||
|
||||
// Create the scene that will be animated
|
||||
// First entity is the planet
|
||||
commands
|
||||
.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Icosphere::default())),
|
||||
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
|
||||
..default()
|
||||
})
|
||||
// Add the Name component, and the animation player
|
||||
.insert_bundle((planet, player))
|
||||
.with_children(|p| {
|
||||
// This entity is just used for animation, but doesn't display anything
|
||||
p.spawn_bundle(TransformBundle { ..default() })
|
||||
// Add the Name component
|
||||
.insert(orbit_controller)
|
||||
.with_children(|p| {
|
||||
// The satellite, placed at a distance of the planet
|
||||
p.spawn_bundle(PbrBundle {
|
||||
transform: Transform::from_xyz(1.5, 0.0, 0.0),
|
||||
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.5 })),
|
||||
material: materials.add(Color::rgb(0.3, 0.9, 0.3).into()),
|
||||
..default()
|
||||
})
|
||||
// Add the Name component
|
||||
.insert(satellite);
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue