From ce473a357e08332d9da5648e497f761c6fd2989f Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Fri, 22 Mar 2024 13:59:01 +0100 Subject: [PATCH] feat(animation): split animation logic/components into Blueprint vs Instance animations * renamed existing animation components with Blueprint prefix * added almost identical but seperate InstanceAnimations & InstanceAnimationPlayerLink --- crates/bevy_gltf_blueprints/src/animation.rs | 21 ++++++- crates/bevy_gltf_blueprints/src/lib.rs | 5 +- .../src/spawn_from_blueprints.rs | 16 ++--- .../src/spawn_post_process.rs | 6 +- testing/bevy_example/assets/registry.json | 36 ++++++++++- testing/bevy_example/assets/testing.blend | Bin 2237584 -> 2254280 bytes testing/bevy_example/src/game/mod.rs | 59 +++++++++++++++--- 7 files changed, 115 insertions(+), 28 deletions(-) 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 7d8adcde1ca141854dbe88633e9d09caf530ed09..8aa688496acc92c7e525c01deca6687adf466d2a 100644 GIT binary patch delta 22572 zcmbVz2Ut@{*KqDl0-+>;R1p-!!dgKQK}v#a!3y@aDp*$R=&EZ6JFX49>fpL6cI;@x zpaKEQiX979s=b%B*ZI$xn~QP(_x-;A`SU!7Gc)JRnbYRX+?$YmDv2vNvye-kph#+< zySZ=judM`^sV*sLp?bg8ah%{aLn&09X5;$t8F>sg&GsRQ_^e&ujVSfU)uqkC(Z&+gcs%X!*dDBpj{>`YG2jv-P2-<@b<|q`r^(- z;c{eO{{9tx<8}kM(C20J{j*Z~{y6|*fOk(zD%syWzDXH8x=vp|yiWglaFxEgUj$+b z>22Xu`}z)di*hK!y{kqPPTva34mIqamY$}!FCC^g{!XU`GD6?9LqD!r31}c{@#gUj zlei-K^4?`O@%ilw^jXDu`n3EkeO!8q-oKttFB>-r$2!(*4|0+G6v$7?&d^6C1@z&q zzv+XUCurG)gY?$vz4T_mZhGfR4t)xA2_D=yMz5bprw4>z>89yz>6-W;edA93xyESH zKM$_4wV#72(z;Jz-ABbIVeO;zPEjtsQLu~VY@RI~>0GBJtZ%;d!&@il!<)w$>+LJq zwEW^BT2^RaPzpK~pV>!C&+VtBXZO>hybbj5+VOgysF9qow5LTiv=P_3e=VOWT>?y3 zk8Py|`*-0n~F<^_3xtz=Xs63xO<5?sp8ThdiD4=x^GoH zT{fmQof{Jr56~N@_UPr^7I9UJ!1i;@=G&LE>GhL4Y1aB_ zbY{P%!nW=qzDMb8T=()3W>(2LJ-rF8z6M-H$I}6}(M$Q8=!I;(b&uIxwO9AAFi&Fi z?p@1c(oXDMOqY&nEo|!<>?+!Dgeib4;e3#zf8TR8XNPHkVR!^_1*?Shy~CQ`1tF+? zF)Vxo;){!2G;W~hkNibXWv-z4yOO9OZ7SWhViXmo^`w*ghY5ClqPS7|fqneBYOfz* zmWj@K0{+DHkM3Gb=MD-McJ^)T+?82Ydj252_V-SDK6@=ab#SHdqHou#lbX_jVQ#d6 zZynmSNfR0n5Wpa=gT8OSCR`2JSZs&jrotWZ{B|Kr+xrlx;xie-&R-g<2QrtTy9#sD zga^O$vD`bVHl5l=qi@^4EmymozB6sL$~^(v{_~)SCGTzU`0+hU1pR=z&f}T+S0Fpi z9{Q7Jte!web#EcO7|^56@2#wz}s1ZA;#Nr-SU|bzFo{IIosyYN&R)glbG7_3}K|; z80%lRgRg@6+H=&$@%z%~rSze-=%M)9^!W7Vba;ox`jN5TocE_!usGBvtWT`6u^I)+ zV7&r(FYF#v-)_%_#o(&-wBUe17f8><({VO3!Ac(k)Ad)1jRLgaJP2sQST?_M6_g9_n&Ci*jhAyvOi7#wGM5fA3by=XLIiG z8k)UzHl6s3R=D$PV^6U#VRm7$DKCUvIu4P_Tuw7rjT9OW^Yn4Dyl;S(p zr-rdU)HtaTHU8e11~jarA3JO~XL(}ZGCFred!Z~Y>}Ra6Ps`4-?SK37VW@7qXyK7H zG=FO%O`q43rjBhvQ{n<>-I_J1i;AaJU=eReb!8g-(yFn3;P8o@b+4}N>GG+)>Clcs z>4-*ycYrTGyuj=&VRaq1hgi=q(r4x8#KH?j39^_L9o7ujX`nnQri%JdgQnIG$99i7lCNVqlX=Pq!hz{w-l zd|2+@6}Dm6a!}#0Xy@-)K^xVt$Cj|O;HjrIPaD+sVM_!CKt_+POOH%wK#xxgq_2;_ z5~ELW+Ba|};qJrAaTj#<_w%D}Ry@^!01psQx0(xW9Tq^7;=*WpTrDQxeiYoMJV|Q^i)i9|VOlst2MR&~%qeZ!EXzIuyx;xH`URv6nemtQcGp;LV z*$j*x65U)lIli_0!S!Q;-EYB-YgAEFTP07c!s1>wJY71}kLIQhrjbpm(J(Isy}af( z`r-H%`tk2=^y8!J!d@$Hq0q)km?5{-@BYn>)2>=Ni=H^Rj-ENNoUWPFiY||9N`>J~ z>535nbS1#5kpc9t-@@qbg?;GZHSqvr>4D{gsXir^?wl7be4fzBzilIDYGWa7QexVDYW={m~6fkq@v1J_)macNCI;^AKLvRtR2hR@ShKuq+6($Lfs} zm0TN4=CcP^(6p)TXxg;)bpP^U^l18QS_D=2)~Vfay6I`f#ViP5HrxPm=^Z>KE@U#= zrR=}xiS4s!{$|1Y_wbPT?*7yUJmd-<^0wt@eP=m%T2A{0d(ck>JLu=L836m}=hM6C z$1{8A3pfbgJ-vmu8li@}r;zr$g9fq|%Ohs&MlxS-{N0jkU5IBQJ8DZ{HY$VHkjHR6 zcyae4{Rb{8$c~x!7EXMG*N`-LPQ3&=I}d(af%h!1dBeNa(H6kzC(5JT855iI zLhoKY$d*Mf9M0HCe+^QwZF_y!Oh^V!;U?Uh_QDbm2=qE_Q`bsV11hwT@Vl!}bB2#~ zU<2BrRR|r_IZ%k2@ss@ApM!;IGiv&ko-`?3L1+IGM5niRr}sc3ypy6aIS0~d4?k3#2x2L}j=tht1SW1_VYDt4U z6|^yguUiurdSTsk`uWr@5l#b!B&!4n<(KpO>79KGXx4%@Lc*+Ou20I&(d~;z)23c_ zw2GAiE<-KpgWa?BXJ*B64GRkn(_w@A)Ant&bTgSlufe&zd3+cR_LNh)2x_TaAHf@mur z-el(tA!>=cFm#@SFk*>KdocOq$?fz#?231ADaNvo(U1U7-m!yw()JCU=!~DO>9lZ; zP7RaMi6I>Qy`wMvd|ppKfxF({y_B-dSzkU+#|1tryFe$6iKYFz=;*{Dk@UcZL|O)F zoK5OLdo`5PEFUwn7k88?^gO2%JHL&`Sd+hv2T|T(a%NM`jZQyxPaUA&W%%a-_{j$Xy0~p zU{@U-0MI{LOP9t+(VJut-7%smy|5l~9CZ=(X}_>@<9GQRsD54?ZQsa^HgOkMtIQJ2 z7R;2hd+BF1{ew(uw6%c3g6w?)>%%S44xI9nlv{*m4buW%Pn9ibdLnpda&{H^G?7IJzA zw)VTD8wKq`XCZo#uG(i%`y+S?y@i0fZ=TYZo=Y7s>|9i}#+$3T^dUU9+_`>&t(CQN z4ZU$787|j*AnX;wiv`sM&p*_HX7Tx9xG6WUTR~g@tfe8r%^9=^4rF-nfS$B>_fF6b zq~aKiw`fko0JM;KEyJ4AsIdBUP>3`AqnkI~GqDZ5w0aDEeRw6Lte&MUE9GZ)gYMOZ z{_|AA@Ffnym_;5=yDH<2mWUwiSmN&U{=xzJch(l#r%e;u*j+_`33Q>w$-U{xgf?_$ zY%5xF_Mq@&QBA>W=>^LVpnUwu!9v+m&win(7$~I;ZBD}hqa&k#4x|bFThcvKyU;6t zjs?Y5(RX?4egMqtFNK*5zM3#9{~4UAT|J_GKP*;Be|5Sd}(%x1`Oh zThfAAk+fuaUwUWl2>Qyf98T1Y^uyyD!UdKYR)S~pkpy^1ryEwzHhC93**t&-2R3EU zKe{y?H!zAW7~P95|2>v&m^p|ZSTus3S^XRRCrc0&HKM}n={v-%Z88AbsHCL)f5G1fU3gt5A|YAAiWdp3Q#3t<+0vV8`a#Ou2-$MB2T~d~^W_-#=$CjrMb*Pj)8Ke-5TFh42=H$2k_qcfbd) zOoSK0tAvQ4h7B6JDQ`Bas)XYoK|xP0>)xRZC{% zfhnEn{j_*`cil*OdPXyPd|WMhda@sVzIQ%-sTU2D@T&t$z~CiJ{+paXS!6$Yt)gzW`P zp7&7c*wqWBegR-t=x3$E3-U3+Ud46AeTiwjc}PQA1c|pZ){SoLA*cF5YWnvCU;1MI zAK&9-GUZj~GA17$B-Uz9BjTOAk$ zhG4wDvUC&c$LG^fLkh%nM0TVxI$Sdf7X89J_d06@CNfJ=OjCqUz$c_7c?haM%M)ZW z8RzS4aTV>054EBrn#*a=dNSI-k&ONtz|s7p1-gDJ0qT5yJO$qiD6v5Nv16+l%v_k?4AzSKM!wnb>$L@l) zfsITmvH}At;YHvL#Ge%!NhS0lnEB=IMg5bt3ho!jM($Sc#cF{1$m#Uh4)hzYd;7fT z40MQ@r_H_o?S>cuX)}C=qvjLbD{w=6D>*4>H~9!-)_Yi;Wp1X|^95mjxI2WR(mUv3 zC=*{wPrcZ&k?5bSS8`ozIjiy{?`%$pr4-EsZT_1^Ogob%qNcDt!7X24&!M)oR0!M> zAWYier9MsJfksTCtGR-4gR5|OgPRL%RNSn{T6}_DJG}Xbz1r5wP%%xR;5t}Y$QweH z{L;vkr#lz@R;dZo2sC2}^DiHvC|sHO3SOD8N?2MTG~YDB0uvP+v29cRDxfB0Ai^hj z)wy*|(kxt4#dWLcXsJgJ>`j?wTJORS>waI;6dNc=EP1iwnnco4SP1e;gfl|ahPnzU zS!KeQO^t;mn;fj5FatYmC_%r)+a3$UJ9t>bYu>)})a9b}32K!hJlM;I9{O|kf7C>b z31k7&;25Qq8k{s~V#41wVf*v>g(Jl~QxcYr>>1g5`mepaZCm);j5E7P`adVP<=;PZ z@c7qzmp**Ge?>*%4=j8^7`v@aW7xZRP_h_f9k|LWEZeSMpd7!!$6$EDh$bA^wJr@! zkaN8`{~GouF6~|Qqy81=-lF+~+i$P(YEJ6JNFl=R~zdb)^xV&z`l-W@c z!K6#NrMD2XU9EXu_WU#4e!qhIz#l@wCRZiPR%q1}4sBOg2fu^vU*U0F{NAC2z5#yJ z^WdJ1dx^Iz|BIm8u{qk)*)FQ+;0BcPu_SM|aqWUBGoxCC2K!Z4TYo&UKYD}3n#@F?rg+YPVlENc+Re`tGHRUmo4~_U-OPVg2?xLjO&6 zmS5o|2R?x>8{(`ezj`81pLolIb2__b%0B7h{4PK3S&Mqre?n359=6u-A|xWX=G2L! z<3{w0YJX_W{H33YvWwsd`zoaE^^$`f!i&`&%A4(4hd0E)dvNxaJRrC1fw|ye~ z!%$RGTeV8gMK-JJ`Nz0{v1fL!+Whs#v77Lub>aD`UB*up=WlC>%~Mr}i4+j6dkm(vv1ob8-J9R|Y#+^2r6o43YAHhXd4CL7Q>ut|N} z7R~)#!de8@4Gj+P4hm>w?_g)mgS~#7YIwUw+DW}z_Cb9=aJ;pJe%7siE-1824f)Ut za{_yAPWU&Cllr!r%*EVrrOnT?LY&9TWU7D%A*(F7T2=*B>)&*O0WY$lL{lwA*MLm0 zfD^XBbAcTBe!zx(7Mxt!Os|y5s>{CzRdq$x0(pD)xcUM`NuQvRVxM91$c8JEb25&c zvE{a4!|MAIpsc^23VXHH(Z?duvjfkOKNMHrYN}Ws4!e{;(p=Os)-_BQlEklNj&nw+M$Lt z7cPvqjm}`UyCEhK~J0ujfD zaY5)LvNMcph7H4=FwU7{t0OC^GOyyW=|T!~ zlnP=zEO$`;&3VfHCJ{aPy4(#QIo5_Qrk?3zC6mkSLC*Ivl@U^gT%5}}8EQvzO*w~z zZmT(C2}&6G+7p7kd2CpgkMTkb-<+H*gswZ4JE zmPEDZloo$;>$$%^pNMe2ZD+MQ2F1#>jFpiYr#6UWCx@i{^^ugJoqTxeHe!U-hY! z#CL^8$F>g)(cQRAE9;6or5N>r!{x-TKR40-Ev$bXA}9yQ=I(N2MSm{RCi3D=wx>Q6 z?j*);e076z0QZdZ&Hh=Ic%3;xRJQbInd~0xXM&h)081d8;)r_;SDiZrv2Z52+jvXT zaGYFina!Q%0AREl$sWL|l(=>-acILiyPSsRk00bVWXEtpd~E|z5bSjaf-#p`MRbpd zhbk=fd-FgiU4r?#2HjvzXT{0Lh68*JL)s|LgG)fk2uYo;usz^y>VK&0!_I}VxXu!t zXZ`D@ejT9UNA=`5^9i=)u%c@6o$9EK9rSU&)JHn@BWtX|4b~a^B7@a#GXb1T)u50m zBntT6ujIc`o9$4s4|G(392(8(t*_f2WuoFVhDl?%F)p?Rx#Bj9vpO1LcsZBT@Giw> zf!YUw!oJ7R6n`g@yns^}8Z6)ndA09!J=5XCC@79tnd*~(Ke&&Ii3Ga-iy)bbRX2(K zVy;A?NV)GsUM+@93t&071c1AAdivnQ+R6^pO z%ym=fcY;KR&ama?C3CYBmFn5&%VY;yO6nOrR&u_!*1fGo`y%ZPoi}i+ROGk=??B#e z=eF6V+K8kNDQ;>*`VKB_vm6{mIz;heNtzSIH&NKO6q!=feV;oS^1JaKoXs$fdD9Ir zE3Y;Mrt+FJtO^-em8-3YOidGOvf}zI-{&N?2Or4gkqbTet2S>ozGSr-Fv;l2w^I8y z;%i{^lj;K&OL}^`X}U7#&Am@fB(@j7;J;KB{>?@*_B8K8I`!s#U35;zF~;~&C0>9% zR^@mx-Axwt=8xK(TO=L|lR)dX z7H~uoF%IHW9QJ*sbQxrJW6+af5<8d=<j(4AEL8NhEd>7NV7|RNPFY8R-hqNA zD<@qh^EF8H5Wb;2^J^)|h~}IPD~IsqTI=O8Ecvh)C2Z!;*?vfcaKW_eyGw)du<$TU z*urz1ZQy&h)7%iV)62HtkOe#ABRNl#7b3Sy!TYcgg6Fr5Z{ofVe0kh#8$i8EJkR=M z`Zm5DD@)|kHh!c{yMI_&bOX$i!`AI`rg%J3$<3-hrlVKsW&}0K$8`RdjazGR{{SXs z+xdC53&CQ9Wal%?Hmp@L_4hv3szO$)NX8C6k>iN}PF@RW+)%DDpbb0u1VG-qaL^D7 zh=NI=kv&SzokT~#5gZ?^R3!ZW7FS%w zyqIDiwNaUB<^NJ#ksbAKR#{9<1C`bKe=4q|_d!0Mm&?fMgM3TdAV@m4qvxf{G5I{V zH8b#>O_WS58-T^kP(emulKSRY+{7DPErsv8sW-&C+{0;x=UM!7g*vjP-KrK=la@~D9S**58oC@an=*_p0+A=;^QE5QP{`V@af!6uA@+Y+B>AbU?k zt;FL2ly@5rw~ypAe5+~&AOX#Zdnro1t`kpM->Fv!RdUYCNXr*Dn3tT0=UKjnB9*`Y z$)G#SH?&l&J^0dzjJwSDau(o@b_8;xD*$5rl#%@YmagQ@W!_tk%fTJTnKZn@dnsmj zdf-I5T;Y2;#87eGDB#C=qliOCE>v*~&m*`vIT3Xc@J~m6|02E@cZw`5;ycQNKbyoo zL$b~r)Nr^8TCQ&&d15D04@Gm zCUa(e2hhaLWW|aUe^>JIlSais3vNusoCO(mgSS_%1eTR#)(yUkW+mGeI6?I^5ubCM z$eSB{qT=DLdaM98AiC2E71?!@_p(r>zlS?Fskwq{@0q&s1Uo>`TO+{}xaM?dGfYYp znh>Si9~g58p`&5(Ek2sF?OjJq-t==TT9dScVC2_g-cF%{C=vS-{;c9&cdMhMyo3+1 zSvdAmgv-*m^Z%Hy@wc#OHW;y8*{DKD0eLvEAlYAKiUgh5R(2mEogdV<~UV<2o%DWR&v& zazjSB;-|0_oejC`seC5yJ)_KUrMmJgN20et5%N0-PebWm%2c&F(p_Mi=OJR!sgbgu zGHLJJGAF~Vxyo)_icUpTe#$hZ@8(pn8g4wEq;#X&f)x5G!%6i)N)M9rQXOcB@mK!D z+4ir(M5z!PRyI*yQL=?c1t|k~jcP~{OLXz#XV}w1IZ5R#tv(*=JVr~@BKT+J8c)`Q zZ6J{_B=})d$g7`~f~Y82*h(3sz$MAJQss~U^$Mm$K^O79DNce1H&Z`pw)h|?Vbwh7 zlm4xh`r1iZ;(3aPkRPsO67>e!s9X~ENwYS}rXH*b%1NXG6Dv+3bK58zcuFG@he{*r z#b%OoZItyrr6GwW(!|2166dzSA`M9_NhTIHmGlP|A8ANpDKN1_N~|(#VppMbCDxHj zji*GFxK(y0wUC=U1A#TAA&Di@#3D^qT_u_dWgSmxT;h{F%;u9Bk;=NnuL6=SCQ|9v zOky^__Di9;CcDa-l!^~4I`lP$iNrpH1UnU}bPc?23L6U-I39WNgR#;9mgw)Gjj{5b zgJCAmTc|yV#}m$lq_tDpdy1nnnZz}jahYb5iS3jjp3;!SQea|XQ^`4CsVNOfEN*kf zl#-?fBDYAaP#Edb6LIgAn_fQan924Ad{C<_W&Dt)=}x>$(k@jBE=yI`fLhm*hyKfrZgn6 z1esW*sj4Yt=3}Lcr!+3{sZ4xqK3R*Rq#=prI_Qb3NmEtRMN!hY#FuX3WAll+Gl-Ig zBo;IoMM+at2~3odjgyEcN=I913cA$Lv9ofBoaDLNs0>+MlrwyY@{ZDh9B!cuGR&N) z96OxrL7tZ?UHG7M(zms;j-f%BvbRE!)XTjFNxGv9sEsYW0901XQ36;1SOTa3tN^SHFYnmA(vlbVI4e1n)D-`a1-`Xx4ZgM1 z7nN`#7!>u?R}>0Vo)kAy2fDW$HF0SC_~BzF1PzQGGkkRHgrP$Qju|^}(AY7nMrh!- zEu`We=bECcWt&w{leq>l-ryRNLp5#V6gWyQK2|!C!YHMc0w44ZCmN}bDHM_SC*L58 zo2rW~um$^ZOn|zklC{|coAg>rc25T*Ny1~LvmrS^UFZW>z1ZIB>|h>7*T<@L4*yXx z)joK2mVW2O3wD`Qe2CD?N#a~(0kI8IXRF3Po0nIoRjH1|hiaUN{Rp)S(Tq?p|302K zMD0V?Oj0}JkPcY$Rt;6BkgpxoE94kg`%&ud986SN@poPj?G*KBO`P&2d%qdEXBFH>V7u9=aCia(fL(meSNNu9Qq_NQ$0kX`pb#kQ9Vdj zl-f;+T_;j;S6PGT4yrqpfyRz@k~|BL4L=Jfc8Anc=MkA{x({1tH=QCSf@iIGx1n)XthXLzTykM!c7+ z14&el+M2w5tckMJ@({)O*5X6V^>*MwytGv#zl>3@R^U^jVMDI^K1b|I)hi9@{nf=B zN%Q5D^7+;;iEfH|lsYL%d~#-(s7C9^{B`gK1SL~>fG7?dtZY5Ft3HL!>SAp*YS&$USf?tw^ zlbJs$ZLQ-?p^7&T)z_oys49x|p%wCNPzE?w1`M{>)Jbx-ixofs-KMBV+CDt5X75`N z6E9D$Hg}$sPEoHXYj3KF!uQv!Vo5QKx~2A$leGS7m0@!!x+aiT)Ew@GNd{-T1ZM$1O)wr{6qdb}Helt=Yq^@qA zte44j08bAPzZ}jjAurSSK!e`yO)({*9Uzk>YAGGo4Exc&-SxaIJ`=~VFI)C1GmY5h z<*j^a#IdZ_4+4a;%-q|Z#xnXBIxq7cv{#j7hBJOyqOt9xrI|x^)@JgfOMY!;G2(c{ z%aB^&StgS-f341OGbhYVb2aR2W7$&OwMk3z<%v2AYmLH?_fma@vmG+WuIcK{-44KP zy{P}`D^8gO3A>qmXoKE~T5H(?roUI>Zv7`Z2VR4V`hPg6G9-fjvQ?t~dtYZYb6S&N zj1C!`gZh3+k!RXN8^%O?LH|(i{h9AayMqs8vY5y5nW6XAM`TBK|3QBjbHag|5rzwq zt0Jri8?4``m-6=R-x9P-J{X&}dRvrHIQ=7h;evioa(2s9wi3YKGFg{8Rh#|#Awiox zX-YQsgU>8IaAnez&^Q>we%hCp%}%}7<;CoK&isBW`eA@2O)wtVxc>;!U9DSW=BDjG zqN3mR-go5YfltlCnBK|qddcR8rM0OytD#i<~13qbs}4GFMk-u0eMEfcvw5<$Ux7bSJF5Qa+@_m#Mu!&`jDEHtGP7H0 z6>XJ0U08ovlaa>aRa?R@ei)XE@~lI$n>)6-ncw0`XEca3eXY)SF&}(EqMP3=|0~~^ zYjFR9L3p%coOb_Z>#%!!w&nUxQRa|DYtAWwA7iaOnBLQPx#z+#lp7k=MLY3{wbobN zn%Oa7X8YXw8{6faO+$-ivX!+RT3#&~nO|7{ln(XIn4~j~nWiw_YIc$7wb?&Ecff{5 zx$~668NY0dwb78?Q~S8*LY82QEVk#}`qlZUw#LXxz1_?Q)op6$SIn<|wB*qeQxFoj zDOJR)BiDfVx$+atVzGqN_;B{tZ)R$f`|USmL}fPL%OA=yZEEG(=1LbK7eWdZ%s8Ky=eUU z!?U1$BCsQ~@iin~$;izu3Qx|T(qT+9h2x61NPPp^M8HNj9% zp@DeRSvy(u5J*UBIw4$)2ZaRA8+XCr|8CDAl>O2>Jxkr=H|cmFy(7TU-8{mgdM{am-rEmVKc zV!9_CDb4e8pO)`h?PP?MM{eeWZKssw4d`QeH2K+=2vadihj{q9@@ZzFSZf8Lu&Y-% zUE6zU_~9>wDIpW!E$;Ok1liQ3ZQ*+*Ku>S@fhwPD7LS@|&Zmcqsuf2}7o-tJz4@w%~fc3s;d zw#mM{EzP^!W`Dk-#Z?{7$2CaMYjw7>Ii*kRxx7pD9dcex==`> z!(tM#4ee$=IP68K?%mA#N1OdoU)mVWITa~ytVmsz?`TU{dD`uOTcXLj@2NGRrj%M` zU{TGn@{o0_N3hhoKaD$*-t9N-AU83!%0sUm>g%>X{49*2MT%Y1vMn^v^SU3}nuiv} zZ;3cGtKR-xFPWHH4bnRYRfl#$Ju$VIMJGvfuQ_d*MJ=wC>V9oCE&qhe_tbJRAG9hf z)g6qrJgR+bXzzquLUVq)R=+9k$jmva?1pmhTyaaZ|B|5f+N%rsBeO0$8`75PjvNGA z?6*g;bqWo2L#NmBJG2b=Q11hmF6YRGEz6UwSPdmDQCsUM2}v&MX>@KbW|0Pp-{l52 z#$>&iMG3_T#>D-DLi=uc!{i$emFi@1`}13gS;QjYY(D6>__S_Dr2J^Cp^F%$rgjW9wj0}!^+CSzCCD5Ia**C+ z{cJw)h68}u&s{t$HZ=CGVJ2kQ_~?~T)^ zXzl;36MnwflO<|P@4C4imrmDu-L4vn>lizEhPU&X6T1GHnD{Xfp1FnjRq|w6nL` z`QYO6+s54NcM%7#8pH~;Y9|z+_zDYGJP;O|RiSg{Z){j>$a?&)@7iQS#hAfTTavGcE%1fyRrWI#Bs)qd9!j|j`w3$_3wW(@45S| zmM&kfU|rRcfY<6gSM$;30q^q~?C;R>P4&x$k+n2SczfYtg3%QYb>|wj~ksm;QK?xtSBL z15@q@`v@VZgQ*Y|hV%c|iBR$r#^P(nOr{tr_w>Sf)8X8zBOGooa@YZsGh81WSAT}q z>!vGH$^LuQl~lQ-hiG6108%PkuzK&3zUK5Xo-buI2>p6BOU0ff4o6W*Me6z*wy8n4k?& z4LGFvXc?R_mV}A180+m3d~c;~5Gr=n*W=JC@oDEJi>d@L%MjS9Z%d6Ya!jAN+OY{5%){DK-hGYmQ(+-sr!DiW zvpGQyOc55ZBUFZk0az=)LXP)uZ)uR}M+D~C+%V<%b^Bz)z?77OD0b=dCCz1<6STVb zy_p)bZ|n{1{l0e?jv;+|R@=k&Q&RI}!$#!dviZGV9^3~xzRi^56;oy!FvlV9EB*Se zUQ+XB(aG%6(FJa6R*>Th{+;9Igk2v>^U@*5S61eD^iufl8tTn-vwHJ2_}@96SDE8u zvXc$d?yq4cy?wEwd10Ly+WFnxm`YpQs{&VacgsBwV`x$@F5qx-hs)Yl&%_+hB%cCf zAjcz3IsQCmqM;|W`j5$8pl;f!2TI1$`~x`h$WqA;$}?{*~kAgm2}gd95MG9Sz%C zX?oRErY~nNK*n=nt2Qf@hPJ~ruQ)z^IlgMDiSHac*~-ONj!B5cS3j&Z>z;C?gX&I? zclb&%PAM|U@OxqS9(I(*s)~uEf}G(1((m*ji$-XcRD%YaBM~C+n)<-dbfjipwaNk0 z%!eihlyDgs>PiEWgrs|-1Zg4<6Gz2PAbF!Ty~(vv8t=Lihcv_YzBogYB+ZB!12cXf zt*Pm5Vvr`pS)06YuLseO*37SF>PvK0#v=9-90il^V>EMpq!Ee3H%sJ@B*Bto++Z(f zVn0?B=Oa-iZq;FtTar@Aoq^nyRFj8%6{2>M6ce{Asp-nMA*t~iFCU3TT0n}JB&u?O zm+|mMn^Ez-v!jhPQDWGZJWeB5WcBhhy$Q~kpm7tsev>sWhT9V~Rpg4vzH3Zxo|E^% z8$Y+n8Yebp0G@`k*(*nK@rFi+uY9989s4c;3sx(l%TOxZ@O#!O05Jf*AGa{is=OAK zk-}S=Y?3xbqauk-1Llmv zqsVC1*1lFWV}RpkZ7uR5AC8-~rK1d%hr1EhH1n<_^~a?Pe5jA0XEU31RFPN zO9I)rNw~zH3yMhmQX3aQxoq65jS8WmCWR6zJ6cr4Ot93JCP)@DFPSW0ikl3O+UOlr zg2^*$YcUdDuz-1_IC3N3-iMT@Iw({u@|Z`u*P4lrj^cN=qC)U(pA7`sYm>vMhDi`| z>AMr8UN`lnKqr}I2120y$i>T=u?g0|hX3XOKUQWK`v|rG_;WO*A;vxee%*k-w8AmO z*hjDjZ~(wD#Mno`4dMuZV~DYj-~`|-lO?c0Xs`hsbOCS`i40>O!404)0MZa+AHf}< z8UT(V#y)}vfF}TsA;vyJb$}WGI95YeQyjoS{NNFQM06N#Z*(Xr%(o9^VIVPr2EKfR z9ZNDcX(l)){q^IH>kWZ`AI=Jzkxm7F{z!5I(#jZz(G7m`|6!9}j~2f%t&EUKWNXkQ zhIn7qG$ns!LLqUxr?Dk54>XDd42Tq@e+TE^LHTzu{v8Aih`H~vjsBH<{%>D{kH`Gr zWOL_2PF4C(a=a8U6f9+dls!_`;Sb5-pE4=~hW^KRut1U62bvlYQbJ0JCMA%R7gD@& zisVTt0-`7Pp(np=0Z-n2ps`PobdVf`0;Oy9?8pi~gEMAMnPsFl+VH}S!(Gerv94A6Q+C)c;baRY!or#VZ>E<{Q z-;Vp47!V_aIZlMWmx+!T>E<{Q`t~L|Vx*g6q~jR8d5Hf*<&uE?@^H~$#7Hy8NY69T z5hL9kBR$PTM~rlHjPyhk9Wm0)a02tR&cuKi8O$*XkeTR+W!gp-d&9HmzrwNb$cj(l zn_qjg{-AN2!_x0u4G&uJAQXA*ula-`5B8A<=?K`yF{C9R6EfofPDTb4j!Y;VnXr#M zNJkJALPaIT62pKGEdz|>=9n1(!xBciPK&Z#=k$Vawm|rmaU-=Tc)+pA%(~6-`23g1 z`ltxfQ8AdH6*bpsQSnF9eObT3QYS{=7;33S{$G~yY(Dl;aipVsj-0b zxg=hx8sCPvGra(?p5U&;t&ZnZ06-8xBmmBc28dbE<&y@$4!|D3!O-PXm5~P&D*X9C z-X6y`>hC|68TwlUNgS^X<2x%;{9D*2y*K^d@ncbS`~j+3^}#fNSo~H#Bh%5lmWdBl zz{-_mVuL38uxX6lD(THVcIT9l*q16tdo21m13yVAt?!eU8IHAUnWjtPRIogLQ(vi0 zeui{cXZIo5KLOjrt|Na@j| zC?EgH#!GNjAWqxu=;qb4M~{|5gr^bc@JXv|12bzA-7d!lI(wj@+0tbV^&UTVLhOX$ zW5)~}I&sucuo^QW8O9}3|JP+Nhdjsye)y!dl-jr~w!bfn?)iUNHp%3Y|8?1XhaHv6 zN^M*g+iY1sv=-g?zb!i%_%JBMZ;zv=y;%-o5^$vd9>;X95gBJ`-2%QrUJ$+45x@z+ z8Nda=6~GOkDu6pcH2@Do^j^>Fg7|w3$ofDv`^m7Twt{5i~j zNPpEgQYNOqX?mqNQ~=Z8w2Ya!$fZAsGf)45uaY>^bV;136Nob{V=ZUfZ`|KtewW%m<@gkX0L9yqjQbAcWtF4 zmkj!!g}e4&oyTN@@bB$3))s{`>zVMw^Fk!yl6n7CIQY+t&?;`u&`2ZuG98`KATI?o l9;Mltq_GTzBoH&yJW-?!9k{^v=js480K5#oKYPbj{2y^=I1>N> delta 16802 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 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)