diff --git a/crates/bevy_gltf_blueprints/src/animation.rs b/crates/bevy_gltf_blueprints/src/animation.rs index 0b3b96d..6473818 100644 --- a/crates/bevy_gltf_blueprints/src/animation.rs +++ b/crates/bevy_gltf_blueprints/src/animation.rs @@ -48,7 +48,7 @@ pub struct AnimationInfos { pub animations: Vec, } -#[derive( Reflect, Default, Debug)] +#[derive(Reflect, Default, Debug)] pub struct AnimationMarker { // pub frame: u32, pub name: String, @@ -71,7 +71,6 @@ pub struct AnimationMarkerReached { pub marker_name: String, } - ///////////////////// /// triggers events when a given animation marker is reached for INSTANCE animations @@ -129,7 +128,6 @@ pub fn trigger_instance_animation_markers_events( // emit an event AnimationMarkerReached(entity, animation_name, frame, marker_name) // FIXME: problem, this can fire multiple times in a row, depending on animation length , speed , etc for marker in matching_markers_per_frame { - animation_marker_events.send(AnimationMarkerReached { entity: entity, animation_name: animation_name.clone(), @@ -145,11 +143,7 @@ pub fn trigger_instance_animation_markers_events( /// triggers events when a given animation marker is reached for BLUEPRINT animations pub fn trigger_blueprint_animation_markers_events( - animation_infos: Query<( - Entity, - &BlueprintAnimationPlayerLink, - &BlueprintAnimations, - )>, + animation_infos: Query<(Entity, &BlueprintAnimationPlayerLink, &BlueprintAnimations)>, // FIXME: annoying hiearchy issue yet again: the Markers & AnimationInfos are stored INSIDE the blueprint, so we need to access them differently all_animation_infos: Query<(Entity, &AnimationMarkers, &AnimationInfos, &Parent)>, animation_players: Query<&AnimationPlayer>, @@ -161,20 +155,20 @@ pub fn trigger_blueprint_animation_markers_events( let animation_clip = animation_clips.get(animation_player.animation_clip()); // FIXME: horrible code - for (_, markers, animation_infos, parent) in all_animation_infos.iter(){ + for (_, markers, animation_infos, parent) in all_animation_infos.iter() { if parent.get() == entity { if animation_clip.is_some() { - // println!("Entity {:?} markers {:?}", entity, markers); // println!("Player {:?} {}", animation_player.elapsed(), animation_player.completions()); // FIMXE: yikes ! very inneficient ! perhaps add boilerplate to the "start playing animation" code so we know what is playing - let animation_name = animations.named_animations.iter().find_map(|(key, value)| { - if value == animation_player.animation_clip() { - Some(key) - } else { - None - } - }); + let animation_name = + animations.named_animations.iter().find_map(|(key, value)| { + if value == animation_player.animation_clip() { + Some(key) + } else { + None + } + }); if animation_name.is_some() { let animation_name = animation_name.unwrap(); let animation_length_seconds = animation_clip.unwrap().duration(); @@ -187,23 +181,23 @@ pub fn trigger_blueprint_animation_markers_events( // TODO: we also need to take playback speed into account let time_in_animation = animation_player.elapsed() - (animation_player.completions() as f32) * animation_length_seconds; - let frame_seconds = - (animation_length_frames / animation_length_seconds) * time_in_animation; + let frame_seconds = (animation_length_frames / animation_length_seconds) + * time_in_animation; // println!("frame seconds {}", frame_seconds); let frame = frame_seconds.ceil() as u32; // FIXME , bad hack - + let matching_animation_marker = &markers.0[animation_name]; - - + if matching_animation_marker.contains_key(&frame) { - let matching_markers_per_frame = matching_animation_marker.get(&frame).unwrap(); + let matching_markers_per_frame = + matching_animation_marker.get(&frame).unwrap(); // println!("FOUND A MARKER {:?} at frame {}", matching_markers_per_frame, frame); // emit an event AnimationMarkerReached(entity, animation_name, frame, marker_name) // FIXME: complete hack-ish solution , otherwise this can fire multiple times in a row, depending on animation length , speed , etc let diff = frame as f32 - frame_seconds; - if diff < 0.03 { + println!("diff {}", diff); + if diff < 0.1 { for marker in matching_markers_per_frame { - animation_marker_events.send(AnimationMarkerReached { entity: entity, animation_name: animation_name.clone(), @@ -212,16 +206,12 @@ pub fn trigger_blueprint_animation_markers_events( }); } } - } } - } - - + } break; } } - } -} \ 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 a1be51b..5960664 100644 --- a/crates/bevy_gltf_blueprints/src/lib.rs +++ b/crates/bevy_gltf_blueprints/src/lib.rs @@ -119,7 +119,6 @@ impl Plugin for BlueprintsPlugin { .register_type::() .register_type::() .register_type::() - .register_type::() .register_type::() .register_type::() @@ -128,9 +127,7 @@ impl Plugin for BlueprintsPlugin { .register_type::() .register_type::>>() .register_type::>>>() - .add_event::() - .register_type::() .register_type::>>() .insert_resource(BluePrintsConfig { @@ -181,10 +178,12 @@ impl Plugin for BlueprintsPlugin { .chain() .in_set(GltfBlueprintsSet::AfterSpawn), ) - - - .add_systems(Update, (trigger_instance_animation_markers_events, trigger_blueprint_animation_markers_events)) - - ; + .add_systems( + Update, + ( + trigger_instance_animation_markers_events, + trigger_blueprint_animation_markers_events, + ), + ); } } diff --git a/testing/bevy_example/expected_screenshot.png b/testing/bevy_example/expected_screenshot.png deleted file mode 100644 index 43569fc..0000000 Binary files a/testing/bevy_example/expected_screenshot.png and /dev/null differ diff --git a/testing/bevy_example/src/game/animation.rs b/testing/bevy_example/src/game/animation.rs index 2fbfb9a..e6aae9e 100644 --- a/testing/bevy_example/src/game/animation.rs +++ b/testing/bevy_example/src/game/animation.rs @@ -1,8 +1,7 @@ use std::time::Duration; use bevy_gltf_blueprints::{ - AnimationInfos, AnimationMarkerReached, - BlueprintAnimationPlayerLink, BlueprintAnimations, + AnimationInfos, AnimationMarkerReached, BlueprintAnimationPlayerLink, BlueprintAnimations, InstanceAnimationPlayerLink, InstanceAnimations, }; @@ -37,7 +36,7 @@ pub fn setup_main_scene_animations(asset_server: Res, mut commands: pub fn animations( added_animation_players: Query<(Entity, &Name, &AnimationPlayer)>, - added_animation_infos: Query<(Entity, &Name, &AnimationInfos), (Added)>, + added_animation_infos: Query<(Entity, &Name, &AnimationInfos), Added>, animtest: Res, mut commands: Commands, assets_gltf: Res>, @@ -95,10 +94,7 @@ pub fn play_animations( (With, With), >, - animated_fox: Query< - (&BlueprintAnimationPlayerLink, &BlueprintAnimations), - (With), - >, + animated_fox: Query<(&BlueprintAnimationPlayerLink, &BlueprintAnimations), With>, mut animation_players: Query<&mut AnimationPlayer>, keycode: Res>, @@ -229,7 +225,6 @@ pub fn play_animations( } } - pub fn react_to_animation_markers( mut animation_marker_events: EventReader, ) { diff --git a/testing/bevy_example/src/game/mod.rs b/testing/bevy_example/src/game/mod.rs index 82c78c8..c953270 100644 --- a/testing/bevy_example/src/game/mod.rs +++ b/testing/bevy_example/src/game/mod.rs @@ -6,17 +6,15 @@ pub use in_game::*; use std::{collections::HashMap, fs, time::Duration}; use bevy_gltf_blueprints::{ - BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintName, BlueprintsList, - GltfBlueprintsSet, InstanceAnimationPlayerLink, InstanceAnimations, + BlueprintAnimationPlayerLink, BlueprintName, BlueprintsList, + GltfBlueprintsSet, }; use bevy::{ - ecs::query, gltf::Gltf, prelude::*, render::view::screenshot::ScreenshotManager, - time::common_conditions::on_timer, window::PrimaryWindow, + prelude::*, render::view::screenshot::ScreenshotManager, time::common_conditions::on_timer, window::PrimaryWindow }; use bevy_gltf_worlflow_examples_common_rapier::{AppState, GameState}; -use crate::{TupleTestF32, UnitTest}; use json_writer::to_json_string; fn start_game(mut next_app_state: ResMut>) { @@ -144,11 +142,11 @@ impl Plugin for GamePlugin { .add_systems(Update, play_animations) .add_systems(Update, react_to_animation_markers) - /* .add_systems(Update, generate_screenshot.run_if(on_timer(Duration::from_secs_f32(0.2)))) // TODO: run once + .add_systems(Update, generate_screenshot.run_if(on_timer(Duration::from_secs_f32(0.2)))) // TODO: run once .add_systems( Update, exit_game.run_if(on_timer(Duration::from_secs_f32(0.5))), - ) // shut down the app after this time*/ + ) // shut down the app after this time ; } } diff --git a/tools/gltf_auto_export/tests/expected_bevy_hierarchy.json b/tools/gltf_auto_export/tests/expected_bevy_hierarchy.json index 8a1165b..040c997 100644 --- a/tools/gltf_auto_export/tests/expected_bevy_hierarchy.json +++ b/tools/gltf_auto_export/tests/expected_bevy_hierarchy.json @@ -1 +1 @@ -{"b_Tail02_013":["b_Tail03_014"],"Blueprint4_nested.001":["Blueprint3"],"Collection 2 1":["Empty_in_sub_collection"],"b_Root_00":["b_Hip_01"],"b_LeftForeArm_010":["b_LeftHand_011"],"b_Spine01_02":["b_Spine02_03"],"Blueprint7_hierarchy.001":["Blueprint4_nested.001","Cube.001"],"b_RightLeg01_019":["b_RightLeg02_020"],"b_LeftUpperArm_09":["b_LeftForeArm_010"],"no_name":["Parent_Object","lighting_components_World","assets_list_World_components","Collection","Collection 2"],"Blueprint3":["Blueprint3_mesh","Blueprint3_mesh"],"world":["no_name"],"Parent_Object":["Cube.003","Blueprint1","Cylinder.001"],"Light":["Light","DirectionalLight Gizmo"],"Blueprint1.001":["Blueprint1_mesh"],"Blueprint7_hierarchy":["Cube.001"],"Spot":["Spot"],"b_Hip_01":["b_Spine01_02","b_Tail01_012","b_LeftLeg01_015","b_RightLeg01_019"],"Cylinder":["Cylinder.001","Cylinder.001"],"Collection 2":["Collection 2 1","Empty_in_collection","Spot"],"b_RightForeArm_07":["b_RightHand_08"],"Blueprint3_mesh":["Cylinder","Cylinder"],"Blueprint4_nested":["Blueprint3"],"Fox_mesh":["fox1"],"b_LeftLeg01_015":["b_LeftLeg02_016"],"b_Neck_04":["b_Head_05"],"b_RightFoot01_021":["b_RightFoot02_022"],"Blueprint1_mesh":["Cube.001","Cube.001"],"b_Tail01_012":["b_Tail02_013"],"Fox":["Fox_mesh","_rootJoint"],"Collection":["Blueprint1.001","Blueprint4_nested","Blueprint6_animated","Blueprint7_hierarchy","Camera","Cube","Empty","Light","Plane"],"Cube":["Cube"],"_rootJoint":["b_Root_00"],"b_RightLeg02_020":["b_RightFoot01_021"],"b_RightUpperArm_06":["b_RightForeArm_07"],"Plane":["Plane"],"Camera":["Camera Gizmo"],"Blueprint6_animated":["Fox"],"b_Spine02_03":["b_Neck_04","b_RightUpperArm_06","b_LeftUpperArm_09"],"b_LeftLeg02_016":["b_LeftFoot01_017"],"b_LeftFoot01_017":["b_LeftFoot02_018"],"Cube.001":["Cube.002","Cylinder","Cube.002","Cylinder"],"Cylinder.001":["Cylinder.002","Blueprint7_hierarchy.001","Empty_as_child"],"Blueprint1":["Blueprint1_mesh"]} \ No newline at end of file +{"Blueprint6_animated":["Fox"],"Collection 2 1":["Empty_in_sub_collection"],"Blueprint1.001":["Blueprint1_mesh"],"Blueprint3":["Blueprint3_mesh","Blueprint3_mesh"],"b_Spine02_03":["b_Neck_04","b_RightUpperArm_06","b_LeftUpperArm_09","b_Neck_04","b_RightUpperArm_06","b_LeftUpperArm_09"],"_rootJoint":["b_Root_00","b_Root_00"],"Cube.001":["Cube.002","Cylinder","Cube.002","Cylinder"],"b_Root_00":["b_Hip_01","b_Hip_01"],"Collection 2":["Blueprint8_animated_no_bones","Collection 2 1","Empty_in_collection","Spot"],"Blueprint6_animated.001":["Fox"],"Collection":["Blueprint1.001","Blueprint4_nested","Blueprint6_animated","Blueprint7_hierarchy","Camera","Cube","Empty","Light","Plane"],"Camera":["Camera Gizmo"],"Blueprint7_hierarchy.001":["Blueprint4_nested.001","Cube.001"],"b_Spine01_02":["b_Spine02_03","b_Spine02_03"],"Light":["Light","DirectionalLight Gizmo"],"Cylinder":["Cylinder.001","Cylinder.001"],"b_Tail01_012":["b_Tail02_013","b_Tail02_013"],"b_RightLeg01_019":["b_RightLeg02_020","b_RightLeg02_020"],"b_LeftFoot01_017":["b_LeftFoot02_018","b_LeftFoot02_018"],"Cube":["Cube"],"b_Hip_01":["b_Spine01_02","b_Tail01_012","b_LeftLeg01_015","b_RightLeg01_019","b_Spine01_02","b_Tail01_012","b_LeftLeg01_015","b_RightLeg01_019"],"b_LeftForeArm_010":["b_LeftHand_011","b_LeftHand_011"],"Fox":["Fox_mesh","_rootJoint","Fox_mesh","_rootJoint"],"Blueprint8_animated_no_bones":["Cylinder.002"],"Parent_Object":["Cube.003","Blueprint1","Cylinder.001"],"b_RightUpperArm_06":["b_RightForeArm_07","b_RightForeArm_07"],"world":["no_name"],"b_LeftLeg01_015":["b_LeftLeg02_016","b_LeftLeg02_016"],"Spot":["Spot"],"b_RightFoot01_021":["b_RightFoot02_022","b_RightFoot02_022"],"Blueprint7_hierarchy":["Cube.001"],"b_RightLeg02_020":["b_RightFoot01_021","b_RightFoot01_021"],"Blueprint4_nested":["Blueprint3"],"Fox_mesh":["fox1","fox1"],"b_RightForeArm_07":["b_RightHand_08","b_RightHand_08"],"Blueprint3_mesh":["Cylinder","Cylinder"],"Blueprint1_mesh":["Cube.001","Cube.001"],"b_Neck_04":["b_Head_05","b_Head_05"],"b_LeftUpperArm_09":["b_LeftForeArm_010","b_LeftForeArm_010"],"no_name":["Parent_Object","Blueprint6_animated.001","lighting_components_World","assets_list_World_components","Collection","Collection 2"],"Cylinder.002":["Cylinder.003"],"Blueprint4_nested.001":["Blueprint3"],"Blueprint1":["Blueprint1_mesh"],"Cylinder.001":["Cylinder.002","Blueprint7_hierarchy.001","Empty_as_child"],"b_Tail02_013":["b_Tail03_014","b_Tail03_014"],"b_LeftLeg02_016":["b_LeftFoot01_017","b_LeftFoot01_017"],"Plane":["Plane"]} \ No newline at end of file diff --git a/tools/gltf_auto_export/tests/expected_screenshot.png b/tools/gltf_auto_export/tests/expected_screenshot.png new file mode 100644 index 0000000..50f10c6 Binary files /dev/null and b/tools/gltf_auto_export/tests/expected_screenshot.png differ diff --git a/tools/gltf_auto_export/tests/test_bevy_integration.py b/tools/gltf_auto_export/tests/test_bevy_integration.py index 76da5ea..a7ca08c 100644 --- a/tools/gltf_auto_export/tests/test_bevy_integration.py +++ b/tools/gltf_auto_export/tests/test_bevy_integration.py @@ -134,7 +134,7 @@ def test_export_complex(setup_data): assert sorted(hierarchy.items()) == sorted(expected.items()) # last but not least, do a visual compare - screenshot_expected_path = os.path.join(root_path, "expected_screenshot.png") + screenshot_expected_path = os.path.join(os.path.dirname(__file__), "expected_screenshot.png") screenshot_observed_path = os.path.join(root_path, "screenshot.png") img_a = Image.open(screenshot_expected_path) img_b = Image.open(screenshot_observed_path)