mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-23 12:20:53 +00:00
Compare commits
No commits in common. "49dd0bc536e3201ede4665fbae9b3c64159e4b6f" and "c44d82e7dc04f1e86159f7b5cb7ca201305d737c" have entirely different histories.
49dd0bc536
...
c44d82e7dc
@ -3,7 +3,7 @@ use bevy::utils::HashMap;
|
|||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
/// storage for animations for a given entity's BLUEPRINT (ie for example a characters animations), essentially a clone of gltf's `named_animations`
|
/// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations`
|
||||||
pub struct BlueprintAnimations {
|
pub struct BlueprintAnimations {
|
||||||
pub named_animations: HashMap<String, Handle<AnimationClip>>,
|
pub named_animations: HashMap<String, Handle<AnimationClip>>,
|
||||||
}
|
}
|
||||||
@ -15,6 +15,13 @@ pub struct BlueprintAnimations {
|
|||||||
/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid
|
/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid
|
||||||
pub struct BlueprintAnimationPlayerLink(pub Entity);
|
pub struct BlueprintAnimationPlayerLink(pub Entity);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct Animated{
|
||||||
|
pub animations: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
/// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations`
|
/// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations`
|
||||||
@ -29,54 +36,12 @@ pub struct InstanceAnimations {
|
|||||||
/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid
|
/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid
|
||||||
pub struct InstanceAnimationPlayerLink(pub Entity);
|
pub struct InstanceAnimationPlayerLink(pub Entity);
|
||||||
|
|
||||||
/// Stores Animation information: name, frame informations etc
|
|
||||||
#[derive(Reflect, Default, Debug)]
|
|
||||||
pub struct AnimationInfo {
|
|
||||||
pub name: String,
|
|
||||||
pub frame_start: f32,
|
|
||||||
pub frame_end: f32,
|
|
||||||
pub frames_length: f32,
|
|
||||||
pub frame_start_override: f32,
|
|
||||||
pub frame_end_override: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stores information about animations, to make things a bit easier api wise:
|
pub struct AnimationMarker{
|
||||||
/// these components are automatically inserted by gltf_auto_export on entities that have animations
|
pub frame:u32,
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
pub struct AnimationInfos {
|
|
||||||
pub animations: Vec<AnimationInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AnimationMarker {
|
|
||||||
pub frame: u32,
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores information about animation markers: practical for adding things like triggering events at specific keyframes etc
|
|
||||||
/// it is essentiall a hashmap of AnimationName => HashMap<FrameNumber, Vec of marker names>
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct AnimationMarkers(pub HashMap<String, HashMap<u32, Vec<String>>>);
|
pub struct AnimationMarkers(pub HashMap<String, HashMap<u32, Vec<String> >>);
|
||||||
|
|
||||||
// FIXME: ugh, ugly, there has to be a better way to do this ?
|
|
||||||
#[derive(Component, Default, Debug)]
|
|
||||||
pub struct AnimationMarkerTrackers(pub HashMap<String, HashMap<u32, Vec<AnimationMarkerTracker>>>);
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
pub struct AnimationMarkerTracker {
|
|
||||||
// pub frame:u32,
|
|
||||||
// pub name: String,
|
|
||||||
// pub processed_for_cycle: bool,
|
|
||||||
pub prev_frame: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Event that gets triggered once a specific marker inside an animation has been reached (frame based)
|
|
||||||
/// Provides some usefull information about which entity , wich animation, wich frame & which marker got triggered
|
|
||||||
#[derive(Event, Debug)]
|
|
||||||
pub struct AnimationMarkerReached {
|
|
||||||
pub entity: Entity,
|
|
||||||
pub animation_name: String,
|
|
||||||
pub frame: u32,
|
|
||||||
pub marker_name: String,
|
|
||||||
}
|
|
@ -119,16 +119,17 @@ impl Plugin for BlueprintsPlugin {
|
|||||||
.register_type::<BlueprintName>()
|
.register_type::<BlueprintName>()
|
||||||
.register_type::<MaterialInfo>()
|
.register_type::<MaterialInfo>()
|
||||||
.register_type::<SpawnHere>()
|
.register_type::<SpawnHere>()
|
||||||
|
|
||||||
.register_type::<BlueprintAnimations>()
|
.register_type::<BlueprintAnimations>()
|
||||||
.register_type::<InstanceAnimations>()
|
.register_type::<InstanceAnimations>()
|
||||||
.register_type::<AnimationInfo>()
|
.register_type::<Animated>()
|
||||||
.register_type::<AnimationInfos>()
|
|
||||||
.register_type::<Vec<AnimationInfo>>()
|
|
||||||
.register_type::<AnimationMarkers>()
|
.register_type::<AnimationMarkers>()
|
||||||
.register_type::<HashMap<u32, Vec<String>>>()
|
.register_type::<HashMap<u32, Vec<String>>>()
|
||||||
.register_type::<HashMap<String, HashMap<u32, Vec<String>>>>()
|
.register_type::<HashMap<String, HashMap<u32, Vec<String> >>>()
|
||||||
.add_event::<AnimationMarkerReached>()
|
|
||||||
|
|
||||||
.register_type::<BlueprintsList>()
|
.register_type::<BlueprintsList>()
|
||||||
|
.register_type::<Vec<String>>()
|
||||||
.register_type::<HashMap<String, Vec<String>>>()
|
.register_type::<HashMap<String, Vec<String>>>()
|
||||||
.insert_resource(BluePrintsConfig {
|
.insert_resource(BluePrintsConfig {
|
||||||
format: self.format,
|
format: self.format,
|
||||||
|
@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use bevy::{gltf::Gltf, prelude::*, utils::HashMap};
|
use bevy::{gltf::Gltf, prelude::*, utils::HashMap};
|
||||||
|
|
||||||
use crate::{BluePrintsConfig, BlueprintAnimations};
|
use crate::{BlueprintAnimations, BluePrintsConfig};
|
||||||
|
|
||||||
/// this is a flag component for our levels/game world
|
/// this is a flag component for our levels/game world
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
@ -281,10 +281,9 @@ pub(crate) fn spawn_from_blueprints(
|
|||||||
},
|
},
|
||||||
Spawned,
|
Spawned,
|
||||||
OriginalChildren(original_children),
|
OriginalChildren(original_children),
|
||||||
BlueprintAnimations {
|
BlueprintAnimations { // these are animations specific to the inside of the blueprint
|
||||||
// these are animations specific to the inside of the blueprint
|
|
||||||
named_animations: gltf.named_animations.clone(),
|
named_animations: gltf.named_animations.clone(),
|
||||||
},
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
if add_to_world.is_some() {
|
if add_to_world.is_some() {
|
||||||
|
@ -85,9 +85,7 @@ pub(crate) fn spawned_blueprint_post_process(
|
|||||||
// FIXME: stopgap solution: since we cannot use an AnimationPlayer at the root entity level
|
// 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,
|
// 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
|
// BUT we still want to have some marker/control at the root entity level, we add this
|
||||||
commands
|
commands.entity(original).insert(BlueprintAnimationPlayerLink(added));
|
||||||
.entity(original)
|
|
||||||
.insert(BlueprintAnimationPlayerLink(added));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,19 +110,6 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"typeInfo": "List"
|
"typeInfo": "List"
|
||||||
},
|
},
|
||||||
"alloc::vec::Vec<bevy_gltf_blueprints::animation::AnimationInfo>": {
|
|
||||||
"isComponent": false,
|
|
||||||
"isResource": false,
|
|
||||||
"items": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/bevy_gltf_blueprints::animation::AnimationInfo"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"short_name": "Vec<AnimationInfo>",
|
|
||||||
"title": "alloc::vec::Vec<bevy_gltf_blueprints::animation::AnimationInfo>",
|
|
||||||
"type": "array",
|
|
||||||
"typeInfo": "List"
|
|
||||||
},
|
|
||||||
"alloc::vec::Vec<bevy_render::color::Color>": {
|
"alloc::vec::Vec<bevy_render::color::Color>": {
|
||||||
"isComponent": false,
|
"isComponent": false,
|
||||||
"isResource": false,
|
"isResource": false,
|
||||||
@ -2960,36 +2947,36 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
"bevy_example::game::animation::Marker1": {
|
"bevy_example::game::Marker1": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"isComponent": true,
|
"isComponent": true,
|
||||||
"isResource": false,
|
"isResource": false,
|
||||||
"properties": {},
|
"properties": {},
|
||||||
"required": [],
|
"required": [],
|
||||||
"short_name": "Marker1",
|
"short_name": "Marker1",
|
||||||
"title": "bevy_example::game::animation::Marker1",
|
"title": "bevy_example::game::Marker1",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
"bevy_example::game::animation::Marker2": {
|
"bevy_example::game::Marker2": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"isComponent": true,
|
"isComponent": true,
|
||||||
"isResource": false,
|
"isResource": false,
|
||||||
"properties": {},
|
"properties": {},
|
||||||
"required": [],
|
"required": [],
|
||||||
"short_name": "Marker2",
|
"short_name": "Marker2",
|
||||||
"title": "bevy_example::game::animation::Marker2",
|
"title": "bevy_example::game::Marker2",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
"bevy_example::game::animation::Marker3": {
|
"bevy_example::game::Marker3": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"isComponent": true,
|
"isComponent": true,
|
||||||
"isResource": false,
|
"isResource": false,
|
||||||
"properties": {},
|
"properties": {},
|
||||||
"required": [],
|
"required": [],
|
||||||
"short_name": "Marker3",
|
"short_name": "Marker3",
|
||||||
"title": "bevy_example::game::animation::Marker3",
|
"title": "bevy_example::game::Marker3",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
@ -3562,90 +3549,25 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
"bevy_gltf_blueprints::animation::AnimationInfo": {
|
"bevy_gltf_blueprints::animation::Animated": {
|
||||||
"additionalProperties": false,
|
|
||||||
"isComponent": false,
|
|
||||||
"isResource": false,
|
|
||||||
"properties": {
|
|
||||||
"frame_end": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/f32"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"frame_end_override": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/f32"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"frame_start": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/f32"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"frame_start_override": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/f32"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"frames_length": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/f32"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/alloc::string::String"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"frame_start",
|
|
||||||
"frame_end",
|
|
||||||
"frames_length",
|
|
||||||
"frame_start_override",
|
|
||||||
"frame_end_override"
|
|
||||||
],
|
|
||||||
"short_name": "AnimationInfo",
|
|
||||||
"title": "bevy_gltf_blueprints::animation::AnimationInfo",
|
|
||||||
"type": "object",
|
|
||||||
"typeInfo": "Struct"
|
|
||||||
},
|
|
||||||
"bevy_gltf_blueprints::animation::AnimationInfos": {
|
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"isComponent": true,
|
"isComponent": true,
|
||||||
"isResource": false,
|
"isResource": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"animations": {
|
"animations": {
|
||||||
"type": {
|
"type": {
|
||||||
"$ref": "#/$defs/alloc::vec::Vec<bevy_gltf_blueprints::animation::AnimationInfo>"
|
"$ref": "#/$defs/alloc::vec::Vec<alloc::string::String>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"animations"
|
"animations"
|
||||||
],
|
],
|
||||||
"short_name": "AnimationInfos",
|
"short_name": "Animated",
|
||||||
"title": "bevy_gltf_blueprints::animation::AnimationInfos",
|
"title": "bevy_gltf_blueprints::animation::Animated",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
"bevy_gltf_blueprints::animation::AnimationMarkers": {
|
|
||||||
"isComponent": true,
|
|
||||||
"isResource": false,
|
|
||||||
"items": false,
|
|
||||||
"prefixItems": [
|
|
||||||
{
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/bevy_utils::hashbrown::HashMap<alloc::string::String, bevy_utils::hashbrown::HashMap<u32, alloc::vec::Vec<alloc::string::String>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"short_name": "AnimationMarkers",
|
|
||||||
"title": "bevy_gltf_blueprints::animation::AnimationMarkers",
|
|
||||||
"type": "array",
|
|
||||||
"typeInfo": "TupleStruct"
|
|
||||||
},
|
|
||||||
"bevy_gltf_blueprints::animation::BlueprintAnimations": {
|
"bevy_gltf_blueprints::animation::BlueprintAnimations": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"isComponent": true,
|
"isComponent": true,
|
||||||
@ -11012,32 +10934,6 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Map"
|
"typeInfo": "Map"
|
||||||
},
|
},
|
||||||
"bevy_utils::hashbrown::HashMap<alloc::string::String, bevy_utils::hashbrown::HashMap<u32, alloc::vec::Vec<alloc::string::String>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/bevy_utils::hashbrown::HashMap<u32, alloc::vec::Vec<alloc::string::String>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"isComponent": false,
|
|
||||||
"isResource": false,
|
|
||||||
"short_name": "HashMap<String, HashMap<u32, Vec<String>, DefaultHashBuilder>, DefaultHashBuilder>",
|
|
||||||
"title": "bevy_utils::hashbrown::HashMap<alloc::string::String, bevy_utils::hashbrown::HashMap<u32, alloc::vec::Vec<alloc::string::String>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>",
|
|
||||||
"type": "object",
|
|
||||||
"typeInfo": "Map"
|
|
||||||
},
|
|
||||||
"bevy_utils::hashbrown::HashMap<u32, alloc::vec::Vec<alloc::string::String>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": {
|
|
||||||
"$ref": "#/$defs/alloc::vec::Vec<alloc::string::String>"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"isComponent": false,
|
|
||||||
"isResource": false,
|
|
||||||
"short_name": "HashMap<u32, Vec<String>, DefaultHashBuilder>",
|
|
||||||
"title": "bevy_utils::hashbrown::HashMap<u32, alloc::vec::Vec<alloc::string::String>, bevy_utils::hashbrown::hash_map::DefaultHashBuilder>",
|
|
||||||
"type": "object",
|
|
||||||
"typeInfo": "Map"
|
|
||||||
},
|
|
||||||
"bevy_utils::smallvec::SmallVec<[bevy_ecs::entity::Entity; 8]>": {
|
"bevy_utils::smallvec::SmallVec<[bevy_ecs::entity::Entity; 8]>": {
|
||||||
"isComponent": false,
|
"isComponent": false,
|
||||||
"isResource": false,
|
"isResource": false,
|
||||||
|
Binary file not shown.
@ -1,278 +0,0 @@
|
|||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use bevy_gltf_blueprints::{
|
|
||||||
AnimationInfos, AnimationMarkerReached, AnimationMarkerTrackers, AnimationMarkers,
|
|
||||||
BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintName, BlueprintsList,
|
|
||||||
GltfBlueprintsSet, InstanceAnimationPlayerLink, InstanceAnimations,
|
|
||||||
};
|
|
||||||
|
|
||||||
use bevy::{gltf::Gltf, prelude::*};
|
|
||||||
use bevy_gltf_worlflow_examples_common_rapier::{AppState, GameState};
|
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
/// flag component for testing
|
|
||||||
pub struct Marker1;
|
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
/// flag component for testing
|
|
||||||
pub struct Marker2;
|
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
|
||||||
#[reflect(Component)]
|
|
||||||
/// flag component for testing
|
|
||||||
pub struct Marker3;
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
|
||||||
pub struct AnimTest(Handle<Gltf>);
|
|
||||||
|
|
||||||
pub fn setup_main_scene_animations(asset_server: Res<AssetServer>, mut commands: Commands) {
|
|
||||||
commands.insert_resource(AnimTest(asset_server.load("models/World.glb")));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn animations(
|
|
||||||
added_animation_players: Query<(Entity, &Name, &AnimationPlayer)>,
|
|
||||||
added_animation_infos: Query<(Entity, &Name, &AnimationInfos), (Added<AnimationInfos>)>,
|
|
||||||
animtest: Res<AnimTest>,
|
|
||||||
mut commands: Commands,
|
|
||||||
assets_gltf: Res<Assets<Gltf>>,
|
|
||||||
parents: Query<&Parent>,
|
|
||||||
) {
|
|
||||||
for (entity, name, animation_infos) in added_animation_infos.iter() {
|
|
||||||
//println!("animated stuf {:?} on entity {}", animation_infos, name);
|
|
||||||
let gltf = assets_gltf.get(&animtest.0).unwrap();
|
|
||||||
let mut matching_data = true;
|
|
||||||
for animation_info in &animation_infos.animations {
|
|
||||||
if !gltf.named_animations.contains_key(&animation_info.name) {
|
|
||||||
matching_data = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if matching_data {
|
|
||||||
println!(
|
|
||||||
"inserting Animations components into {} ({:?})",
|
|
||||||
name, entity
|
|
||||||
);
|
|
||||||
println!("Found match {:?}", gltf.named_animations);
|
|
||||||
commands.entity(entity).insert(InstanceAnimations {
|
|
||||||
named_animations: gltf.named_animations.clone(),
|
|
||||||
});
|
|
||||||
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(InstanceAnimationPlayerLink(ancestor));
|
|
||||||
}
|
|
||||||
// info!("{:?} is an ancestor of {:?}", ancestor, player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn play_animations(
|
|
||||||
animated_marker1: Query<
|
|
||||||
(&InstanceAnimationPlayerLink, &InstanceAnimations),
|
|
||||||
(With<AnimationInfos>, With<Marker1>),
|
|
||||||
>,
|
|
||||||
animated_marker2: Query<
|
|
||||||
(&InstanceAnimationPlayerLink, &InstanceAnimations),
|
|
||||||
(With<AnimationInfos>, With<Marker2>),
|
|
||||||
>,
|
|
||||||
animated_marker3: Query<
|
|
||||||
(
|
|
||||||
&InstanceAnimationPlayerLink,
|
|
||||||
&InstanceAnimations,
|
|
||||||
&BlueprintAnimationPlayerLink,
|
|
||||||
&BlueprintAnimations,
|
|
||||||
),
|
|
||||||
(With<AnimationInfos>, With<Marker3>),
|
|
||||||
>,
|
|
||||||
|
|
||||||
mut animation_players: Query<&mut AnimationPlayer>,
|
|
||||||
keycode: Res<ButtonInput<KeyCode>>,
|
|
||||||
) {
|
|
||||||
if keycode.just_pressed(KeyCode::KeyM) {
|
|
||||||
for (link, animations) in animated_marker1.iter() {
|
|
||||||
println!("animations {:?}", animations.named_animations);
|
|
||||||
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
||||||
let anim_name = "Blueprint1_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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if keycode.just_pressed(KeyCode::KeyJ) {
|
|
||||||
for (link, animations) in animated_marker1.iter() {
|
|
||||||
println!("animations {:?}", animations.named_animations);
|
|
||||||
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
||||||
let anim_name = "Blueprint1_jump";
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if keycode.just_pressed(KeyCode::KeyA) {
|
|
||||||
for (link, animations) in animated_marker2.iter() {
|
|
||||||
println!("animations {:?}", animations.named_animations);
|
|
||||||
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
||||||
let anim_name = "Blueprint1_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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if keycode.just_pressed(KeyCode::KeyB) {
|
|
||||||
for (link, animations) in animated_marker2.iter() {
|
|
||||||
println!("animations {:?}", animations.named_animations);
|
|
||||||
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
||||||
let anim_name = "Blueprint1_jump";
|
|
||||||
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 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trigger_event_based_on_animation_marker(
|
|
||||||
animation_infos: Query<(
|
|
||||||
Entity,
|
|
||||||
&AnimationMarkers,
|
|
||||||
&InstanceAnimationPlayerLink,
|
|
||||||
&InstanceAnimations,
|
|
||||||
&AnimationInfos,
|
|
||||||
)>,
|
|
||||||
animation_players: Query<&AnimationPlayer>,
|
|
||||||
animation_clips: Res<Assets<AnimationClip>>,
|
|
||||||
mut animation_marker_events: EventWriter<AnimationMarkerReached>,
|
|
||||||
) {
|
|
||||||
for (entity, markers, link, animations, animation_infos) in animation_infos.iter() {
|
|
||||||
let animation_player = animation_players.get(link.0).unwrap();
|
|
||||||
let animation_clip = animation_clips.get(animation_player.animation_clip());
|
|
||||||
|
|
||||||
if animation_clip.is_some() {
|
|
||||||
// if marker_trackers.0.contains_key(k)
|
|
||||||
// marker_trackers.0
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if animation_name.is_some() {
|
|
||||||
let animation_name = animation_name.unwrap();
|
|
||||||
|
|
||||||
let animation_length_seconds = animation_clip.unwrap().duration();
|
|
||||||
let animation_length_frames = animation_infos
|
|
||||||
.animations
|
|
||||||
.iter()
|
|
||||||
.find(|anim| &anim.name == animation_name)
|
|
||||||
.unwrap()
|
|
||||||
.frames_length;
|
|
||||||
// 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 as f32 / animation_length_seconds) * time_in_animation;
|
|
||||||
let frame = frame_seconds as u32;
|
|
||||||
|
|
||||||
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();
|
|
||||||
// println!("FOUND A MARKER {:?} at frame {}", matching_markers_per_frame, frame);
|
|
||||||
//emit an event , something like 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_name in matching_markers_per_frame {
|
|
||||||
animation_marker_events.send(AnimationMarkerReached {
|
|
||||||
entity: entity,
|
|
||||||
animation_name: animation_name.clone(),
|
|
||||||
frame: frame,
|
|
||||||
marker_name: marker_name.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn react_to_animation_markers(
|
|
||||||
mut animation_marker_events: EventReader<AnimationMarkerReached>,
|
|
||||||
) {
|
|
||||||
for event in animation_marker_events.read() {
|
|
||||||
println!("animation marker event {:?}", event)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +1,13 @@
|
|||||||
pub mod animation;
|
|
||||||
pub mod in_game;
|
pub mod in_game;
|
||||||
pub use animation::*;
|
use std::{
|
||||||
pub use in_game::*;
|
collections::HashMap, fs, time::Duration
|
||||||
|
|
||||||
use std::{collections::HashMap, fs, time::Duration};
|
|
||||||
|
|
||||||
use bevy_gltf_blueprints::{
|
|
||||||
AnimationInfos, AnimationMarkerReached, AnimationMarkerTrackers, AnimationMarkers,
|
|
||||||
BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintName, BlueprintsList,
|
|
||||||
GltfBlueprintsSet, InstanceAnimationPlayerLink, InstanceAnimations,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use bevy_gltf_blueprints::{Animated, AnimationMarkers, BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintName, BlueprintsList, GltfBlueprintsSet, InstanceAnimationPlayerLink, InstanceAnimations};
|
||||||
|
pub use in_game::*;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::query, gltf::Gltf, prelude::*, render::view::screenshot::ScreenshotManager,
|
ecs::query, gltf::Gltf, prelude::*, render::view::screenshot::ScreenshotManager, time::common_conditions::on_timer, window::PrimaryWindow
|
||||||
time::common_conditions::on_timer, window::PrimaryWindow,
|
|
||||||
};
|
};
|
||||||
use bevy_gltf_worlflow_examples_common_rapier::{AppState, GameState};
|
use bevy_gltf_worlflow_examples_common_rapier::{AppState, GameState};
|
||||||
|
|
||||||
@ -24,6 +18,7 @@ fn start_game(mut next_app_state: ResMut<NextState<AppState>>) {
|
|||||||
next_app_state.set(AppState::AppLoading);
|
next_app_state.set(AppState::AppLoading);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if the export from Blender worked correctly, we should have animations (simplified here by using AnimationPlayerLink)
|
// if the export from Blender worked correctly, we should have animations (simplified here by using AnimationPlayerLink)
|
||||||
// if the export from Blender worked correctly, we should have an Entity called "Blueprint4_nested" that has a child called "Blueprint3" that has a "BlueprintName" component with value Blueprint3
|
// if the export from Blender worked correctly, we should have an Entity called "Blueprint4_nested" that has a child called "Blueprint3" that has a "BlueprintName" component with value Blueprint3
|
||||||
// if the export from Blender worked correctly, we should have a blueprints_list
|
// if the export from Blender worked correctly, we should have a blueprints_list
|
||||||
@ -38,7 +33,7 @@ fn validate_export(
|
|||||||
empties_candidates: Query<(Entity, &Name, &GlobalTransform)>,
|
empties_candidates: Query<(Entity, &Name, &GlobalTransform)>,
|
||||||
|
|
||||||
blueprints_list: Query<(Entity, &BlueprintsList)>,
|
blueprints_list: Query<(Entity, &BlueprintsList)>,
|
||||||
root: Query<(Entity, &Name, &Children), (Without<Parent>, With<Children>)>,
|
root: Query<(Entity, &Name, &Children), (Without<Parent>, With<Children>)>
|
||||||
) {
|
) {
|
||||||
let animations_found = !animation_player_links.is_empty();
|
let animations_found = !animation_player_links.is_empty();
|
||||||
|
|
||||||
@ -84,23 +79,22 @@ fn validate_export(
|
|||||||
let mut tree: HashMap<String, Vec<String>> = HashMap::new();
|
let mut tree: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
|
|
||||||
for child in children.iter_descendants(root.0) {
|
for child in children.iter_descendants(root.0) {
|
||||||
let child_name: String = names
|
let child_name:String = names.get(child).map_or(String::from("no_name"), |e| e.to_string() ); //|e| e.to_string(), || "no_name".to_string());
|
||||||
.get(child)
|
|
||||||
.map_or(String::from("no_name"), |e| e.to_string()); //|e| e.to_string(), || "no_name".to_string());
|
|
||||||
//println!(" child {}", child_name);
|
//println!(" child {}", child_name);
|
||||||
let parent = parents.get(child).unwrap();
|
let parent = parents.get(child).unwrap();
|
||||||
let parent_name: String = names
|
let parent_name:String = names.get(parent.get()).map_or(String::from("no_name"), |e| e.to_string() ); //|e| e.to_string(), || "no_name".to_string());
|
||||||
.get(parent.get())
|
tree.entry(parent_name).or_default().push(child_name.clone());
|
||||||
.map_or(String::from("no_name"), |e| e.to_string()); //|e| e.to_string(), || "no_name".to_string());
|
|
||||||
tree.entry(parent_name)
|
|
||||||
.or_default()
|
|
||||||
.push(child_name.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let hierarchy = to_json_string(&tree);
|
let hierarchy = to_json_string(&tree);
|
||||||
fs::write("bevy_hierarchy.json", hierarchy).expect("unable to write hierarchy file")
|
fs::write(
|
||||||
|
"bevy_hierarchy.json",
|
||||||
|
hierarchy
|
||||||
|
)
|
||||||
|
.expect("unable to write hierarchy file")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fs::write(
|
fs::write(
|
||||||
"bevy_diagnostics.json",
|
"bevy_diagnostics.json",
|
||||||
format!(
|
format!(
|
||||||
@ -124,6 +118,244 @@ fn exit_game(mut app_exit_events: ResMut<Events<bevy::app::AppExit>>) {
|
|||||||
app_exit_events.send(bevy::app::AppExit);
|
app_exit_events.send(bevy::app::AppExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct MainAnimations(Vec<Handle<AnimationClip>>);
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct AnimTest(Handle<Gltf>);
|
||||||
|
fn setup_main_scene_animations(
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
/*commands.insert_resource(MainAnimations(vec![
|
||||||
|
asset_server.load("models/World.glb#Blueprint1_jump"),
|
||||||
|
asset_server.load("models/World.glb#Blueprint1_move"),
|
||||||
|
|
||||||
|
// asset_server.load("models/library/Blueprint6_animated.glb#Run"),
|
||||||
|
|
||||||
|
]));*/
|
||||||
|
|
||||||
|
commands.insert_resource(AnimTest(asset_server.load("models/World.glb")));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn animations(
|
||||||
|
added_animation_players:Query<(Entity, &Name, &AnimationPlayer)>,
|
||||||
|
addded_animateds:Query<(Entity, &Name, &Animated),(Added<Animated>)>,
|
||||||
|
|
||||||
|
animtest: Res<AnimTest>,
|
||||||
|
|
||||||
|
mut commands: Commands,
|
||||||
|
assets_gltf: Res<Assets<Gltf>>,
|
||||||
|
|
||||||
|
parents: Query<&Parent>,
|
||||||
|
names: Query<&Name>,
|
||||||
|
|
||||||
|
) {
|
||||||
|
for (entity, name, animated) in addded_animateds.iter() {
|
||||||
|
// println!("animated stuf {:?} on entity {}", animated, name);
|
||||||
|
let gltf = assets_gltf.get(&animtest.0).unwrap();
|
||||||
|
|
||||||
|
let animations_list = animated;
|
||||||
|
let mut matching_data = true;
|
||||||
|
for animation_name in &animations_list.animations {
|
||||||
|
if !gltf.named_animations.contains_key(animation_name){
|
||||||
|
matching_data = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matching_data {
|
||||||
|
println!("inserting Animations components into {} ({:?})", name, entity);
|
||||||
|
println!("Found match {:?}", gltf.named_animations);
|
||||||
|
// commands.entity(entity).remove::<Animations>();
|
||||||
|
// FIXME: for some reason this does NOT overwrite the component ??
|
||||||
|
|
||||||
|
commands.entity(entity).insert(
|
||||||
|
InstanceAnimations {
|
||||||
|
named_animations: gltf.named_animations.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//animations.named_animations = gltf.named_animations.clone();
|
||||||
|
|
||||||
|
|
||||||
|
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(InstanceAnimationPlayerLink(ancestor));
|
||||||
|
}
|
||||||
|
// info!("{:?} is an ancestor of {:?}", ancestor, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_animations(
|
||||||
|
animated_marker1: Query<(&InstanceAnimationPlayerLink, &InstanceAnimations), (With<Animated>, With<Marker1>)>,
|
||||||
|
animated_marker2: Query<(&InstanceAnimationPlayerLink, &InstanceAnimations), (With<Animated>, With<Marker2>)>,
|
||||||
|
animated_marker3: Query<(&InstanceAnimationPlayerLink, &InstanceAnimations, &BlueprintAnimationPlayerLink, &BlueprintAnimations), (With<Animated>, With<Marker3>)>,
|
||||||
|
|
||||||
|
mut animation_players: Query<&mut AnimationPlayer>,
|
||||||
|
keycode: Res<ButtonInput<KeyCode>>,
|
||||||
|
|
||||||
|
) {
|
||||||
|
if keycode.just_pressed(KeyCode::KeyM) {
|
||||||
|
for (link, animations) in animated_marker1.iter() {
|
||||||
|
println!("animations {:?}", animations.named_animations);
|
||||||
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
||||||
|
let anim_name = "Blueprint1_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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if keycode.just_pressed(KeyCode::KeyJ) {
|
||||||
|
for (link, animations) in animated_marker1.iter() {
|
||||||
|
println!("animations {:?}", animations.named_animations);
|
||||||
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
||||||
|
let anim_name = "Blueprint1_jump";
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if keycode.just_pressed(KeyCode::KeyA) {
|
||||||
|
for (link, animations) in animated_marker2.iter() {
|
||||||
|
println!("animations {:?}", animations.named_animations);
|
||||||
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
||||||
|
let anim_name = "Blueprint1_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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if keycode.just_pressed(KeyCode::KeyB) {
|
||||||
|
for (link, animations) in animated_marker2.iter() {
|
||||||
|
println!("animations {:?}", animations.named_animations);
|
||||||
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
||||||
|
let anim_name = "Blueprint1_jump";
|
||||||
|
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 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger_event_based_on_animation_marker(
|
||||||
|
bla: Query<(Entity, &AnimationMarkers, &InstanceAnimationPlayerLink, &InstanceAnimations)>,
|
||||||
|
animation_players: Query<&AnimationPlayer>,
|
||||||
|
animation_clips: Res<Assets<AnimationClip>>
|
||||||
|
) {
|
||||||
|
for (entity, markers, link, animations) in bla.iter() {
|
||||||
|
let animation_player = animation_players.get(link.0).unwrap();
|
||||||
|
|
||||||
|
let animation_clip = animation_clips.get(animation_player.animation_clip());
|
||||||
|
|
||||||
|
if animation_clip.is_some(){
|
||||||
|
// println!("Entity {:?} markers {:?}", entity, markers);
|
||||||
|
// println!("Player {:?} {}", animation_player.elapsed(), animation_player.completions());
|
||||||
|
|
||||||
|
let animation_total_length = animation_clip.unwrap().duration();
|
||||||
|
let animation_total_frames = 80; // FIXME just for testing
|
||||||
|
// TODO: we also need to take playback speed into account
|
||||||
|
let time_in_animation = animation_player.elapsed() - (animation_player.completions() as f32) * animation_total_length;//(animation_player.elapsed() / (animation_player.completions() as f32 + 1.0)) ;// / animation_total_length;
|
||||||
|
let time_bla = (animation_total_frames as f32 / animation_total_length) * time_in_animation ;
|
||||||
|
let frame = time_bla as u32;
|
||||||
|
// println!("time_in_animation {} out of {}, completions {}, // frame {}",time_in_animation, animation_total_length, animation_player.completions(), frame);
|
||||||
|
//animation_player.animation_clip()
|
||||||
|
|
||||||
|
let matching_animation_marker = &markers.0[&"Blueprint1_jump".to_string()];
|
||||||
|
if matching_animation_marker.contains_key(&frame) {
|
||||||
|
let matching_markers_per_frame = matching_animation_marker.get(&frame).unwrap();
|
||||||
|
println!("FOUND A MARKER {:?} at frame {}", matching_markers_per_frame, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// flag component for testing
|
||||||
|
pub struct Marker1;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// flag component for testing
|
||||||
|
pub struct Marker2;
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
/// flag component for testing
|
||||||
|
pub struct Marker3;
|
||||||
|
|
||||||
pub struct GamePlugin;
|
pub struct GamePlugin;
|
||||||
impl Plugin for GamePlugin {
|
impl Plugin for GamePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
@ -142,8 +374,6 @@ impl Plugin for GamePlugin {
|
|||||||
.after(GltfBlueprintsSet::AfterSpawn)
|
.after(GltfBlueprintsSet::AfterSpawn)
|
||||||
)
|
)
|
||||||
.add_systems(Update, play_animations)
|
.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(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
|
@ -27,17 +27,27 @@ def remove_unwanted_custom_properties(object):
|
|||||||
# TODO: rename actions ?
|
# TODO: rename actions ?
|
||||||
# reference https://github.com/KhronosGroup/glTF-Blender-IO/blob/main/addons/io_scene_gltf2/blender/exp/animation/gltf2_blender_gather_action.py#L481
|
# reference https://github.com/KhronosGroup/glTF-Blender-IO/blob/main/addons/io_scene_gltf2/blender/exp/animation/gltf2_blender_gather_action.py#L481
|
||||||
def copy_animation_data(source, target):
|
def copy_animation_data(source, target):
|
||||||
|
"""if source.data:
|
||||||
|
data = source.data.copy()
|
||||||
|
target.data = data"""
|
||||||
if source.animation_data and source.animation_data:
|
if source.animation_data and source.animation_data:
|
||||||
|
#print("copying animation data from", source.name, "to", target.name)
|
||||||
|
print("I have animation data")
|
||||||
ad = source.animation_data
|
ad = source.animation_data
|
||||||
|
"""if ad.action:
|
||||||
|
print(source.name,'uses',ad.action.name)"""
|
||||||
|
|
||||||
|
animations = []
|
||||||
blender_actions = []
|
blender_actions = []
|
||||||
blender_tracks = {}
|
blender_tracks = {}
|
||||||
|
|
||||||
# TODO: this might need to be modified/ adapted to match the standard gltf exporter settings
|
# TODO: this might need to be modified/ adapted to match the standard gltf exporter settings
|
||||||
for track in ad.nla_tracks:
|
for track in ad.nla_tracks:
|
||||||
|
#print("track", track.name, track.active)
|
||||||
non_muted_strips = [strip for strip in track.strips if strip.action is not None and strip.mute is False]
|
non_muted_strips = [strip for strip in track.strips if strip.action is not None and strip.mute is False]
|
||||||
|
|
||||||
for strip in non_muted_strips: #t.strips:
|
for strip in non_muted_strips: #t.strips:
|
||||||
# print(" ", source.name,'uses',strip.action.name, "active", strip.active, "action", strip.action)
|
print(" ", source.name,'uses',strip.action.name, "active", strip.active, "action", strip.action)
|
||||||
blender_actions.append(strip.action)
|
blender_actions.append(strip.action)
|
||||||
blender_tracks[strip.action.name] = track.name
|
blender_tracks[strip.action.name] = track.name
|
||||||
|
|
||||||
@ -47,28 +57,31 @@ def copy_animation_data(source, target):
|
|||||||
blender_actions.sort(key = lambda a: a.name.lower())
|
blender_actions.sort(key = lambda a: a.name.lower())
|
||||||
|
|
||||||
markers_per_animation = {}
|
markers_per_animation = {}
|
||||||
animations_infos = []
|
|
||||||
|
|
||||||
for action in blender_actions:
|
for action in blender_actions:
|
||||||
animation_name = blender_tracks[action.name]
|
animation_name = blender_tracks[action.name]
|
||||||
animations_infos.append(
|
animations.append(animation_name)
|
||||||
f'(name: "{animation_name}", frame_start: {action.frame_range[0]}, frame_end: {action.frame_range[1]}, frames_length: {action.frame_range[1] - action.frame_range[0]}, frame_start_override: {action.frame_start}, frame_end_override: {action.frame_end})'
|
|
||||||
)
|
|
||||||
markers_per_animation[animation_name] = {}
|
markers_per_animation[animation_name] = {}
|
||||||
|
|
||||||
|
print("markers", action.pose_markers, "for", action.name)
|
||||||
for marker in action.pose_markers:
|
for marker in action.pose_markers:
|
||||||
|
|
||||||
if marker.frame not in markers_per_animation[animation_name]:
|
if marker.frame not in markers_per_animation[animation_name]:
|
||||||
markers_per_animation[animation_name][marker.frame] = []
|
markers_per_animation[animation_name][marker.frame] = []
|
||||||
|
print(" marker", marker.name, marker.frame)
|
||||||
|
|
||||||
markers_per_animation[animation_name][marker.frame].append(marker.name)
|
markers_per_animation[animation_name][marker.frame].append(marker.name)
|
||||||
|
|
||||||
|
print("animations", animations)
|
||||||
|
|
||||||
"""if target.animation_data == None:
|
"""if target.animation_data == None:
|
||||||
target.animation_data_create()
|
target.animation_data_create()
|
||||||
target.animation_data.action = source.animation_data.action.copy()"""
|
target.animation_data.action = source.animation_data.action.copy()"""
|
||||||
# alternative method, using the built-in link animation operator
|
# alternative method, using the build in link animation operator
|
||||||
with bpy.context.temp_override(active_object=source, selected_editable_objects=[target]):
|
with bpy.context.temp_override(active_object=source, selected_editable_objects=[target]):
|
||||||
bpy.ops.object.make_links_data(type='ANIMATION')
|
bpy.ops.object.make_links_data(type='ANIMATION')
|
||||||
# we add an "AnimationInfos" component
|
# we add an "animated" flag component
|
||||||
target['AnimationInfos'] = f'(animations: {animations_infos})'.replace("'","")
|
target['Animated'] = f'(animations: {animations})'.replace("'", '"')
|
||||||
|
|
||||||
markers_formated = '{'
|
markers_formated = '{'
|
||||||
for animation in markers_per_animation.keys():
|
for animation in markers_per_animation.keys():
|
||||||
@ -79,7 +92,10 @@ def copy_animation_data(source, target):
|
|||||||
markers_formated += f"{frame}:{markers}, ".replace("'", '"')
|
markers_formated += f"{frame}:{markers}, ".replace("'", '"')
|
||||||
markers_formated += '}, '
|
markers_formated += '}, '
|
||||||
markers_formated += '}'
|
markers_formated += '}'
|
||||||
|
print("markers_formated", markers_formated)
|
||||||
target["AnimationMarkers"] = f'( {markers_formated} )'
|
target["AnimationMarkers"] = f'( {markers_formated} )'
|
||||||
|
#'({"animation_name": {5: ["Marker_1"]} })'
|
||||||
|
#f'({json.dumps(markers_per_animation)})'
|
||||||
|
|
||||||
"""print("copying animation data for", source.name, target.animation_data)
|
"""print("copying animation data for", source.name, target.animation_data)
|
||||||
properties = [p.identifier for p in source.animation_data.bl_rna.properties if not p.is_readonly]
|
properties = [p.identifier for p in source.animation_data.bl_rna.properties if not p.is_readonly]
|
||||||
@ -136,7 +152,7 @@ def duplicate_object(object, parent, combine_mode, destination_collection, libra
|
|||||||
copy.parent = parent_empty
|
copy.parent = parent_empty
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# print(nester, "copy", copy)
|
print(nester, "copy", copy)
|
||||||
# do this both for empty replacements & normal copies
|
# do this both for empty replacements & normal copies
|
||||||
if parent is not None:
|
if parent is not None:
|
||||||
copy.parent = parent
|
copy.parent = parent
|
||||||
|
Loading…
Reference in New Issue
Block a user