Path: blob/main/examples/animation/animated_transform.rs
6592 views
//! Create and play an animation defined by code that operates on the [`Transform`] component.12use std::f32::consts::PI;34use bevy::{5animation::{animated_field, AnimationTarget, AnimationTargetId},6prelude::*,7};89fn main() {10App::new()11.add_plugins(DefaultPlugins)12.insert_resource(AmbientLight {13color: Color::WHITE,14brightness: 150.0,15..default()16})17.add_systems(Startup, setup)18.run();19}2021fn setup(22mut commands: Commands,23mut meshes: ResMut<Assets<Mesh>>,24mut materials: ResMut<Assets<StandardMaterial>>,25mut animations: ResMut<Assets<AnimationClip>>,26mut graphs: ResMut<Assets<AnimationGraph>>,27) {28// Camera29commands.spawn((30Camera3d::default(),31Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),32));3334// Light35commands.spawn((36PointLight {37intensity: 500_000.0,38..default()39},40Transform::from_xyz(0.0, 2.5, 0.0),41));4243// Let's use the `Name` component to target entities. We can use anything we44// like, but names are convenient.45let planet = Name::new("planet");46let orbit_controller = Name::new("orbit_controller");47let satellite = Name::new("satellite");4849// Creating the animation50let mut animation = AnimationClip::default();51// A curve can modify a single part of a transform: here, the translation.52let planet_animation_target_id = AnimationTargetId::from_name(&planet);53animation.add_curve_to_target(54planet_animation_target_id,55AnimatableCurve::new(56animated_field!(Transform::translation),57UnevenSampleAutoCurve::new([0.0, 1.0, 2.0, 3.0, 4.0].into_iter().zip([58Vec3::new(1.0, 0.0, 1.0),59Vec3::new(-1.0, 0.0, 1.0),60Vec3::new(-1.0, 0.0, -1.0),61Vec3::new(1.0, 0.0, -1.0),62// in case seamless looping is wanted, the last keyframe should63// be the same as the first one64Vec3::new(1.0, 0.0, 1.0),65]))66.expect("should be able to build translation curve because we pass in valid samples"),67),68);69// Or it can modify the rotation of the transform.70// To find the entity to modify, the hierarchy will be traversed looking for71// an entity with the right name at each level.72let orbit_controller_animation_target_id =73AnimationTargetId::from_names([planet.clone(), orbit_controller.clone()].iter());74animation.add_curve_to_target(75orbit_controller_animation_target_id,76AnimatableCurve::new(77animated_field!(Transform::rotation),78UnevenSampleAutoCurve::new([0.0, 1.0, 2.0, 3.0, 4.0].into_iter().zip([79Quat::IDENTITY,80Quat::from_axis_angle(Vec3::Y, PI / 2.),81Quat::from_axis_angle(Vec3::Y, PI / 2. * 2.),82Quat::from_axis_angle(Vec3::Y, PI / 2. * 3.),83Quat::IDENTITY,84]))85.expect("Failed to build rotation curve"),86),87);88// If a curve in an animation is shorter than the other, it will not repeat89// until all other curves are finished. In that case, another animation should90// be created for each part that would have a different duration / period.91let satellite_animation_target_id = AnimationTargetId::from_names(92[planet.clone(), orbit_controller.clone(), satellite.clone()].iter(),93);94animation.add_curve_to_target(95satellite_animation_target_id,96AnimatableCurve::new(97animated_field!(Transform::scale),98UnevenSampleAutoCurve::new(99[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0]100.into_iter()101.zip([102Vec3::splat(0.8),103Vec3::splat(1.2),104Vec3::splat(0.8),105Vec3::splat(1.2),106Vec3::splat(0.8),107Vec3::splat(1.2),108Vec3::splat(0.8),109Vec3::splat(1.2),110Vec3::splat(0.8),111]),112)113.expect("Failed to build scale curve"),114),115);116// There can be more than one curve targeting the same entity path.117animation.add_curve_to_target(118AnimationTargetId::from_names(119[planet.clone(), orbit_controller.clone(), satellite.clone()].iter(),120),121AnimatableCurve::new(122animated_field!(Transform::rotation),123UnevenSampleAutoCurve::new([0.0, 1.0, 2.0, 3.0, 4.0].into_iter().zip([124Quat::IDENTITY,125Quat::from_axis_angle(Vec3::Y, PI / 2.),126Quat::from_axis_angle(Vec3::Y, PI / 2. * 2.),127Quat::from_axis_angle(Vec3::Y, PI / 2. * 3.),128Quat::IDENTITY,129]))130.expect("should be able to build translation curve because we pass in valid samples"),131),132);133134// Create the animation graph135let (graph, animation_index) = AnimationGraph::from_clip(animations.add(animation));136137// Create the animation player, and set it to repeat138let mut player = AnimationPlayer::default();139player.play(animation_index).repeat();140141// Create the scene that will be animated142// First entity is the planet143let planet_entity = commands144.spawn((145Mesh3d(meshes.add(Sphere::default())),146MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))),147// Add the animation graph and player148planet,149AnimationGraphHandle(graphs.add(graph)),150player,151))152.id();153commands.entity(planet_entity).insert((154AnimationTarget {155id: planet_animation_target_id,156player: planet_entity,157},158children![(159Transform::default(),160Visibility::default(),161orbit_controller,162AnimationTarget {163id: orbit_controller_animation_target_id,164player: planet_entity,165},166children![(167Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),168MeshMaterial3d(materials.add(Color::srgb(0.3, 0.9, 0.3))),169Transform::from_xyz(1.5, 0.0, 0.0),170AnimationTarget {171id: satellite_animation_target_id,172player: planet_entity,173},174satellite,175)],176)],177));178}179180181