diff --git a/crates/bevy_gltf_blueprints/src/animation.rs b/crates/bevy_gltf_blueprints/src/animation.rs index d3c40a3..1257044 100644 --- a/crates/bevy_gltf_blueprints/src/animation.rs +++ b/crates/bevy_gltf_blueprints/src/animation.rs @@ -4,7 +4,7 @@ use bevy::utils::HashMap; #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] /// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations` -pub struct Animations { +pub struct BlueprintAnimations { pub named_animations: HashMap>, } @@ -13,10 +13,25 @@ pub struct Animations { /// so that the root entity knows which of its children contains an actualy `AnimationPlayer` component /// this is for convenience, because currently , Bevy's gltf parsing inserts `AnimationPlayers` "one level down" /// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid -pub struct AnimationPlayerLink(pub Entity); +pub struct BlueprintAnimationPlayerLink(pub Entity); #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] pub struct Animated{ pub animations: Vec -} \ No newline at end of file +} + + +#[derive(Component, Reflect, Default, Debug)] +#[reflect(Component)] +/// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations` +pub struct InstanceAnimations { + pub named_animations: HashMap>, +} + +#[derive(Component, Debug)] +/// Stop gap helper component : this is inserted into a "root" entity (an entity representing a whole gltf file) +/// so that the root entity knows which of its children contains an actualy `AnimationPlayer` component +/// this is for convenience, because currently , Bevy's gltf parsing inserts `AnimationPlayers` "one level down" +/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid +pub struct InstanceAnimationPlayerLink(pub Entity); \ No newline at end of file diff --git a/crates/bevy_gltf_blueprints/src/lib.rs b/crates/bevy_gltf_blueprints/src/lib.rs index 13f2d36..e18daf6 100644 --- a/crates/bevy_gltf_blueprints/src/lib.rs +++ b/crates/bevy_gltf_blueprints/src/lib.rs @@ -119,8 +119,11 @@ impl Plugin for BlueprintsPlugin { .register_type::() .register_type::() .register_type::() - .register_type::() + + .register_type::() + .register_type::() .register_type::() + .register_type::() .register_type::>() .register_type::>>() diff --git a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs index c91ea8a..8931444 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use bevy::{gltf::Gltf, prelude::*, utils::HashMap}; -use crate::{Animations, BluePrintsConfig}; +use crate::{BlueprintAnimations, BluePrintsConfig}; /// this is a flag component for our levels/game world #[derive(Component)] @@ -202,7 +202,6 @@ pub(crate) fn spawn_from_blueprints( Option<&Library>, Option<&AddToGameWorld>, Option<&Name>, - Option<&Animations> ), ( With, @@ -228,7 +227,6 @@ pub(crate) fn spawn_from_blueprints( library_override, add_to_world, name, - animations, ) in spawn_placeholders.iter() { debug!( @@ -283,15 +281,11 @@ pub(crate) fn spawn_from_blueprints( }, Spawned, OriginalChildren(original_children), - )); - - // only insert the animations if they are not present already: TODO ideally we want to be merging animations, though it could lead to clashes - if animations.is_none() { - commands.entity(entity).insert(Animations { + BlueprintAnimations { // these are animations specific to the inside of the blueprint named_animations: gltf.named_animations.clone(), - }); - } - + } + )); + if add_to_world.is_some() { let world = game_world .get_single_mut() diff --git a/crates/bevy_gltf_blueprints/src/spawn_post_process.rs b/crates/bevy_gltf_blueprints/src/spawn_post_process.rs index b53f4d7..0da0386 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_post_process.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_post_process.rs @@ -5,7 +5,7 @@ use bevy::prelude::*; use bevy::scene::SceneInstance; // use bevy::utils::hashbrown::HashSet; -use super::{AnimationPlayerLink, Animations}; +use super::{BlueprintAnimationPlayerLink, BlueprintAnimations}; use super::{SpawnHere, Spawned}; use crate::{ AssetsToLoad, BlueprintAssetsLoaded, CopyComponents, InBlueprint, NoInBlueprint, @@ -24,7 +24,7 @@ pub(crate) fn spawned_blueprint_post_process( Entity, &Children, &OriginalChildren, - &Animations, + &BlueprintAnimations, Option<&NoInBlueprint>, Option<&Name>, ), @@ -85,7 +85,7 @@ pub(crate) fn spawned_blueprint_post_process( // FIXME: stopgap solution: since we cannot use an AnimationPlayer at the root entity level // and we cannot update animation clips so that the EntityPaths point to one level deeper, // BUT we still want to have some marker/control at the root entity level, we add this - commands.entity(original).insert(AnimationPlayerLink(added)); + commands.entity(original).insert(BlueprintAnimationPlayerLink(added)); } } } diff --git a/testing/bevy_example/assets/registry.json b/testing/bevy_example/assets/registry.json index 29b8dc0..2cdc5bb 100644 --- a/testing/bevy_example/assets/registry.json +++ b/testing/bevy_example/assets/registry.json @@ -2969,6 +2969,17 @@ "type": "object", "typeInfo": "Struct" }, + "bevy_example::game::Marker3": { + "additionalProperties": false, + "isComponent": true, + "isResource": false, + "properties": {}, + "required": [], + "short_name": "Marker3", + "title": "bevy_example::game::Marker3", + "type": "object", + "typeInfo": "Struct" + }, "bevy_example::test_components::AComponentWithAnExtremlyExageratedOrMaybeNotButCouldBeNameOrWut": { "additionalProperties": false, "isComponent": true, @@ -3557,7 +3568,7 @@ "type": "object", "typeInfo": "Struct" }, - "bevy_gltf_blueprints::animation::Animations": { + "bevy_gltf_blueprints::animation::BlueprintAnimations": { "additionalProperties": false, "isComponent": true, "isResource": false, @@ -3571,8 +3582,27 @@ "required": [ "named_animations" ], - "short_name": "Animations", - "title": "bevy_gltf_blueprints::animation::Animations", + "short_name": "BlueprintAnimations", + "title": "bevy_gltf_blueprints::animation::BlueprintAnimations", + "type": "object", + "typeInfo": "Struct" + }, + "bevy_gltf_blueprints::animation::InstanceAnimations": { + "additionalProperties": false, + "isComponent": true, + "isResource": false, + "properties": { + "named_animations": { + "type": { + "$ref": "#/$defs/bevy_utils::hashbrown::HashMap, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>" + } + } + }, + "required": [ + "named_animations" + ], + "short_name": "InstanceAnimations", + "title": "bevy_gltf_blueprints::animation::InstanceAnimations", "type": "object", "typeInfo": "Struct" }, diff --git a/testing/bevy_example/assets/testing.blend b/testing/bevy_example/assets/testing.blend index 7d8adcd..8aa6884 100644 Binary files a/testing/bevy_example/assets/testing.blend and b/testing/bevy_example/assets/testing.blend differ diff --git a/testing/bevy_example/src/game/mod.rs b/testing/bevy_example/src/game/mod.rs index a7eaf22..00187ad 100644 --- a/testing/bevy_example/src/game/mod.rs +++ b/testing/bevy_example/src/game/mod.rs @@ -3,7 +3,7 @@ use std::{ collections::HashMap, fs, time::Duration }; -use bevy_gltf_blueprints::{Animated, AnimationPlayerLink, Animations, BlueprintName, BlueprintsList, GltfBlueprintsSet}; +use bevy_gltf_blueprints::{Animated, BlueprintAnimationPlayerLink, BlueprintAnimations, InstanceAnimationPlayerLink, InstanceAnimations, BlueprintName, BlueprintsList, GltfBlueprintsSet}; pub use in_game::*; use bevy::{ @@ -29,7 +29,7 @@ fn validate_export( children: Query<&Children>, names: Query<&Name>, blueprints: Query<(Entity, &Name, &BlueprintName)>, - animation_player_links: Query<(Entity, &AnimationPlayerLink)>, + animation_player_links: Query<(Entity, &BlueprintAnimationPlayerLink)>, empties_candidates: Query<(Entity, &Name, &GlobalTransform)>, blueprints_list: Query<(Entity, &BlueprintsList)>, @@ -141,7 +141,7 @@ fn setup_main_scene_animations( fn animations( added_animation_players:Query<(Entity, &Name, &AnimationPlayer)>, - mut addded_animateds:Query<(Entity, &Name, &Animated),(Added, Without)>, + addded_animateds:Query<(Entity, &Name, &Animated),(Added)>, animtest: Res, @@ -171,7 +171,7 @@ fn animations( // FIXME: for some reason this does NOT overwrite the component ?? commands.entity(entity).insert( - Animations { + InstanceAnimations { named_animations: gltf.named_animations.clone(), }, ); @@ -183,7 +183,7 @@ fn animations( for ancestor in parents.iter_ancestors(entity) { if added_animation_players.contains(ancestor) { println!("found match with animationPlayer !! {:?}",names.get(ancestor)); - commands.entity(entity).insert(AnimationPlayerLink(ancestor)); + commands.entity(entity).insert(InstanceAnimationPlayerLink(ancestor)); } // info!("{:?} is an ancestor of {:?}", ancestor, player); } @@ -192,8 +192,9 @@ fn animations( } fn play_animations( - animated_marker1: Query<(&AnimationPlayerLink, &Animations), (With, With)>, - animated_marker2: Query<(&AnimationPlayerLink, &Animations), (With, With)>, + animated_marker1: Query<(&InstanceAnimationPlayerLink, &InstanceAnimations), (With, With)>, + animated_marker2: Query<(&InstanceAnimationPlayerLink, &InstanceAnimations), (With, With)>, + animated_marker3: Query<(&InstanceAnimationPlayerLink, &InstanceAnimations, &BlueprintAnimationPlayerLink, &BlueprintAnimations), (With, With)>, mut animation_players: Query<&mut AnimationPlayer>, keycode: Res>, @@ -268,6 +269,43 @@ fn play_animations( .repeat(); } } + + // play instance animation + if keycode.just_pressed(KeyCode::KeyW) { + for (link, animations, _, _) in animated_marker3.iter() { + println!("animations {:?}", animations.named_animations); + let mut animation_player = animation_players.get_mut(link.0).unwrap(); + let anim_name = "Blueprint8_move"; + animation_player + .play_with_transition( + animations + .named_animations + .get(anim_name) + .expect("animation name should be in the list") + .clone(), + Duration::from_secs(5), + ) + .repeat(); + } + } + // play blueprint animation + if keycode.just_pressed(KeyCode::KeyX) { + for (_, _, link, animations) in animated_marker3.iter() { + println!("animations {:?}", animations.named_animations); + let mut animation_player = animation_players.get_mut(link.0).unwrap(); + let anim_name = "Walk"; + animation_player + .play_with_transition( + animations + .named_animations + .get(anim_name) + .expect("animation name should be in the list") + .clone(), + Duration::from_secs(5), + ) + .repeat(); + } + } } #[derive(Component, Reflect, Default, Debug)] @@ -280,11 +318,18 @@ pub struct Marker1; /// flag component for testing pub struct Marker2; +#[derive(Component, Reflect, Default, Debug)] +#[reflect(Component)] +/// flag component for testing +pub struct Marker3; + pub struct GamePlugin; impl Plugin for GamePlugin { fn build(&self, app: &mut App) { app.register_type::() .register_type::() + .register_type::() + .add_systems(Update, (spawn_test).run_if(in_state(GameState::InGame))) .add_systems(Update, validate_export) .add_systems(OnEnter(AppState::MenuRunning), start_game)