use bevy::{ core::FixedTimestep, gltf::*, math::{const_quat, const_vec3}, prelude::*, scene::InstanceId, }; /// This illustrates loading animations from GLTF files and manually playing them. /// Note that a higher level animation api is in the works. This exists to illustrate how to /// read and build a custom GLTF animator, not to illustrate a final Bevy animation api. fn main() { App::new() .add_plugins(DefaultPlugins) .insert_resource(AmbientLight { color: Color::WHITE, brightness: 1.0, }) .add_startup_system(setup) .add_system_set( SystemSet::new() .with_run_criteria(FixedTimestep::step(10.0)) .with_system(switch_scene), ) .add_system(setup_scene_once_loaded) .add_system(gltf_animation_driver) .run(); } struct Example { model_name: &'static str, camera_transform: Transform, speed: f32, } impl Example { const fn new(model_name: &'static str, camera_transform: Transform, speed: f32) -> Self { Self { model_name, camera_transform, speed, } } } // const ANIMATIONS: [(&str, Transform, f32); 3] = [ const ANIMATIONS: [Example; 3] = [ // https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/AnimatedTriangle Example::new( "models/animated/AnimatedTriangle.gltf", Transform { translation: const_vec3!([0.0, 0.0, 3.0]), rotation: const_quat!([0.0, 0.0, 0.0, 1.0]), scale: const_vec3!([1.0; 3]), }, 0.12, ), // https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/BoxAnimated Example::new( "models/animated/BoxAnimated.gltf", Transform { translation: const_vec3!([4.0, 2.0, 4.0]), rotation: const_quat!([-0.08, 0.38, 0.03, 0.92]), scale: const_vec3!([1.0; 3]), }, 0.4, ), Example::new( "models/animated/animations.gltf", Transform { translation: const_vec3!([-10.0, 5.0, -3.0]), rotation: const_quat!([0.16, 0.69, 0.16, -0.69]), scale: const_vec3!([1.0; 3]), }, 2.5, ), ]; struct CurrentScene { instance_id: InstanceId, animation: Handle, speed: f32, } struct CurrentAnimation { start_time: f64, animation: GltfAnimation, } fn setup( mut commands: Commands, asset_server: Res, mut scene_spawner: ResMut, ) { // Insert a resource with the current scene information commands.insert_resource(CurrentScene { // Its instance id, to be able to check that it's loaded instance_id: scene_spawner .spawn(asset_server.load(&format!("{}#Scene0", ANIMATIONS[0].model_name))), // The handle to the first animation animation: asset_server.load(&format!("{}#Animation0", ANIMATIONS[0].model_name)), // The animation speed modifier speed: ANIMATIONS[0].speed, }); // Add a camera commands.spawn_bundle(PerspectiveCameraBundle { transform: ANIMATIONS[0].camera_transform, ..Default::default() }); // Add a directional light commands.spawn_bundle(DirectionalLightBundle::default()); } // Switch the scene to the next one every 10 seconds fn switch_scene( mut commands: Commands, scene_root: Query, Without, Without)>, mut camera: Query<&mut Transform, With>, mut current: Local, mut current_scene: ResMut, asset_server: Res, mut scene_spawner: ResMut, ) { *current = (*current + 1) % ANIMATIONS.len(); // Despawn the existing scene, then start loading the next one commands.entity(scene_root.single()).despawn_recursive(); current_scene.instance_id = scene_spawner .spawn(asset_server.load(&format!("{}#Scene0", ANIMATIONS[*current].model_name))); current_scene.animation = asset_server.load(&format!("{}#Animation0", ANIMATIONS[*current].model_name)); current_scene.speed = ANIMATIONS[*current].speed; // Update the camera position *camera.single_mut() = ANIMATIONS[*current].camera_transform; // Reset the current animation commands.remove_resource::(); } // Setup the scene for animation once it is loaded, by adding the animation to a resource with // the start time. fn setup_scene_once_loaded( mut commands: Commands, scene_spawner: Res, current_scene: Res, time: Res