Improve the animated_mesh
example (#17328)
# Objective Building upon https://github.com/bevyengine/bevy/pull/17191, improve the `animated_mesh` example by removing code, adding comments, and making the example more c&p'able. ## Solution - Split the setup function in two to clarify what the example is demonstrating. - `setup_mesh_and_animation` is the demonstration. - `setup_camera_and_environment` just sets up the example app. - Changed the animation playing to use `AnimationPlayer` directly instead of creating `AnimationTransitions`. - This appears sufficient when only playing a single animation. - Added a comment pointing users to an example of multiple animations. - Changed the animation to be the run cycle. - I think it got accidentally changed to the idle in [#17191](https://github.com/bevyengine/bevy/pull/17191), so this is reverting back to the original. - Note that we can improve it to select the animation by name if [#16529](https://github.com/bevyengine/bevy/pull/16529) lands. - Renamed `FOX_PATH` to a more neutral `GLTF_PATH`. - Updated the example descriptions to mention the fox. - This adds a little character and hints that the example involves character animation. - Removed a seemingly redundant `AnimationGraphHandle` component. - Removed an unnecessary `clone()`. - Added various comments. ## Notes - A draft of this PR was discussed on Discord: https://discord.com/channels/691052431525675048/1326910663972618302/1326920498663133348 - There was discord discussion on whether a component is "inserted onto", "inserted into" or "added to" an entity. - "Added to" is most common in code and docs, and seems best to me. But it awkwardly differs from the name of `EntityCommands::insert`. - This PR prefers "added to". - I plan to follow up this PR with similar changes to the `animated_mesh_control` and `animated_mesh_events` examples. - But I could roll them into this PR if requested. ## Testing `cargo run --example animated_mesh` --------- Co-authored-by: François Mockers <mockersf@gmail.com>
This commit is contained in:
parent
b90329aef5
commit
c96949dabe
@ -1289,7 +1289,7 @@ doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.animated_mesh]
|
||||
name = "Animated Mesh"
|
||||
description = "Plays an animation from a skinned glTF"
|
||||
description = "Plays an animation on a skinned glTF model of a fox"
|
||||
category = "Animation"
|
||||
wasm = true
|
||||
|
||||
|
@ -194,7 +194,7 @@ Example | Description
|
||||
|
||||
Example | Description
|
||||
--- | ---
|
||||
[Animated Mesh](../examples/animation/animated_mesh.rs) | Plays an animation from a skinned glTF
|
||||
[Animated Mesh](../examples/animation/animated_mesh.rs) | Plays an animation on a skinned glTF model of a fox
|
||||
[Animated Mesh Control](../examples/animation/animated_mesh_control.rs) | Plays an animation from a skinned glTF with keyboard controls
|
||||
[Animated Mesh Events](../examples/animation/animated_mesh_events.rs) | Plays an animation from a skinned glTF with events
|
||||
[Animated Transform](../examples/animation/animated_transform.rs) | Create and play an animation defined by code that operates on the `Transform` component
|
||||
|
@ -1,10 +1,11 @@
|
||||
//! Plays animations from a skinned glTF.
|
||||
//! Plays an animation on a skinned glTF model of a fox.
|
||||
|
||||
use std::{f32::consts::PI, time::Duration};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use bevy::{pbr::CascadeShadowConfigBuilder, prelude::*};
|
||||
|
||||
const FOX_PATH: &str = "models/animated/Fox.glb";
|
||||
// An example asset that contains a mesh and animation.
|
||||
const GLTF_PATH: &str = "models/animated/Fox.glb";
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
@ -14,8 +15,9 @@ fn main() {
|
||||
..default()
|
||||
})
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, setup_scene_once_loaded)
|
||||
.add_systems(Startup, setup_mesh_and_animation)
|
||||
.add_systems(Startup, setup_camera_and_environment)
|
||||
.add_systems(Update, play_animation_once_loaded)
|
||||
.run();
|
||||
}
|
||||
|
||||
@ -25,27 +27,61 @@ struct Animations {
|
||||
index: AnimationNodeIndex,
|
||||
}
|
||||
|
||||
fn setup(
|
||||
// Create an animation graph and start loading the mesh and animation.
|
||||
fn setup_mesh_and_animation(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut graphs: ResMut<Assets<AnimationGraph>>,
|
||||
) {
|
||||
// Build the animation graph
|
||||
// Build an animation graph containing a single animation.
|
||||
let (graph, index) = AnimationGraph::from_clip(
|
||||
// We specifically want the "walk" animation, which is the first one.
|
||||
asset_server.load(GltfAssetLabel::Animation(0).from_asset(FOX_PATH)),
|
||||
// We want the "run" animation from our example asset, which has an
|
||||
// index of two.
|
||||
asset_server.load(GltfAssetLabel::Animation(2).from_asset(GLTF_PATH)),
|
||||
);
|
||||
|
||||
// Keep our animation graph in a Resource so that it can be inserted onto
|
||||
// the correct entity once the scene actually loads.
|
||||
// Keep our animation graph in a Resource so that it can be added to the
|
||||
// correct entity once the scene loads.
|
||||
let graph_handle = graphs.add(graph);
|
||||
commands.insert_resource(Animations {
|
||||
graph_handle: graph_handle.clone(),
|
||||
graph_handle,
|
||||
index,
|
||||
});
|
||||
|
||||
// Tell the engine to start loading our mesh and animation, and then spawn
|
||||
// them as a scene when ready.
|
||||
commands.spawn(SceneRoot(
|
||||
asset_server.load(GltfAssetLabel::Scene(0).from_asset(GLTF_PATH)),
|
||||
));
|
||||
}
|
||||
|
||||
// Detect that the scene is loaded and spawned, then play the animation.
|
||||
fn play_animation_once_loaded(
|
||||
mut commands: Commands,
|
||||
animations: Res<Animations>,
|
||||
mut players: Query<(Entity, &mut AnimationPlayer), Added<AnimationPlayer>>,
|
||||
) {
|
||||
for (entity, mut player) in &mut players {
|
||||
// Start the animation player and tell it to repeat forever.
|
||||
//
|
||||
// If you want to try stopping and switching animations, see the
|
||||
// `animated_mesh_control.rs` example.
|
||||
player.play(animations.index).repeat();
|
||||
|
||||
// Insert the animation graph with our selected animation. This
|
||||
// connects the animation player to the mesh.
|
||||
commands
|
||||
.entity(entity)
|
||||
.insert(AnimationGraphHandle(animations.graph_handle.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn a camera and a simple environment with a ground plane and light.
|
||||
fn setup_camera_and_environment(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
// Camera
|
||||
commands.spawn((
|
||||
Camera3d::default(),
|
||||
@ -72,34 +108,4 @@ fn setup(
|
||||
}
|
||||
.build(),
|
||||
));
|
||||
|
||||
// Fox
|
||||
commands.spawn((
|
||||
SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(FOX_PATH))),
|
||||
AnimationGraphHandle(graph_handle),
|
||||
));
|
||||
}
|
||||
|
||||
// Once the scene is loaded, start the animation
|
||||
fn setup_scene_once_loaded(
|
||||
mut commands: Commands,
|
||||
animations: Res<Animations>,
|
||||
mut players: Query<(Entity, &mut AnimationPlayer), Added<AnimationPlayer>>,
|
||||
) {
|
||||
for (entity, mut player) in &mut players {
|
||||
let mut transitions = AnimationTransitions::new();
|
||||
|
||||
// Make sure to start the animation via the `AnimationTransitions`
|
||||
// component. The `AnimationTransitions` component wants to manage all
|
||||
// the animations and will get confused if the animations are started
|
||||
// directly via the `AnimationPlayer`.
|
||||
transitions
|
||||
.play(&mut player, animations.index, Duration::ZERO)
|
||||
.repeat();
|
||||
|
||||
commands
|
||||
.entity(entity)
|
||||
.insert(transitions)
|
||||
.insert(AnimationGraphHandle(animations.graph_handle.clone()));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user