From 444a536dad35d4771586c56e5ff53d5b5bbf1880 Mon Sep 17 00:00:00 2001 From: Fenrisul Date: Tue, 20 Jan 2015 00:08:06 -0800 Subject: [PATCH 1/4] Importer improvements Attributes Multiple atlas support More examples --- .../src/Attachments/AtlasAttachmentLoader.cs | 26 +- spine-csharp/src/SkeletonJson.cs | 4 +- .../Scenes/Attributes and AtlasRegions.unity | Bin 0 -> 20844 bytes .../Attributes and AtlasRegions.unity.meta | 4 + .../Examples/Scenes/Mix and Match.unity | Bin 0 -> 18572 bytes .../Examples/Scenes/Mix and Match.unity.meta | 4 + .../Scripts/BasicPlatformerController.cs | 6 + .../Assets/Examples/Scripts/Chimera.cs | 17 + .../Assets/Examples/Scripts/Chimera.cs.meta | 8 + .../Examples/Scripts/FootSoldierExample.cs | 51 + .../Scripts/FootSoldierExample.cs.meta | 8 + .../Spine/Dragon/dragon_SkeletonData.asset | Bin 637 -> 4208 bytes .../Spine/Eyes/eyes_SkeletonData.asset | Bin 4204 -> 4208 bytes .../Assets/Examples/Spine/FootSoldier.meta | 5 + .../Examples/Spine/FootSoldier/Equipment.meta | 5 + .../FootSoldier/Equipment/Equipment.atlas.txt | 34 + .../Equipment/Equipment.atlas.txt.meta | 4 + .../Spine/FootSoldier/Equipment/Equipment.png | Bin 0 -> 40334 bytes .../FootSoldier/Equipment/Equipment.png.meta | 47 + .../Equipment/Equipment_Atlas.asset | Bin 0 -> 4184 bytes .../Equipment/Equipment_Atlas.asset.meta | 4 + .../Equipment/Equipment_Material.mat | Bin 0 -> 4220 bytes .../Equipment/Equipment_Material.mat.meta | 4 + .../Spine/FootSoldier/FS_White.atlas.txt | 90 + .../Spine/FootSoldier/FS_White.atlas.txt.meta | 4 + .../Examples/Spine/FootSoldier/FS_White.png | Bin 0 -> 51842 bytes .../Spine/FootSoldier/FS_White.png.meta | 47 + .../Spine/FootSoldier/FS_White_Atlas.asset | Bin 0 -> 4184 bytes .../FootSoldier/FS_White_Atlas.asset.meta | 4 + .../Spine/FootSoldier/FS_White_Material.mat | Bin 0 -> 4220 bytes .../FootSoldier/FS_White_Material.mat.meta | 4 + .../Spine/FootSoldier/FootSoldier.json | 1754 +++++++++++++++++ .../Spine/FootSoldier/FootSoldier.json.meta | 4 + .../FootSoldier_SkeletonData.asset | Bin 0 -> 4212 bytes .../FootSoldier_SkeletonData.asset.meta | 4 + .../Examples/Spine/FootSoldier/license.txt | 5 + .../Spine/FootSoldier/license.txt.meta | 4 + .../Spine/Goblins/goblins-mesh_Material.mat | Bin 4224 -> 4224 bytes .../Goblins/goblins-mesh_SkeletonData.asset | Bin 4212 -> 4216 bytes spine-unity/Assets/Examples/Spine/Hero.prefab | Bin 9024 -> 9024 bytes .../Spine/Hero/Hero_SkeletonData.asset | Bin 4344 -> 4348 bytes .../Assets/Examples/Spine/Hero/license.txt | 5 + .../Examples/Spine/Hero/license.txt.meta | 4 + .../Examples/Spine/Raptor/raptor_Material.mat | Bin 4216 -> 4216 bytes .../Spine/Raptor/raptor_SkeletonData.asset | Bin 4204 -> 4208 bytes .../Spineboy/spineboy_SkeletonData.asset | Bin 4208 -> 4212 bytes .../Assets/Examples/Spine/dragon.prefab | Bin 9144 -> 9400 bytes .../Assets/spine-unity/AtlasRegionAttacher.cs | 49 + .../spine-unity/AtlasRegionAttacher.cs.meta | 8 + .../spine-unity/Editor/AtlasAssetInspector.cs | 22 +- .../spine-unity/Editor/GUI/icon-slotRoot.png | Bin 0 -> 649 bytes .../Editor/GUI/icon-slotRoot.png.meta | 47 + .../Editor/GUI/icon-subMeshRenderer.png.meta | 14 +- .../spine-unity/Editor/GUI/icon-weights.png | Bin 0 -> 698 bytes .../Editor/GUI/icon-weights.png.meta | 47 + .../Editor/SkeletonDataAssetInspector.cs | 640 +++--- .../Editor/SkeletonRendererInspector.cs | 11 +- .../Editor/SpineAttributeDrawers.cs | 456 +++++ .../Editor/SpineAttributeDrawers.cs.meta | 8 + .../Editor/SpineEditorUtilities.cs | 485 +++-- .../Assets/spine-unity/SkeletonDataAsset.cs | 34 +- .../Assets/spine-unity/SkeletonExtensions.cs | 24 +- .../Assets/spine-unity/SkeletonRenderer.cs | 18 +- .../SkeletonUtilityKinematicShadow.cs | 6 +- .../Assets/spine-unity/SpineAttributes.cs | 111 ++ .../spine-unity/SpineAttributes.cs.meta | 8 + 66 files changed, 3706 insertions(+), 442 deletions(-) create mode 100644 spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity create mode 100644 spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity.meta create mode 100644 spine-unity/Assets/Examples/Scenes/Mix and Match.unity create mode 100644 spine-unity/Assets/Examples/Scenes/Mix and Match.unity.meta create mode 100644 spine-unity/Assets/Examples/Scripts/Chimera.cs create mode 100644 spine-unity/Assets/Examples/Scripts/Chimera.cs.meta create mode 100644 spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs create mode 100644 spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.atlas.txt create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.atlas.txt.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.png create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.png.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Atlas.asset create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Atlas.asset.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset.meta create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/license.txt create mode 100644 spine-unity/Assets/Examples/Spine/FootSoldier/license.txt.meta create mode 100644 spine-unity/Assets/Examples/Spine/Hero/license.txt create mode 100644 spine-unity/Assets/Examples/Spine/Hero/license.txt.meta create mode 100644 spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs create mode 100644 spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs.meta create mode 100644 spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png create mode 100644 spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png.meta create mode 100644 spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png create mode 100644 spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png.meta create mode 100644 spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs create mode 100644 spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs.meta create mode 100644 spine-unity/Assets/spine-unity/SpineAttributes.cs create mode 100644 spine-unity/Assets/spine-unity/SpineAttributes.cs.meta diff --git a/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs b/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs index 37fdbb9fd..4cd6d02af 100644 --- a/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs +++ b/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs @@ -32,15 +32,15 @@ using System; namespace Spine { public class AtlasAttachmentLoader : AttachmentLoader { - private Atlas atlas; + private Atlas[] atlasArray; - public AtlasAttachmentLoader (Atlas atlas) { - if (atlas == null) throw new ArgumentNullException("atlas cannot be null."); - this.atlas = atlas; + public AtlasAttachmentLoader (params Atlas[] atlasArray) { + if (atlasArray == null) throw new ArgumentNullException("atlas array cannot be null."); + this.atlasArray = atlasArray; } public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { - AtlasRegion region = atlas.FindRegion(path); + AtlasRegion region = FindRegion(path); if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")"); RegionAttachment attachment = new RegionAttachment(name); attachment.RendererObject = region; @@ -55,7 +55,7 @@ namespace Spine { } public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { - AtlasRegion region = atlas.FindRegion(path); + AtlasRegion region = FindRegion(path); if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); MeshAttachment attachment = new MeshAttachment(name); attachment.RendererObject = region; @@ -74,7 +74,7 @@ namespace Spine { } public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path) { - AtlasRegion region = atlas.FindRegion(path); + AtlasRegion region = FindRegion(path); if (region == null) throw new Exception("Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")"); SkinnedMeshAttachment attachment = new SkinnedMeshAttachment(name); attachment.RendererObject = region; @@ -95,5 +95,17 @@ namespace Spine { public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { return new BoundingBoxAttachment(name); } + + public AtlasRegion FindRegion(string name) { + AtlasRegion region; + + for (int i = 0; i < atlasArray.Length; i++) { + region = atlasArray[i].FindRegion(name); + if (region != null) + return region; + } + + return null; + } } } diff --git a/spine-csharp/src/SkeletonJson.cs b/spine-csharp/src/SkeletonJson.cs index 77b3d7350..ca9bb6153 100644 --- a/spine-csharp/src/SkeletonJson.cs +++ b/spine-csharp/src/SkeletonJson.cs @@ -42,8 +42,8 @@ namespace Spine { private AttachmentLoader attachmentLoader; public float Scale { get; set; } - public SkeletonJson (Atlas atlas) - : this(new AtlasAttachmentLoader(atlas)) { + public SkeletonJson (params Atlas[] atlasArray) + : this(new AtlasAttachmentLoader(atlasArray)) { } public SkeletonJson (AttachmentLoader attachmentLoader) { diff --git a/spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity b/spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity new file mode 100644 index 0000000000000000000000000000000000000000..eadbc4873f48ce5994ef8c347e10bb2864c072c0 GIT binary patch literal 20844 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 BhDZPa literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity.meta b/spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity.meta new file mode 100644 index 000000000..edbdffa80 --- /dev/null +++ b/spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 63212ccaf5776bd489cba58fb67a2233 +DefaultImporter: + userData: diff --git a/spine-unity/Assets/Examples/Scenes/Mix and Match.unity b/spine-unity/Assets/Examples/Scenes/Mix and Match.unity new file mode 100644 index 0000000000000000000000000000000000000000..06731d193734e3c12f259376965aca7553d6fc76 GIT binary patch literal 18572 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.skeleton.FindSlot(targetSlot).Attachment = SpineAttachment.GetAttachment(attachmentPath, skeletonDataSource); + } +} diff --git a/spine-unity/Assets/Examples/Scripts/Chimera.cs.meta b/spine-unity/Assets/Examples/Scripts/Chimera.cs.meta new file mode 100644 index 000000000..ae5a4019f --- /dev/null +++ b/spine-unity/Assets/Examples/Scripts/Chimera.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5053fe97a7657b5418b0c307b7338b0c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs b/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs new file mode 100644 index 000000000..d85f99847 --- /dev/null +++ b/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs @@ -0,0 +1,51 @@ +using UnityEngine; +using System.Collections; + +public class FootSoldierExample : MonoBehaviour { + [SpineAnimation("Idle")] + public string idleAnimation; + + [SpineAnimation] + public string attackAnimation; + + [SpineSlot] + public string eyesSlot; + + [SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")] + public string eyesOpenAttachment; + + [SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")] + public string blinkAttachment; + + [Range(0, 0.2f)] + public float blinkDuration = 0.05f; + + private SkeletonAnimation skeletonAnimation; + + void Awake() { + skeletonAnimation = GetComponent(); + } + + void Start() { + skeletonAnimation.state.SetAnimation(0, idleAnimation, true); + StartCoroutine("Blink"); + } + + void Update() { + if (Input.GetKey(KeyCode.Space)) { + if (skeletonAnimation.state.GetCurrent(0).Animation.Name != attackAnimation) { + skeletonAnimation.state.SetAnimation(0, attackAnimation, false); + skeletonAnimation.state.AddAnimation(0, idleAnimation, true, 0); + } + } + } + + IEnumerator Blink() { + while (true) { + yield return new WaitForSeconds(Random.Range(0.25f, 3f)); + skeletonAnimation.skeleton.SetAttachment(eyesSlot, blinkAttachment); + yield return new WaitForSeconds(blinkDuration); + skeletonAnimation.skeleton.SetAttachment(eyesSlot, eyesOpenAttachment); + } + } +} diff --git a/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs.meta b/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs.meta new file mode 100644 index 000000000..c82e3bd15 --- /dev/null +++ b/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c826b50b0cfee343be3bdbbf59d0f7c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/Examples/Spine/Dragon/dragon_SkeletonData.asset b/spine-unity/Assets/Examples/Spine/Dragon/dragon_SkeletonData.asset index 8134c651e69208765d816d618357a6112b7a487b..8f43b99b986357ffc52025ba84df9fabf866c23e 100644 GIT binary patch literal 4208 zcmeHKIcyU_6diMha32Xb2_)QLNQe-KV8td5NyuT8P^5|`_Sjxn??$uZkfcfziJlS) zBnm_%AT13vhzgKW(L$FNAyH!fpV?iH?QuuxZ+Yj~_y7CX?%0Ghtq`(jmJqTHMi>a` ziC&L(WxL4VQmGVyH4LRu*KrdpPvq^#+h89XeyP zjJ&s9!$sn1QB`YIzRFtf(AE683=dmsBF(K?f#Io{3~i^Tfm35>yEG7nhf)*TZnZDn z4?v#amXiaJ&Eh%;7SJ}H3&1|I4;9aY3#GhAs zchG>Cg9q2;gbHvg?s-gj(xXEf6bps{ReN+8_QF5`6Vx!w*O4kCxRh51b8kRqOB^FoFhBikUO(HV^>GH4(=s~HJ$RN0B=3L!pYR${HUylKZTiA1bzu(Ba_!|S;h{Grk=C)h+o=x6-oqW66efw$a{g3Lj z{*!r7AhzmNOz&kYJ<@TA7W9?#|%pN2{E_l{nehVu2x GNbDcy6R8LQ literal 637 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 literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png.meta b/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png.meta new file mode 100644 index 000000000..1f7655474 --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ddb89f63d0296cf4f8572b0448bb6b30 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset b/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset new file mode 100644 index 0000000000000000000000000000000000000000..365c78c1fd7524a9fae9997850ad41467fc6c91f GIT binary patch literal 4184 zcmeHK%Wl&^6rBJqk3xa+raZFfx>6BBEKn4;BoIU)5+ETKlu0~ErgH2uo>VOoB1>2x z7O+9;f;~dnu;2r_<{J>=2N0~fAl!$OIEj(?0N*H{*ST}gJ$G!`LQH%W;>bfG#C~X@ z5#sXvmHCC*g80+zb~7-Brn?;Y!J=x&bse;fSd^inX~M$=VWKU>6f`YA)OBCES?ycV zT)A6WRaJXayQ=8PdMNe)gy2!z>zB*cTr0TR2BxrK6>JjtIq)wVRg;ynG|IQUm)Hlc zyWo$8?iu*um;)BIr%Kl;&Td42^+4EXP+8hW1VTb+aS)N=$O8@~-zwuvkK#|TQ{O8w z{^SSgCV(jZ4cSzjF>)A;C_ZX{hO8a9CdP-7lJ!717>j>^G5wuz_yBUf3PB6L zta!?$HLNWf>Ev*Kq}E)%;aVSLB)dg@N)M0Jy{ge`7SrP%rFJOhf!)N^reh#vgf^Di zVV)m~9a^LPIz+q!^3oyZQy(SPjwCfkZVHF4c>a&VPLw#d`2nX;KT~wnW?%uW2f}`} zA&qdQl{9+{r@-QfJ{eYS$&+DNa^a-wnpTF`9cM3gYqLA^8n8PN+cuHi$@nHwf0*5= z1O%07?!MZvP8cdEle9n(?=Py;>6i;nB-ZIn43vou?O2`8CV4hZ5 zYz&AYQOi*=&cR$?;~1@esm_mVfW;AGU814&OwxQ(5sBLN*$Y literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset.meta b/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset.meta new file mode 100644 index 000000000..4b102f19e --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: c574489dd067c2b4cb4dc165a4c410cc +NativeFormatImporter: + userData: diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat b/spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat new file mode 100644 index 0000000000000000000000000000000000000000..b3e55407f94f9d9dc0512a76fbe9048c96c016f4 GIT binary patch literal 4220 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 z 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 C<4zNiycZO6 zHvO}ZrTuHN)5`GcQK6C|%uc}7J68_P<()5I4%;s@S`&6;GfTh_7BjWp9M}8BJlZA| zA;M6TIxv%0EcaI~0c%2h+JlJAyfl`7D^2X!QZflM^GJdYphG}!KAE26WMpJi*HHJ* zMz0VpZm{=rbE1C}wHlcjdvv^mG2Vv;$mgA5zIO=H4S6s^vW+6Dpo-9&R$KZIBn-aC z4B$$pMgj&b5ZMf;1wZb@=L&EbwWcR738JK>>R5k?<*30Cucb_|yjj1x8uyC#)5_O< z?4AiQ>UUSfhKb^njtcxj04q}!B2wZqZ>gs16>|gtW!05^)lR`Y=F26Krpcfc4$8@L znMXIM-1?Nd6y^~-G#fX!x{^Q&6Ld<}SYN+e6^Pk9Dgh-HP*Krl&$HS1-{_FwS41e4 zAgwLFYO_QN&@$7Y`G$gspkq4)8B)qW&QC5L<@uJnbRp&c6p`RizL3A9MK0<(zF)Dp zkLyMs7lINfkz0|+7T<9nrW{NwB*7spMZ@~^SQCRvo!$8|0b58#E5Ae2KMMfd8`atP z#?uXN;!m}N?9DU<6%~eOM$B5Qwkjp)i)hICpH}KrM2g?CQhC4x8r)p4X6q9~k3;&! zBHet#>E^GH@>6r$;&%%2j8(1zT7cf64CnhvokBS4Bho$KHxs2@K|Y1^IiBq@b&9*^&TS2{XM4F@9@3M}Mo2gx#$*_6<34ohGrZrNf5G4>}D zQdCP6C6`byStce&7Y2UH|9#-)===Q1tm *9|^aH_;2OZWmw^^Q824iJ+dKgU}1| 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 literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat.meta b/spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat.meta new file mode 100644 index 000000000..146d15988 --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 5a3598dafa118754db95756064347da7 +NativeFormatImporter: + userData: diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json b/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json new file mode 100644 index 000000000..75e7be0bb --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json @@ -0,0 +1,1754 @@ +{ +"skeleton": { "hash": "uZfvh80BNvvngM3EGMfAkHebg00", "spine": "2.1.08", "width": 147.68, "height": 268.92, "images": "./images/" }, +"bones": [ + { "name": "Root" }, + { "name": "Hip", "parent": "Root", "x": -0.93, "y": 73.4 }, + { "name": "Body", "parent": "Hip", "length": 60.98, "x": 2.46, "y": -7.69, "rotation": 89.52 }, + { "name": "Leg", "parent": "Hip", "length": 31.39, "x": -20.32, "y": -13.85, "rotation": -105.82 }, + { "name": "Leg2", "parent": "Hip", "length": 31.09, "x": 22.48, "y": -12.01, "rotation": -74.17 }, + { "name": "Arm", "parent": "Body", "length": 51.63, "x": 49.91, "y": 37.35, "rotation": 166.67 }, + { "name": "Arm2", "parent": "Body", "length": 52.61, "x": 53.81, "y": -28.52, "rotation": -157.17 }, + { "name": "Feet", "parent": "Leg", "length": 15.4, "x": 39.56, "y": 1.59, "rotation": 14.56 }, + { "name": "Feet2", "parent": "Leg2", "length": 12.32, "x": 41.33, "y": 0.12, "rotation": -17.19 }, + { "name": "Head", "parent": "Body", "length": 65.29, "x": 73.6, "y": 1.09, "rotation": -88.23 }, + { "name": "Shield", "parent": "Arm", "x": 45.01, "y": -2.1, "rotation": 123.56 }, + { "name": "Weapon", "parent": "Arm2", "length": 137.65, "x": 48.2, "y": 12.78, "rotation": 92.5 } +], +"slots": [ + { "name": "Arm2", "bone": "Arm2", "attachment": "Arm2" }, + { "name": "Weapon", "bone": "Weapon" }, + { "name": "Hand", "bone": "Arm2", "attachment": "Hand" }, + { "name": "Leg2", "bone": "Leg2", "attachment": "Leg2" }, + { "name": "Feet2", "bone": "Feet2", "attachment": "Feet2" }, + { "name": "Leg", "bone": "Leg", "attachment": "Leg" }, + { "name": "Feet", "bone": "Feet", "attachment": "Feet" }, + { "name": "Body", "bone": "Body", "attachment": "body" }, + { "name": "Arm", "bone": "Arm", "attachment": "Arm" }, + { "name": "Head", "bone": "Head", "attachment": "Head" }, + { "name": "Eyes", "bone": "Head", "attachment": "Open" }, + { "name": "Shield", "bone": "Shield" }, + { "name": "Mouth", "bone": "Head", "attachment": "Closed" } +], +"skins": { + "default": {}, + "White": { + "Arm": { + "Arm": { "name": "arm", "path": "White/arm", "x": 21.18, "y": 21.04, "rotation": 109.17, "width": 111, "height": 98 } + }, + "Arm2": { + "Arm2": { "name": "arm 2", "path": "White/arm 2", "x": 23.03, "y": -1.29, "rotation": 78.03, "width": 46, "height": 79 } + }, + "Body": { + "body": { "path": "White/body", "x": 23.73, "y": 7.21, "rotation": -89.52, "width": 91, "height": 103 } + }, + "Eyes": { + "Blink": { "path": "White/eyes blink", "x": 10.41, "y": 31.16, "rotation": -1.13, "width": 67, "height": 22 }, + "Open": { "path": "White/eyes", "x": 11.07, "y": 26.12, "rotation": -4.55, "width": 67, "height": 31 } + }, + "Feet": { + "Feet": { "name": "feet", "path": "White/feet", "x": 6.08, "y": -1.36, "rotation": 91.26, "width": 50, "height": 32 } + }, + "Feet2": { + "Feet2": { "name": "feet 2", "path": "White/feet 2", "x": 4.26, "y": -4.34, "rotation": 91.37, "width": 55, "height": 27 } + }, + "Hand": { + "Hand": { "name": "hand", "path": "White/hand", "x": 49.06, "y": 2.06, "rotation": 67.64, "width": 32, "height": 28 } + }, + "Head": { + "Head": { "name": "head 1", "path": "White/head 1", "x": -3.5, "y": 58.44, "rotation": -2.76, "width": 139, "height": 137 } + }, + "Leg": { + "Leg": { "name": "leg", "path": "White/leg", "x": 16.86, "y": -4.3, "rotation": 104.82, "width": 48, "height": 55 } + }, + "Leg2": { + "Leg2": { "name": "leg 2", "path": "White/leg 2", "x": 16.44, "y": -2.11, "rotation": 74.17, "width": 50, "height": 58 } + }, + "Mouth": { + "Closed": { "path": "White/mouth", "x": 10.96, "y": 3.69, "rotation": -1.29, "width": 28, "height": 21 } + } + } +}, +"events": { + "Hit": {} +}, +"animations": { + "Attack": { + "bones": { + "Arm": { + "rotate": [ + { + "time": 0, + "angle": -10.02, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "angle": -50.06 }, + { "time": 0.4, "angle": -15.89 }, + { "time": 0.4666, "angle": -29.45, "curve": "stepped" }, + { + "time": 0.6, + "angle": -29.45, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "angle": -10.02 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "x": 2.53, "y": -1.01 }, + { "time": 0.4666, "x": -5.05, "y": -2.57, "curve": "stepped" }, + { + "time": 0.6, + "x": -5.05, + "y": -2.57, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Root": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Hip": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.3333, "angle": 0, "curve": "stepped" }, + { "time": 0.8333, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, + { "time": 0.3333, "x": 0, "y": 0 }, + { "time": 0.4666, "x": 9.25, "y": -5.94, "curve": "stepped" }, + { + "time": 0.6, + "x": 9.25, + "y": -5.94, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Body": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "angle": 8.25 }, + { "time": 0.4666, "angle": -15.92, "curve": "stepped" }, + { + "time": 0.6, + "angle": -15.92, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "x": -1.07, "y": 3.56 }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Leg": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.3333, "angle": 0 }, + { "time": 0.4666, "angle": -18.61, "curve": "stepped" }, + { + "time": 0.6, + "angle": -18.61, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, + { "time": 0.3333, "x": 0, "y": 0, "curve": "stepped" }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Leg2": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "angle": 15.02 }, + { "time": 0.4666, "angle": 4.71, "curve": "stepped" }, + { + "time": 0.6, + "angle": 4.71, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "x": -2.61, "y": 4.37 }, + { "time": 0.4666, "x": 5.74, "y": 4.37, "curve": "stepped" }, + { + "time": 0.6, + "x": 5.74, + "y": 4.37, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Arm2": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "angle": 148.07 }, + { "time": 0.4666, "angle": 335.98, "curve": "stepped" }, + { + "time": 0.6, + "angle": 335.98, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "x": 4.5, "y": -0.72 }, + { "time": 0.4666, "x": -1.04, "y": -2.35, "curve": "stepped" }, + { + "time": 0.6, + "x": -1.04, + "y": -2.35, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Feet": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.3333, "angle": 0 }, + { "time": 0.4666, "angle": 18.36, "curve": "stepped" }, + { + "time": 0.6, + "angle": 18.36, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, + { "time": 0.3333, "x": 0, "y": 0 }, + { "time": 0.4666, "x": -1.43, "y": 2.2, "curve": "stepped" }, + { + "time": 0.6, + "x": -1.43, + "y": 2.2, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Feet2": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.3333, "angle": 0 }, + { "time": 0.4666, "angle": -2.99, "curve": "stepped" }, + { + "time": 0.6, + "angle": -2.99, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8333, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, + { "time": 0.3333, "x": 0, "y": 0, "curve": "stepped" }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Head": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "angle": 19.17 }, + { "time": 0.4666, "angle": -2.33 }, + { "time": 0.8333, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.3333, "x": -1.36, "y": -0.46 }, + { "time": 0.8333, "x": 0, "y": 0 } + ] + }, + "Weapon": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + } + }, + "events": [ + { "time": 0.4333, "name": "Hit" } + ] + }, + "DeathBackward": { + "bones": { + "Root": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Hip": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.3333, "angle": 87.75 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { "time": 0.2, "x": -50.02, "y": -6.59 }, + { "time": 0.3333, "x": -83.36, "y": -37.67 } + ] + }, + "Body": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { "time": 0.3333, "x": 5.06, "y": -0.04 } + ] + }, + "Leg": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.3333, "angle": 33.36 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Leg2": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.3333, "angle": -48.11 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Arm": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.3333, "angle": -346.22 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { "time": 0.3333, "x": -4.06, "y": -12.11 } + ] + }, + "Arm2": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.3333, "angle": 278.31 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Feet": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.3333, "angle": -46.46 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Feet2": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Head": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.3333, "angle": 17.02 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { "time": 0.3333, "x": -3.67, "y": -21.86 } + ] + }, + "Weapon": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.3333, "angle": -38.52 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + } + } + }, + "DeathForward": { + "bones": { + "Root": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Hip": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": -87.3 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.243, 0, 0.638, 0.47 ] + }, + { + "time": 0.2, + "x": 36.63, + "y": 0.08, + "curve": [ 0.386, 0.35, 0.748, 0.73 ] + }, + { "time": 0.3333, "x": 74.83, "y": -43.12 } + ] + }, + "Body": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Leg": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": 52.39 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "x": -4.47, "y": 3.29 } + ] + }, + "Leg2": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": -34.64 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Arm": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": -306.5 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { "time": 0.3333, "x": -2.42, "y": -20.41 } + ] + }, + "Arm2": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": 160 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { "time": 0.3333, "x": -0.79, "y": 16.15 } + ] + }, + "Feet": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": -19.93 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "x": -0.19, "y": -2.03 } + ] + }, + "Feet2": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": 30.89 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Head": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": 47.13 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Weapon": { + "rotate": [ + { + "time": 0, + "angle": 0, + "curve": [ 0.25, 0, 0.758, 0.67 ] + }, + { "time": 0.3333, "angle": 43.72 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + } + } + }, + "Idle": { + "bones": { + "Body": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5, + "x": 0, + "y": -3.51, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 1, "x": 0, "y": 0 } + ] + }, + "Head": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -1.03, + "y": 0, + "curve": [ 0.212, 0.29, 0.75, 1 ] + }, + { + "time": 0.1333, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.6333, + "x": -1.75, + "y": -0.01, + "curve": [ 0.25, 0, 0.755, 0.68 ] + }, + { "time": 1, "x": -1.03, "y": 0 } + ] + }, + "Arm": { + "rotate": [ + { + "time": 0, + "angle": -10.63, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { + "time": 0.3666, + "angle": -13.14, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8666, "angle": -10 }, + { "time": 1, "angle": -10.63 } + ], + "translate": [ + { + "time": 0, + "x": -0.44, + "y": 0, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { + "time": 0.3666, + "x": -2.17, + "y": -0.01, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8666, "x": 0, "y": 0 }, + { "time": 1, "x": -0.44, "y": 0 } + ] + }, + "Arm2": { + "rotate": [ + { + "time": 0, + "angle": -0.47, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { + "time": 0.3666, + "angle": -2.34, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8666, "angle": 0 }, + { "time": 1, "angle": -0.47 } + ], + "translate": [ + { + "time": 0, + "x": -0.46, + "y": 0, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { + "time": 0.3666, + "x": -2.29, + "y": -0.01, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.8666, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 1, "x": -0.46, "y": 0 } + ] + }, + "Leg": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": -0.26, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { "time": 0.1, "x": 0, "y": 0 }, + { + "time": 0.6, + "x": 0, + "y": -2.03, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": 0, "y": -0.26 } + ] + }, + "Feet": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -0.25, + "y": -0.07, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { + "time": 0.1, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.6, + "x": -1.95, + "y": -0.55, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": -0.25, "y": -0.07 } + ] + }, + "Leg2": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": -0.33, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { "time": 0.1, "x": 0, "y": 0 }, + { + "time": 0.6, + "x": 0, + "y": -2.54, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": 0, "y": -0.33 } + ] + }, + "Feet2": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -0.31, + "y": 0.09, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { + "time": 0.1, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.6, + "x": -2.44, + "y": 0.69, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": -0.31, "y": 0.09 } + ] + }, + "Root": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Hip": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Weapon": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + } + } + }, + "Idle2": { + "bones": { + "Body": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5, + "x": 0, + "y": -3.51, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 1, "x": 0, "y": 0 } + ] + }, + "Head": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.1666, "angle": 22.27, "curve": "stepped" }, + { "time": 0.7333, "angle": 22.27 }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -1.03, + "y": 0, + "curve": [ 0.212, 0.29, 0.75, 1 ] + }, + { + "time": 0.1333, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.4, + "x": -1.75, + "y": -0.01, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 1, "x": -1.03, "y": 0 } + ] + }, + "Arm": { + "rotate": [ + { + "time": 0, + "angle": -10.63, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { + "time": 0.3666, + "angle": -13.14, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8666, "angle": -10 }, + { "time": 1, "angle": -10.63 } + ], + "translate": [ + { + "time": 0, + "x": -0.44, + "y": 0, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { + "time": 0.3666, + "x": -2.17, + "y": -0.01, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8666, "x": 0, "y": 0 }, + { "time": 1, "x": -0.44, "y": 0 } + ] + }, + "Arm2": { + "rotate": [ + { + "time": 0, + "angle": -0.47, + "curve": [ 0.315, 0.27, 0.661, 0.65 ] + }, + { "time": 0.1666, "angle": 79.53, "curve": "stepped" }, + { + "time": 0.7333, + "angle": 79.53, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { "time": 0.9666, "angle": -0.47, "curve": "stepped" }, + { "time": 1, "angle": -0.47 } + ], + "translate": [ + { "time": 0, "x": -0.46, "y": 0, "curve": "stepped" }, + { "time": 1, "x": -0.46, "y": 0 } + ] + }, + "Leg": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": -0.26, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { "time": 0.1, "x": 0, "y": 0 }, + { + "time": 0.6, + "x": 0, + "y": -2.03, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": 0, "y": -0.26 } + ] + }, + "Feet": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -0.25, + "y": -0.07, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { + "time": 0.1, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.6, + "x": -1.95, + "y": -0.55, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": -0.25, "y": -0.07 } + ] + }, + "Leg2": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": -0.33, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { "time": 0.1, "x": 0, "y": 0 }, + { + "time": 0.6, + "x": 0, + "y": -2.54, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": 0, "y": -0.33 } + ] + }, + "Feet2": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -0.31, + "y": 0.09, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { + "time": 0.1, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.6, + "x": -2.44, + "y": 0.69, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": -0.31, "y": 0.09 } + ] + }, + "Root": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Hip": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Weapon": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.1666, "angle": -15.07, "curve": "stepped" }, + { "time": 0.7333, "angle": -15.07 }, + { "time": 0.9666, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + } + } + }, + "Idle3": { + "bones": { + "Body": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5, + "x": 0, + "y": -3.51, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 1, "x": 0, "y": 0 } + ] + }, + "Head": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -1.03, + "y": 0, + "curve": [ 0.212, 0.29, 0.75, 1 ] + }, + { + "time": 0.1333, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.6333, + "x": -1.75, + "y": -0.01, + "curve": [ 0.25, 0, 0.755, 0.68 ] + }, + { "time": 1, "x": -1.03, "y": 0 } + ] + }, + "Arm": { + "rotate": [ + { + "time": 0, + "angle": -10.63, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { + "time": 0.3666, + "angle": -13.14, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8666, "angle": -10 }, + { "time": 1, "angle": -10.63 } + ], + "translate": [ + { + "time": 0, + "x": -0.44, + "y": 0, + "curve": [ 0.337, 0.34, 0.757, 1 ] + }, + { + "time": 0.3666, + "x": -2.17, + "y": -0.01, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.8666, "x": 0, "y": 0 }, + { "time": 1, "x": -0.44, "y": 0 } + ] + }, + "Arm2": { + "rotate": [ + { + "time": 0, + "angle": -0.47, + "curve": [ 0.322, 0.29, 0.658, 0.63 ] + }, + { + "time": 0.1666, + "angle": 322.37, + "curve": [ 0.339, 0.35, 0.673, 0.68 ] + }, + { + "time": 0.2666, + "angle": 335.29, + "curve": [ 0.336, 0.34, 0.67, 0.67 ] + }, + { + "time": 0.3666, + "angle": 322.1, + "curve": [ 0.381, 0.58, 0.729, 1 ] + }, + { + "time": 0.4666, + "angle": 331.22, + "curve": [ 0.333, 0.33, 0.667, 0.66 ] + }, + { + "time": 0.5666, + "angle": 322.25, + "curve": [ 0.33, 0.32, 0.664, 0.66 ] + }, + { + "time": 0.6666, + "angle": 322.37, + "curve": [ 0.386, 0, 0.755, 1 ] + }, + { "time": 1, "angle": -0.47 } + ], + "translate": [ + { + "time": 0, + "x": -0.46, + "y": 0, + "curve": [ 0.322, 0.29, 0.658, 0.63 ] + }, + { + "time": 0.1666, + "x": -12.22, + "y": -0.1, + "curve": [ 0.332, 0.33, 0.682, 0.71 ] + }, + { + "time": 0.4333, + "x": -10.84, + "y": -0.08, + "curve": [ 0.381, 0.58, 0.729, 1 ] + }, + { + "time": 0.6666, + "x": -12.22, + "y": -0.1, + "curve": [ 0.361, 0.43, 0.755, 1 ] + }, + { "time": 1, "x": -0.46, "y": 0 } + ] + }, + "Leg": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": -0.26, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { "time": 0.1, "x": 0, "y": 0 }, + { + "time": 0.6, + "x": 0, + "y": -2.03, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": 0, "y": -0.26 } + ] + }, + "Feet": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -0.25, + "y": -0.07, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { + "time": 0.1, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.6, + "x": -1.95, + "y": -0.55, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": -0.25, "y": -0.07 } + ] + }, + "Leg2": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": -0.33, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { "time": 0.1, "x": 0, "y": 0 }, + { + "time": 0.6, + "x": 0, + "y": -2.54, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": 0, "y": -0.33 } + ] + }, + "Feet2": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.1, "angle": 0, "curve": "stepped" }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { + "time": 0, + "x": -0.31, + "y": 0.09, + "curve": [ 0.374, 0.61, 0.715, 1 ] + }, + { + "time": 0.1, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.6, + "x": -2.44, + "y": 0.69, + "curve": [ 0.242, 0, 0.679, 0.71 ] + }, + { "time": 1, "x": -0.31, "y": 0.09 } + ] + }, + "Root": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Hip": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Weapon": { + "rotate": [ + { "time": 0, "angle": 0 }, + { "time": 0.1666, "angle": -7.41, "curve": "stepped" }, + { "time": 0.6666, "angle": -7.41 }, + { "time": 1, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, + { "time": 1, "x": 0, "y": 0 } + ] + } + } + }, + "Move": { + "bones": { + "Arm": { + "rotate": [ + { + "time": 0, + "angle": -345.33, + "curve": [ 0.235, 0.29, 0.75, 1 ] + }, + { + "time": 0.2, + "angle": -8.71, + "curve": [ 0.25, 0, 0.592, 1 ] + }, + { + "time": 0.5333, + "angle": -338.66, + "curve": [ 0.25, 0, 0.715, 0.63 ] + }, + { "time": 0.6666, "angle": -345.33 } + ], + "translate": [ + { + "time": 0, + "x": -2.81, + "y": -0.06, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.2, + "x": -0.69, + "y": -0.92, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.3333, + "x": -2.81, + "y": -0.06, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5333, + "x": 0.36, + "y": 0.38, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "x": -2.81, "y": -0.06 } + ] + }, + "Leg": { + "rotate": [ + { + "time": 0, + "angle": 26.56, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.2, + "angle": 52.94, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5333, + "angle": -1.83, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "angle": 26.56 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.2, + "x": 19.08, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "x": 0, "y": 0 } + ] + }, + "Leg2": { + "rotate": [ + { + "time": 0, + "angle": -33.11, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.2, + "angle": -49.48, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5333, + "angle": -1.66, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "angle": -33.11 } + ], + "translate": [ + { + "time": 0, + "x": 0, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.2, + "x": -22.21, + "y": 0, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.4, + "x": -11.24, + "y": 6.26, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "x": 0, "y": 0 } + ] + }, + "Feet": { + "rotate": [ + { + "time": 0, + "angle": -23.86, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.2, + "angle": -51.25, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.3333, + "angle": -29.88, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.4333, + "angle": -14.06, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5333, + "angle": -18.03, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "angle": -23.48 } + ], + "translate": [ + { + "time": 0, + "x": -0.84, + "y": -4.45, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.2, "x": -1.03, "y": -4.7, "curve": "stepped" }, + { + "time": 0.5333, + "x": -1.03, + "y": -4.7, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "x": -0.84, "y": -4.45 } + ] + }, + "Feet2": { + "rotate": [ + { + "time": 0, + "angle": 33.53, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.2, + "angle": 9.39, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5333, + "angle": 14.85, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "angle": 33.53 } + ], + "translate": [ + { + "time": 0, + "x": -0.98, + "y": 3.98, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.2, + "x": 0.28, + "y": -0.42, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5333, + "x": 0.31, + "y": 2.54, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { "time": 0.6666, "x": -0.98, "y": 3.98 } + ] + }, + "Hip": { + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { "time": 0.2, "x": 0, "y": 3.84 }, + { "time": 0.3333, "x": 0, "y": 0 }, + { "time": 0.5333, "x": 0, "y": 3.84 }, + { "time": 0.6666, "x": 0, "y": 0 } + ] + }, + "Head": { + "rotate": [ + { "time": 0, "angle": 6.58 } + ], + "translate": [ + { "time": 0, "x": 0.95, "y": 0 }, + { "time": 0.0666, "x": 0, "y": 0 }, + { "time": 0.2666, "x": 1.91, "y": 0.01 }, + { "time": 0.4, "x": 0, "y": 0 }, + { "time": 0.6, "x": 1.91, "y": 0.01 }, + { "time": 0.6666, "x": 0.95, "y": 0 } + ] + }, + "Arm2": { + "rotate": [ + { + "time": 0, + "angle": -5.89, + "curve": [ 0.244, 0.31, 0.75, 1 ] + }, + { + "time": 0.2, + "angle": 4.17, + "curve": [ 0.25, 0, 0.75, 1 ] + }, + { + "time": 0.5333, + "angle": -10.86, + "curve": [ 0.25, 0, 0.781, 0.72 ] + }, + { "time": 0.6666, "angle": -5.89 } + ] + }, + "Body": { + "rotate": [ + { "time": 0, "angle": -5.26 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 2.51 }, + { "time": 0.0666, "x": 0, "y": 0 }, + { "time": 0.2666, "x": 0, "y": 3.02 }, + { "time": 0.4, "x": 0, "y": 0 }, + { "time": 0.6, "x": 0, "y": 5.03 }, + { "time": 0.6666, "x": 0, "y": 2.51 } + ] + } + } + }, + "Parried": { + "bones": { + "Arm": { + "rotate": [ + { "time": 0, "angle": -22.67 }, + { "time": 0.1, "angle": -46.87 }, + { "time": 0.2333, "angle": -5.32 }, + { "time": 0.4, "angle": -10.02 } + ], + "translate": [ + { "time": 0, "x": -3.15, "y": -2.18 }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Root": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + }, + "Hip": { + "rotate": [ + { "time": 0, "angle": 0, "curve": "stepped" }, + { "time": 0.4, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 6.94, "y": -4.46 }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Body": { + "rotate": [ + { "time": 0, "angle": -9.88 }, + { "time": 0.1, "angle": 7.82 }, + { "time": 0.4, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": -0.86, "y": 2.85 }, + { "time": 0.1, "x": -3.19, "y": 2.13 }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Leg": { + "rotate": [ + { "time": 0, "angle": -13.95 }, + { "time": 0.4, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Leg2": { + "rotate": [ + { "time": 0, "angle": 7.29 }, + { "time": 0.1, "angle": 19.32 }, + { "time": 0.4, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 3.65, "y": 4.37 }, + { "time": 0.1, "x": -3.88, "y": 5.46 }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Arm2": { + "rotate": [ + { "time": 0, "angle": 19 }, + { "time": 0.1, "angle": 88.31 }, + { "time": 0.4, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0.34, "y": -1.94 }, + { "time": 0.1, "x": -1.61, "y": 3.91 }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Feet": { + "rotate": [ + { "time": 0, "angle": 13.77 }, + { "time": 0.4, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": -1.07, "y": 1.65 }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Feet2": { + "rotate": [ + { "time": 0, "angle": -2.24 }, + { "time": 0.1, "angle": 3.22 }, + { "time": 0.4, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 }, + { "time": 0.1, "x": -1.56, "y": 1.1 }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Head": { + "rotate": [ + { "time": 0, "angle": 3.04 }, + { "time": 0.1, "angle": 11.84 }, + { "time": 0.4, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": -1.08, "y": -0.37 }, + { "time": 0.4, "x": 0, "y": 0 } + ] + }, + "Weapon": { + "rotate": [ + { "time": 0, "angle": 0 } + ], + "translate": [ + { "time": 0, "x": 0, "y": 0 } + ] + } + } + } +} +} \ No newline at end of file diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json.meta b/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json.meta new file mode 100644 index 000000000..208bf85c4 --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: b075ad1d14f5db64b941d266e53de57d +TextScriptImporter: + userData: diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset b/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset new file mode 100644 index 0000000000000000000000000000000000000000..2328d3451c488a7207d556d82db097ea00b014b8 GIT binary patch literal 4212 zcmeHK%TE(Q7@zt?@Gat7Q1C4%NPI+WD9}n#pr#maG(&d^i`!i@I}k9&aPYv*gGVl2 zHSuxrXuNpTgYiIOJb3Xh@NWISnceNQo!&fln(oXu`}@A%_u9^ukfzs!>=uNOZ7{<` zNPo}Op58()`CBTLVj#m*8uwgph|SSO+gspdi26)!OFUcy>Jsp2*P!K zj&fpALFMi~+=8JaB40XQd?2#%CE9_`!%z%L4$W~x{+XA z>D>VXVi6u(j}t1ut%UD0;Y*JWYEUc~22}0QA=rxo1x#4OC|`%GjG!pnqAL;6#Z~gK z)sIxcLwm)X_P8I_K(XKfsp*Mh29P42VoO4X87KZj<}l&8W7)|G*^|dLE!;5jw`-uf z{2c~R!SSddex5q2nNDaJNe^;Ri~{$H3D+)C0l$y394B?~s<|AUfQiZhn9%*G99_DR zAay}=$_B<~;FON3Lv&grij5kG&S*x$994GWSpy;nUU-$EpVOeEjz{M;j}TK6`UTxc zlM<>!zo=vC5Or%r#?X5-Bj(UA84y9})&eh={IZ6t_XPH8?&uvGmAtRY2#Tr^WySGW zyiy+mhw_3W#_c8f>(_4p;uiMY;GZ}0F1}-68*!NB!Q6iH&f3(CSIM{U`)<8xyZ1?* z*6}A#pAG*U9eRH4L-X(S{3_Oqkd_BOz9n)WQ){i=h3W6p>k2DxH7<<|G&0c0KqCW< z3^X$EA2Wc5Hx8VCEx#l9-kkHX Kh2!g&yYYW{b*J6{ literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset.meta b/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset.meta new file mode 100644 index 000000000..64306fba7 --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: e57cdb51287d3924ebb2ececf816733b +NativeFormatImporter: + userData: diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/license.txt b/spine-unity/Assets/Examples/Spine/FootSoldier/license.txt new file mode 100644 index 000000000..d7d03d722 --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/FootSoldier/license.txt @@ -0,0 +1,5 @@ +Copyright (c) 2014, XDTech + +The project file and images in this "FootSoldier" project are provided for +demonstration purposes only and may not be redistributed for any reason nor +used as the basis for derivative work. \ No newline at end of file diff --git a/spine-unity/Assets/Examples/Spine/FootSoldier/license.txt.meta b/spine-unity/Assets/Examples/Spine/FootSoldier/license.txt.meta new file mode 100644 index 000000000..aa07eb919 --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/FootSoldier/license.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 6fe8b327d2ab4bd438a63ffec150a911 +TextScriptImporter: + userData: diff --git a/spine-unity/Assets/Examples/Spine/Goblins/goblins-mesh_Material.mat b/spine-unity/Assets/Examples/Spine/Goblins/goblins-mesh_Material.mat index 9a65bc515b57e0874914918e32e4afc0e8ea0f9d..e98d762ed47aad1771726a6dc48a36a359bbb1d2 100644 GIT binary patch delta 14 VcmZorY*3sa#%!i%xKT1)0015o1Hu3R delta 14 VcmZorY*3sa#%!u*vQaW!0015w1H=FT diff --git a/spine-unity/Assets/Examples/Spine/Goblins/goblins-mesh_SkeletonData.asset b/spine-unity/Assets/Examples/Spine/Goblins/goblins-mesh_SkeletonData.asset index 72b2e4c4fa64e75346c3c009ff3525b483a1c60c..e443663b9a557cc4d94079c6bceab5f46cffa3ed 100644 GIT binary patch delta 271 zcmeyO@Iyh8fq`Qc1A{;X0|NsmkOoo=3?_PJdWIV%Sy&{>Qj<&aix?71auSOji;GiB ziW&X`fy88Ac4bD%$%X6+T2f#w3=E7QnghZK2q-DCQE`OpvSUa|EJ>WalO=ib92O-; zxykk{Dva`zQ-GwxWKLFPM#agxtU8kqu^LS7WEEvpnLHmTraE~an=+%?2P2S4}QKb!5r2|%_3s$8ER;3SAB{kWeotM!7>`X(DGZ~F0PhwYMG@iVb dU4zkN@;#vQD>gH6Y+#=(BVfYFIN4V~9RTfVLL2}9 delta 240 zcmeyN@I^tAfq}z;fkB{zfq{V&NCPPb1`|DFJ(G=+EG$X^0VPE?Dvl*NiN%h^#i=EB z42f_y0|!v4#N?GMDvXko&jCrP$)8zFC$C_Mo7~1Kz$iC)I;#$&{N(*?%8Uw=U$81n zp2jLNS%ytu@?lnk$uVrAlR4OUCRebFF{)1PXP271j!l434Xj!nq?%D8FeRbXIEy_n|zyHfl+_5Jckr#Vo4$c3(z$NK%NGp;badEWyX@t VIUF0;z?v8s7(p}#gcA@@Qe>mz2-juDkdj!EIC&>a^5i)z zN{n)o?O9Y9~tPtV$QGN)N0`AE-)dvOPO5qXF2Nh9GA$8cm+WuEc0O fc`LgHqsioZKN|8lmY@uifmLIOL7v69gB-o zOY9gD;cNyDpkj&1D_K++B`2Q)l2VgDvzSg^!4fyQja7hAZt`?i9Y*=d``MHk6(+x6 zRhT@DRb;XZo51A5tOk=~*hD9Du<=Z;U>9Rlo!rkZHF+JI0HYdMwK_;OqsC-THs#6t z*uZKTwI}DYD>CW;RjM=UPTtP0%&0f{HoF3&{$zO$DbB=_L!fg@|OjDXH$AAt=3D!xA` diff --git a/spine-unity/Assets/Examples/Spine/Hero/license.txt b/spine-unity/Assets/Examples/Spine/Hero/license.txt new file mode 100644 index 000000000..86fb7fa08 --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/Hero/license.txt @@ -0,0 +1,5 @@ +Copyright (c) 2014, XDTech + +The project file and images in this "Hero" project are provided for +demonstration purposes only and may not be redistributed for any reason nor +used as the basis for derivative work. \ No newline at end of file diff --git a/spine-unity/Assets/Examples/Spine/Hero/license.txt.meta b/spine-unity/Assets/Examples/Spine/Hero/license.txt.meta new file mode 100644 index 000000000..7f70f6011 --- /dev/null +++ b/spine-unity/Assets/Examples/Spine/Hero/license.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 0d9db1748e0cf9f408129df308299463 +TextScriptImporter: + userData: diff --git a/spine-unity/Assets/Examples/Spine/Raptor/raptor_Material.mat b/spine-unity/Assets/Examples/Spine/Raptor/raptor_Material.mat index 658e3cae160d632901d2183a89ddfa6b4fa3e4eb..bba7fb8759108bcc81c51755ce355b8ea3cca080 100644 GIT binary patch delta 14 VcmeyN@IzsO7_*t4;YP`L0RSo-1gHQ2 delta 14 VcmeyN@IzsO7_+IK$wtX|0RSo_1gZc4 diff --git a/spine-unity/Assets/Examples/Spine/Raptor/raptor_SkeletonData.asset b/spine-unity/Assets/Examples/Spine/Raptor/raptor_SkeletonData.asset index d6633bb0ee091a9ab61139fc35c23ff32890d752..64a8d0ed413b7bd7222c98fe57b19a6f00b5c1c1 100644 GIT binary patch delta 271 zcmaE(@IgV6fq`Qc1A{;T0|NsmkOoo=3?_PJdWIV%Sy&{>Qj<&aix?71auSOji;GiB ziW&X`fy88Ac4bD%$%X6+T2f#w3=E7QnghZK2q-DCQE`OpvSUa|EJ>WalO=ib92O-; zxykk{Dva`zQ-GwxWKLFPM#agxtU8kqu^LS7WEEvpnLHmTraE~an=+%?2P2S4}QKb!5r2|%_3s$8ER;3SAB{kWeotM!7>`X(DGZ~F0PhwYMG@iVb dU4zkN@;#vQ3pO)xY+#=(BcQ{`IN4P|9RSmzLF@nk delta 240 zcmeyM@J2zBfq}z;fk7aLfq{V&NCPPb1`|DFJ(G=+EG$X^0VPE?Dvl*NiN%h^#i=EB z42f_y0|!v4#N?GMDvXko&jCrP$)8zFC$C_Mo7~1Kz$iC)I;#$&{N(*?%8Uw=U$81n zp2jLNS%ytu@?lnk$uVrAlR4OUCRebFF{)1PXP271j!l434Xj!nq?%D8FeRbXIEy_n|zyHfl+_5Jckr#Vo4$c3(z$NK%NGp;badEWyYM% VIUF0Qj<&aix?71auSOji;GiB ziW&X`fy88Ac4bD%$%X6+T2f#w3=E7QnghZK2q-DCQE`OpvSUa|EJ>WalO=ib92O-; zxykk{Dva`zQ-GwxWKLFPM#agxtU8kqu^LS7WEEvpnLHmTraE~an=+%?2P2S4}QKb!5r2|%_3s$8ER;3SAB{kWeotM!7>`X(DGZ~F0PhwYMG@iVb dU4zkN@;#vQOExocY+#=(BVfSDIN4J`9RT2kLIeN+ delta 240 zcmeyO@IgV6fq}z;fkB{vfq{V&NCPPb1`|DFJ(G=+EG$X^0VPE?Dvl*NiN%h^#i=EB z42f_y0|!v4#N?GMDvXko&jCrP$)8zFC$C_Mo7~1Kz$iC)I;#$&{N(*?%8Uw=U$81n zp2jLNS%ytu@?lnk$uVrAlR4OUCRebFF{)1PXP271j!l434Xj!nq?%D8FeRbXIEy_n|zyHfl+_5Jckr#Vo4$c3(z$NK%NGp;badEWyXTd VIUF0L9a#03^)70U{U}ic5+z z^U@ho5=#=nnl(V088s)rVo_k!n#|3rsHqK62r&$*D=jBKv4o){GdDFjIWZ@dfd!~W zXL3B75~J?qCN^D0J+LYIU{ef0rZ5_A7H7XH$yhM?qe9>221O>O$*+{;CNEHy000}k BJx%}s delta 127 zcmdntxx-zWfk82nfkAl(0|NsmkX-f{7=B}TQ$&Fs32>XR?BDKlzJe#N4|s5v=NT6nS?D<7j4h_zXp0u>1WfNmk6 diff --git a/spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs b/spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs new file mode 100644 index 000000000..193ab754d --- /dev/null +++ b/spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs @@ -0,0 +1,49 @@ +using UnityEngine; +using System.Collections; +using Spine; + + +public class AtlasRegionAttacher : MonoBehaviour { + + [System.Serializable] + public class SlotRegionPair { + [SpineSlot] + public string slot; + + [SpineAtlasRegion] + public string region; + } + + public AtlasAsset atlasAsset; + public SlotRegionPair[] attachments; + + [HideInInspector] + public SkeletonRenderer skeletonRenderer; + + + Atlas atlas; + + void Start() { + atlas = atlasAsset.GetAtlas(); + this.skeletonRenderer = GetComponent(); + + AtlasAttachmentLoader loader = new AtlasAttachmentLoader(atlas); + + float scaleMultiplier = skeletonRenderer.skeletonDataAsset.scale; + + var enumerator = attachments.GetEnumerator(); + while (enumerator.MoveNext()) { + var entry = (SlotRegionPair)enumerator.Current; + var regionAttachment = loader.NewRegionAttachment(null, entry.region, entry.region); + regionAttachment.Width = regionAttachment.RegionOriginalWidth * scaleMultiplier; + regionAttachment.Height = regionAttachment.RegionOriginalHeight * scaleMultiplier; + + regionAttachment.SetColor(new Color(1, 1, 1, 1)); + regionAttachment.UpdateOffset(); + + var slot = this.skeletonRenderer.skeleton.FindSlot(entry.slot); + slot.Attachment = regionAttachment; + } + } + +} diff --git a/spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs.meta b/spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs.meta new file mode 100644 index 000000000..bbf8780fa --- /dev/null +++ b/spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: afde57cc4fd39bb4dbd61b73403ae6a8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs index 136b7aae8..fc07c6fae 100644 --- a/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs @@ -28,8 +28,14 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; using UnityEditor; using UnityEngine; +using Spine; + [CustomEditor(typeof(AtlasAsset))] public class AtlasAssetInspector : Editor { @@ -46,9 +52,23 @@ public class AtlasAssetInspector : Editor { EditorGUILayout.PropertyField(atlasFile); EditorGUILayout.PropertyField(materials, true); + + + if (atlasFile.objectReferenceValue != null) { + Atlas atlas = asset.GetAtlas(); + FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); + List regions = (List)field.GetValue(atlas); + EditorGUILayout.LabelField("Regions"); + EditorGUI.indentLevel++; + for (int i = 0; i < regions.Count; i++) { + EditorGUILayout.LabelField(regions[i].name); + } + EditorGUI.indentLevel--; + } + if (serializedObject.ApplyModifiedProperties() || - (Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed") + (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") ) { asset.Reset(); } diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png new file mode 100644 index 0000000000000000000000000000000000000000..dfca413ac6c0f93c6a5d01eb38c52396d1f02934 GIT binary patch literal 649 zcmV;40(Sk0P)Kjs{jB17IZ~ebVG7wVRUJ4ZXi@?ZDjy3I4?3d zFEKJ@Q-b9H0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00H4i zL_t(Ijir;%YZFlr$3Jhg+rHiIrl}gER*8BMQM3|iHK8{_yyR3u1ux=Br2j*XUOaix zTTbFVz33?y4}w|*SFBQrKMpDJM-q28Tbty0NLQMg6rlqT9`j~C^PM-0P)e~E(}y{Q z5EhUGtPyzuP*+L?Ljgc?>G8MfZk6vZ9ykts8U?TbLht9$M`=&}jTr!JlYVly>QVSV z03dnu?sB!U{`o)hnGiwrDC=DqYi+k8(iFc!pf_cG`)ZqZ@yrRn<&*~=EUUpgQ-;f)WX79z>WYGK<9VZ z2WUE(3+GA1Z7R=JNF9@mn>MH}`zHNrHk-|urfCDQfj@}pMxW-y=_!F_JItIrjZ$4u zUD|$&%-|Z*xJ#v@l5URu1>Y95gcjeIZ^wA@( z>#oLPv5$bK?^G~h8%SyKwDO!gw-#Cbu*Up+4(Hm{GwpVJ!*$*F>2!LmTrNKVT2TuD zfFUgmX(4R~zoT*Q;UoNTlSZRStyb%Jp4Uqx66>W>>2|SLtN@`;0~300000NkvXXu0mjf_@@}V literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png.meta new file mode 100644 index 000000000..d85022986 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4a1646cf39026224c85ecba92d7d6948 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta index 35500c50d..cbccad91c 100644 --- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta @@ -5,8 +5,8 @@ TextureImporter: serializedVersion: 2 mipmaps: mipMapMode: 0 - enableMipMap: 1 - linearTexture: 0 + enableMipMap: 0 + linearTexture: 1 correctGamma: 0 fadeOut: 0 borderMipMap: 0 @@ -25,10 +25,10 @@ TextureImporter: maxTextureSize: 1024 textureSettings: filterMode: -1 - aniso: -1 + aniso: 1 mipBias: -1 - wrapMode: -1 - nPOTScale: 1 + wrapMode: 1 + nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 @@ -38,8 +38,8 @@ TextureImporter: spritePivot: {x: .5, y: .5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaIsTransparency: 0 - textureType: -1 + alphaIsTransparency: 1 + textureType: 2 buildTargetSettings: [] spriteSheet: sprites: [] diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png b/spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png new file mode 100644 index 0000000000000000000000000000000000000000..fa8f1906b3d2906ae4cebcd54a385e0d2ae8240c GIT binary patch literal 698 zcmV;r0!96aP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-t7IZ~ebVG7wVRUJ4ZXi@?ZDjy3GcPeYFEKQ6D{h|v00I(8 zL_t(IjjfbTZxT@yhMyT`U?5as8irb?Qz(%%wQ)gQuyN%=Hzw}<6Q)0=vH!py;MRpJ zH>_}FLSjmhbZh|~X-kHW8D?BC80F$u!cA^+lk=V@=RNn{BZXnex|X~)(z;>F;vh*< z1}FgrFamnOa79i!(j+6zSr~?cUtmD#Q;j#4My@@^Db+awPFKLnXElzC8hU3;f49zK z;QcbpurzW2MGgJs^XjX6cWw!!4;R-IyA1#$y&>2H-1Zo!sG-{v{QYL5b^lznIUAC; zQ|uKIDD5#0;4Wf6UqHW9=jbF~rRmZtCvi2I$?`5Iahoo!lYEt^75!C}4S~~&xyeB{ zG1O!xu^5x(%5JN0pb-S-CQ(m+RIe$|8Y8X>VWyss=gqj(xBd?6WeqS)6jecut3rY| z_3%A^uKNQl4V0UV<=(!*?{@mjVl zU9!*p?fTo+#{OO5o!vA)ra#vn?S%zX2|69;TebQu48wQJm8E3M(gDJPso1-fihB4! zv^kQXU;+^7Q>$$Df=zuUT0R= warnings = new List(); + + void OnEnable() { + + try { + atlasAssets = serializedObject.FindProperty("atlasAssets"); skeletonJSON = serializedObject.FindProperty("skeletonJSON"); scale = serializedObject.FindProperty("scale"); fromAnimation = serializedObject.FindProperty("fromAnimation"); toAnimation = serializedObject.FindProperty("toAnimation"); duration = serializedObject.FindProperty("duration"); defaultMix = serializedObject.FindProperty("defaultMix"); - + m_skeletonDataAsset = (SkeletonDataAsset)target; m_skeletonDataAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_skeletonDataAsset)); - - EditorApplication.update += Update; + EditorApplication.update += Update; } catch { } + + m_skeletonData = m_skeletonDataAsset.GetSkeletonData(true); + + RepopulateWarnings(); } - - void OnDestroy () { + + void OnDestroy() { m_initialized = false; EditorApplication.update -= Update; this.DestroyPreviewInstances(); @@ -88,13 +92,13 @@ public class SkeletonDataAssetInspector : Editor { this.m_previewUtility = null; } } - - override public void OnInspectorGUI () { + + override public void OnInspectorGUI() { serializedObject.Update(); SkeletonDataAsset asset = (SkeletonDataAsset)target; - + EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(atlasAsset); + EditorGUILayout.PropertyField(atlasAssets, true); EditorGUILayout.PropertyField(skeletonJSON); EditorGUILayout.PropertyField(scale); if (EditorGUI.EndChangeCheck()) { @@ -102,142 +106,301 @@ public class SkeletonDataAssetInspector : Editor { m_previewUtility.Cleanup(); m_previewUtility = null; } + + RepopulateWarnings(); } + - SkeletonData skeletonData = asset.GetSkeletonData(asset.atlasAsset == null || asset.skeletonJSON == null); - if (skeletonData != null) { - showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data"); - if (showAnimationStateData) { - EditorGUILayout.PropertyField(defaultMix); - - // Animation names - String[] animations = new String[skeletonData.Animations.Count]; - for (int i = 0; i < animations.Length; i++) - animations[i] = skeletonData.Animations[i].Name; - - for (int i = 0; i < fromAnimation.arraySize; i++) { - SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i); - SerializedProperty to = toAnimation.GetArrayElementAtIndex(i); - SerializedProperty durationProp = duration.GetArrayElementAtIndex(i); - EditorGUILayout.BeginHorizontal(); - from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)]; - to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)]; - durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue); - if (GUILayout.Button("Delete")) { - duration.DeleteArrayElementAtIndex(i); - toAnimation.DeleteArrayElementAtIndex(i); - fromAnimation.DeleteArrayElementAtIndex(i); - } - EditorGUILayout.EndHorizontal(); - } - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.Space(); - if (GUILayout.Button("Add Mix")) { - duration.arraySize++; - toAnimation.arraySize++; - fromAnimation.arraySize++; - } - EditorGUILayout.Space(); - EditorGUILayout.EndHorizontal(); - } + if (m_skeletonData != null) { + + DrawAnimationStateInfo(); + DrawAnimationList(); + DrawSlotList(); - if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) { - StopAnimation(); - m_skeletonAnimation.skeleton.SetToSetupPose(); - m_requireRefresh = true; - } - - #if UNITY_4_3 - m_showAnimationList = EditorGUILayout.Foldout(m_showAnimationList, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot)); - if(m_showAnimationList){ - #else - m_showAnimationList.target = EditorGUILayout.Foldout(m_showAnimationList.target, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot)); - if (EditorGUILayout.BeginFadeGroup(m_showAnimationList.faded)) { - #endif - - - - - EditorGUILayout.LabelField("Name", "Duration"); - foreach (Spine.Animation a in skeletonData.Animations) { - GUILayout.BeginHorizontal(); - - if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) { - if (m_skeletonAnimation.state.GetCurrent(0) != null && m_skeletonAnimation.state.GetCurrent(0).Animation == a) { - GUI.contentColor = Color.black; - if (GUILayout.Button("\u25BA", GUILayout.Width(24))) { - StopAnimation(); - } - GUI.contentColor = Color.white; - } else { - if (GUILayout.Button("\u25BA", GUILayout.Width(24))) { - PlayAnimation(a.Name, true); - } - } - } else { - GUILayout.Label("?", GUILayout.Width(24)); - } - EditorGUILayout.LabelField(new GUIContent(a.Name, SpineEditorUtilities.Icons.animation), new GUIContent(a.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(a.Duration * 30)) + ")").PadLeft(12, ' '))); - GUILayout.EndHorizontal(); - } - } - #if !UNITY_4_3 - EditorGUILayout.EndFadeGroup(); - #endif + } else { + //Show Warnings + foreach (var str in warnings) + EditorGUILayout.LabelField(new GUIContent(str, SpineEditorUtilities.Icons.warning)); } - + if (!Application.isPlaying) { if (serializedObject.ApplyModifiedProperties() || (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") - ) { + ) { asset.Reset(); } } } + + void DrawAnimationStateInfo() { + showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data"); + if (!showAnimationStateData) + return; + + EditorGUILayout.PropertyField(defaultMix); + + // Animation names + String[] animations = new String[m_skeletonData.Animations.Count]; + for (int i = 0; i < animations.Length; i++) + animations[i] = m_skeletonData.Animations[i].Name; + + for (int i = 0; i < fromAnimation.arraySize; i++) { + SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i); + SerializedProperty to = toAnimation.GetArrayElementAtIndex(i); + SerializedProperty durationProp = duration.GetArrayElementAtIndex(i); + EditorGUILayout.BeginHorizontal(); + from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)]; + to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)]; + durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue); + if (GUILayout.Button("Delete")) { + duration.DeleteArrayElementAtIndex(i); + toAnimation.DeleteArrayElementAtIndex(i); + fromAnimation.DeleteArrayElementAtIndex(i); + } + EditorGUILayout.EndHorizontal(); + } + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.Space(); + if (GUILayout.Button("Add Mix")) { + duration.arraySize++; + toAnimation.arraySize++; + fromAnimation.arraySize++; + } + EditorGUILayout.Space(); + EditorGUILayout.EndHorizontal(); + } + void DrawAnimationList() { + showAnimationList = EditorGUILayout.Foldout(showAnimationList, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot)); + if (!showAnimationList) + return; + + if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) { + StopAnimation(); + m_skeletonAnimation.skeleton.SetToSetupPose(); + m_requireRefresh = true; + } + + EditorGUILayout.LabelField("Name", "Duration"); + foreach (Spine.Animation a in m_skeletonData.Animations) { + GUILayout.BeginHorizontal(); + + if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) { + if (m_skeletonAnimation.state.GetCurrent(0) != null && m_skeletonAnimation.state.GetCurrent(0).Animation == a) { + GUI.contentColor = Color.black; + if (GUILayout.Button("\u25BA", GUILayout.Width(24))) { + StopAnimation(); + } + GUI.contentColor = Color.white; + } else { + if (GUILayout.Button("\u25BA", GUILayout.Width(24))) { + PlayAnimation(a.Name, true); + } + } + } else { + GUILayout.Label("?", GUILayout.Width(24)); + } + EditorGUILayout.LabelField(new GUIContent(a.Name, SpineEditorUtilities.Icons.animation), new GUIContent(a.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(a.Duration * 30)) + ")").PadLeft(12, ' '))); + GUILayout.EndHorizontal(); + } + } + + + void DrawSlotList() { + showSlotList = EditorGUILayout.Foldout(showSlotList, new GUIContent("Slots", SpineEditorUtilities.Icons.slotRoot)); + + if (!showSlotList) + return; + + if (m_skeletonAnimation == null || m_skeletonAnimation.skeleton == null) + return; + + EditorGUI.indentLevel++; + try { + showAttachments = EditorGUILayout.ToggleLeft("Show Attachments", showAttachments); + } catch { + return; + } + + + List slotAttachments = new List(); + List slotAttachmentNames = new List(); + List defaultSkinAttachmentNames = new List(); + var defaultSkin = m_skeletonData.Skins[0]; + Skin skin = m_skeletonAnimation.skeleton.Skin; + if (skin == null) { + skin = defaultSkin; + } + + for (int i = m_skeletonAnimation.skeleton.Slots.Count-1; i >= 0; i--) { + Slot slot = m_skeletonAnimation.skeleton.Slots[i]; + EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, SpineEditorUtilities.Icons.slot)); + if (showAttachments) { + + + EditorGUI.indentLevel++; + slotAttachments.Clear(); + slotAttachmentNames.Clear(); + defaultSkinAttachmentNames.Clear(); + + skin.FindNamesForSlot(i, slotAttachmentNames); + skin.FindAttachmentsForSlot(i, slotAttachments); + + + if (skin != defaultSkin) { + defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames); + defaultSkin.FindNamesForSlot(i, slotAttachmentNames); + defaultSkin.FindAttachmentsForSlot(i, slotAttachments); + } else { + defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames); + } + + + + for (int a = 0; a < slotAttachments.Count; a++) { + Attachment attachment = slotAttachments[a]; + string name = slotAttachmentNames[a]; + + Texture2D icon = null; + var type = attachment.GetType(); + + if (type == typeof(RegionAttachment)) + icon = SpineEditorUtilities.Icons.image; + else if (type == typeof(MeshAttachment)) + icon = SpineEditorUtilities.Icons.mesh; + else if (type == typeof(BoundingBoxAttachment)) + icon = SpineEditorUtilities.Icons.boundingBox; + else if (type == typeof(SkinnedMeshAttachment)) + icon = SpineEditorUtilities.Icons.weights; + else + icon = SpineEditorUtilities.Icons.warning; + + //TODO: Waterboard Nate + //if (name != attachment.Name) + //icon = SpineEditorUtilities.Icons.skinPlaceholder; + + bool initialState = slot.Attachment == attachment; + + bool toggled = EditorGUILayout.ToggleLeft(new GUIContent(name, icon), slot.Attachment == attachment); + + if (!defaultSkinAttachmentNames.Contains(name)) { + Rect skinPlaceHolderIconRect = GUILayoutUtility.GetLastRect(); + skinPlaceHolderIconRect.width = SpineEditorUtilities.Icons.skinPlaceholder.width; + skinPlaceHolderIconRect.height = SpineEditorUtilities.Icons.skinPlaceholder.height; + GUI.DrawTexture(skinPlaceHolderIconRect, SpineEditorUtilities.Icons.skinPlaceholder); + } + + + if (toggled != initialState) { + if (toggled) { + slot.Attachment = attachment; + } else { + slot.Attachment = null; + } + m_requireRefresh = true; + } + } + + + EditorGUI.indentLevel--; + } + } + + EditorGUI.indentLevel--; + } + + + void RepopulateWarnings() { + warnings.Clear(); + + if (skeletonJSON.objectReferenceValue == null) + warnings.Add("Missing Skeleton JSON"); + else { + + if (SpineEditorUtilities.IsSpineJSON((TextAsset)skeletonJSON.objectReferenceValue) == false) { + warnings.Add("Skeleton JSON is not a Valid JSON file"); + } else { + bool detectedNullAtlasEntry = false; + List atlasList = new List(); + for (int i = 0; i < atlasAssets.arraySize; i++) { + if (atlasAssets.GetArrayElementAtIndex(i).objectReferenceValue == null) { + detectedNullAtlasEntry = true; + break; + } else { + atlasList.Add(((AtlasAsset)atlasAssets.GetArrayElementAtIndex(i).objectReferenceValue).GetAtlas()); + } + } + + if (detectedNullAtlasEntry) + warnings.Add("AtlasAsset elements cannot be Null"); + else { + //get requirements + var missingPaths = SpineEditorUtilities.GetRequiredAtlasRegions(AssetDatabase.GetAssetPath((TextAsset)skeletonJSON.objectReferenceValue)); + + foreach (var atlas in atlasList) { + for (int i = 0; i < missingPaths.Count; i++) { + if (atlas.FindRegion(missingPaths[i]) != null) { + missingPaths.RemoveAt(i); + i--; + } + } + } + + foreach (var str in missingPaths) + warnings.Add("Missing Region: '" + str + "'"); + + + + } + } + + + } + } + //preview window stuff private PreviewRenderUtility m_previewUtility; private GameObject m_previewInstance; private Vector2 previewDir; private SkeletonAnimation m_skeletonAnimation; - private SkeletonData m_skeletonData; + //private SkeletonData m_skeletonData; private static int sliderHash = "Slider".GetHashCode(); private float m_lastTime; private bool m_playing; private bool m_requireRefresh; private Color m_originColor = new Color(0.3f, 0.3f, 0.3f, 1); - - private void StopAnimation () { + + private void StopAnimation() { m_skeletonAnimation.state.ClearTrack(0); m_playing = false; } - + List m_animEvents = new List(); List m_animEventFrames = new List(); - private void PlayAnimation (string animName, bool loop) { + private void PlayAnimation(string animName, bool loop) { m_animEvents.Clear(); m_animEventFrames.Clear(); - + m_skeletonAnimation.state.SetAnimation(0, animName, loop); - + Spine.Animation a = m_skeletonAnimation.state.GetCurrent(0).Animation; foreach (Timeline t in a.Timelines) { if (t.GetType() == typeof(EventTimeline)) { EventTimeline et = (EventTimeline)t; - + for (int i = 0; i < et.Events.Length; i++) { m_animEvents.Add(et.Events[i]); m_animEventFrames.Add(et.Frames[i]); } - + } } - + m_playing = true; } - - private void InitPreview () { + + private void InitPreview() { if (this.m_previewUtility == null) { this.m_lastTime = Time.realtimeSinceStartup; this.m_previewUtility = new PreviewRenderUtility(true); @@ -247,48 +410,59 @@ public class SkeletonDataAssetInspector : Editor { this.CreatePreviewInstances(); } } - - private void CreatePreviewInstances () { + + private void CreatePreviewInstances() { this.DestroyPreviewInstances(); if (this.m_previewInstance == null) { - string skinName = EditorPrefs.GetString(m_skeletonDataAssetGUID + "_lastSkin", ""); - - m_previewInstance = SpineEditorUtilities.SpawnAnimatedSkeleton((SkeletonDataAsset)target, skinName).gameObject; - m_previewInstance.hideFlags = HideFlags.HideAndDontSave; - m_previewInstance.layer = 0x1f; - - - m_skeletonAnimation = m_previewInstance.GetComponent(); - m_skeletonAnimation.initialSkinName = skinName; - m_skeletonAnimation.LateUpdate(); - - m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true); - - m_previewInstance.renderer.enabled = false; - - m_initialized = true; - AdjustCameraGoals(true); + try { + string skinName = EditorPrefs.GetString(m_skeletonDataAssetGUID + "_lastSkin", ""); + + m_previewInstance = SpineEditorUtilities.SpawnAnimatedSkeleton((SkeletonDataAsset)target, skinName).gameObject; + m_previewInstance.hideFlags = HideFlags.HideAndDontSave; + m_previewInstance.layer = 0x1f; + + + m_skeletonAnimation = m_previewInstance.GetComponent(); + m_skeletonAnimation.initialSkinName = skinName; + m_skeletonAnimation.LateUpdate(); + + m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true); + + m_previewInstance.renderer.enabled = false; + + m_initialized = true; + AdjustCameraGoals(true); + } catch { + + } } } - - private void DestroyPreviewInstances () { + + private void DestroyPreviewInstances() { if (this.m_previewInstance != null) { DestroyImmediate(this.m_previewInstance); m_previewInstance = null; } m_initialized = false; } - - public override bool HasPreviewGUI () { + + public override bool HasPreviewGUI() { //TODO: validate json data + + for (int i = 0; i < atlasAssets.arraySize; i++) { + var prop = atlasAssets.GetArrayElementAtIndex(i); + if (prop.objectReferenceValue == null) + return false; + } + return skeletonJSON.objectReferenceValue != null; } - + Texture m_previewTex = new Texture(); - public override void OnInteractivePreviewGUI (Rect r, GUIStyle background) { + public override void OnInteractivePreviewGUI(Rect r, GUIStyle background) { this.InitPreview(); - + if (UnityEngine.Event.current.type == EventType.Repaint) { if (m_requireRefresh) { this.m_previewUtility.BeginPreview(r, background); @@ -299,50 +473,54 @@ public class SkeletonDataAssetInspector : Editor { if (this.m_previewTex != null) GUI.DrawTexture(r, m_previewTex, ScaleMode.StretchToFill, false); } - + DrawSkinToolbar(r); NormalizedTimeBar(r); //TODO: implement panning // this.previewDir = Drag2D(this.previewDir, r); MouseScroll(r); } - + float m_orthoGoal = 1; Vector3 m_posGoal = new Vector3(0, 0, -10); double m_adjustFrameEndTime = 0; - private void AdjustCameraGoals (bool calculateMixTime) { + private void AdjustCameraGoals(bool calculateMixTime) { + if (this.m_previewInstance == null) + return; + if (calculateMixTime) { if (m_skeletonAnimation.state.GetCurrent(0) != null) { m_adjustFrameEndTime = EditorApplication.timeSinceStartup + m_skeletonAnimation.state.GetCurrent(0).Mix; } } - - + + GameObject go = this.m_previewInstance; + Bounds bounds = go.renderer.bounds; m_orthoGoal = bounds.size.y; - + m_posGoal = bounds.center + new Vector3(0, 0, -10); } - - private void AdjustCameraGoals () { + + private void AdjustCameraGoals() { AdjustCameraGoals(false); } - - private void AdjustCamera () { + + private void AdjustCamera() { if (m_previewUtility == null) return; - - + + if (EditorApplication.timeSinceStartup < m_adjustFrameEndTime) { AdjustCameraGoals(); } - + float orthoSet = Mathf.Lerp(this.m_previewUtility.m_Camera.orthographicSize, m_orthoGoal, 0.1f); - + this.m_previewUtility.m_Camera.orthographicSize = orthoSet; - + float dist = Vector3.Distance(m_previewUtility.m_Camera.transform.position, m_posGoal); if (dist > 60f * ((SkeletonDataAsset)target).scale) { Vector3 pos = Vector3.Lerp(this.m_previewUtility.m_Camera.transform.position, m_posGoal, 0.1f); @@ -352,138 +530,138 @@ public class SkeletonDataAssetInspector : Editor { m_requireRefresh = true; } } - - private void DoRenderPreview (bool drawHandles) { + + private void DoRenderPreview(bool drawHandles) { GameObject go = this.m_previewInstance; - - if (m_requireRefresh) { + + if (m_requireRefresh && go != null) { go.renderer.enabled = true; - + if (EditorApplication.isPlaying) { //do nothing } else { m_skeletonAnimation.Update((Time.realtimeSinceStartup - m_lastTime)); } - + m_lastTime = Time.realtimeSinceStartup; - + if (!EditorApplication.isPlaying) m_skeletonAnimation.LateUpdate(); - + if (drawHandles) { Handles.SetCamera(m_previewUtility.m_Camera); Handles.color = m_originColor; - + Handles.DrawLine(new Vector3(-1000 * m_skeletonDataAsset.scale, 0, 0), new Vector3(1000 * m_skeletonDataAsset.scale, 0, 0)); Handles.DrawLine(new Vector3(0, 1000 * m_skeletonDataAsset.scale, 0), new Vector3(0, -1000 * m_skeletonDataAsset.scale, 0)); } - + this.m_previewUtility.m_Camera.Render(); go.renderer.enabled = false; } - - + + } - - void Update () { + + void Update() { AdjustCamera(); - + if (m_playing) { m_requireRefresh = true; Repaint(); } else if (m_requireRefresh) { - Repaint(); - } else { - #if !UNITY_4_3 - if (m_showAnimationList.isAnimating) - Repaint(); - #endif - } + Repaint(); + } else { + //only needed if using smooth menus + } } - - void DrawSkinToolbar (Rect r) { + + void DrawSkinToolbar(Rect r) { if (m_skeletonAnimation == null) return; - + if (m_skeletonAnimation.skeleton != null) { string label = (m_skeletonAnimation.skeleton != null && m_skeletonAnimation.skeleton.Skin != null) ? m_skeletonAnimation.skeleton.Skin.Name : "default"; - + Rect popRect = new Rect(r); popRect.y += 32; popRect.x += 4; popRect.height = 24; popRect.width = 40; EditorGUI.DropShadowLabel(popRect, new GUIContent("Skin", SpineEditorUtilities.Icons.skinsRoot)); - + popRect.y += 11; popRect.width = 150; popRect.x += 44; - + if (GUI.Button(popRect, label, EditorStyles.popup)) { SelectSkinContext(); } } } - - void SelectSkinContext () { + + void SelectSkinContext() { GenericMenu menu = new GenericMenu(); - + foreach (Skin s in m_skeletonData.Skins) { menu.AddItem(new GUIContent(s.Name), this.m_skeletonAnimation.skeleton.Skin == s, SetSkin, (object)s); } - + menu.ShowAsContext(); } - - void SetSkin (object o) { + + void SetSkin(object o) { Skin skin = (Skin)o; - + m_skeletonAnimation.initialSkinName = skin.Name; m_skeletonAnimation.Reset(); m_requireRefresh = true; - + EditorPrefs.SetString(m_skeletonDataAssetGUID + "_lastSkin", skin.Name); } - - void NormalizedTimeBar (Rect r) { + + void NormalizedTimeBar(Rect r) { + if (m_skeletonAnimation == null) + return; + Rect barRect = new Rect(r); barRect.height = 32; barRect.x += 4; barRect.width -= 4; - + GUI.Box(barRect, ""); - + Rect lineRect = new Rect(barRect); float width = lineRect.width; TrackEntry t = m_skeletonAnimation.state.GetCurrent(0); - + if (t != null) { int loopCount = (int)(t.Time / t.EndTime); float currentTime = t.Time - (t.EndTime * loopCount); - + float normalizedTime = currentTime / t.Animation.Duration; - + lineRect.x = barRect.x + (width * normalizedTime) - 0.5f; lineRect.width = 2; - + GUI.color = Color.red; GUI.DrawTexture(lineRect, EditorGUIUtility.whiteTexture); GUI.color = Color.white; - + for (int i = 0; i < m_animEvents.Count; i++) { //TODO: Tooltip //Spine.Event spev = animEvents[i]; - + float fr = m_animEventFrames[i]; - + Rect evRect = new Rect(barRect); evRect.x = Mathf.Clamp(((fr / t.Animation.Duration) * width) - (SpineEditorUtilities.Icons._event.width / 2), barRect.x, float.MaxValue); evRect.width = SpineEditorUtilities.Icons._event.width; evRect.height = SpineEditorUtilities.Icons._event.height; evRect.y += SpineEditorUtilities.Icons._event.height; GUI.DrawTexture(evRect, SpineEditorUtilities.Icons._event); - - + + //TODO: Tooltip /* UnityEngine.Event ev = UnityEngine.Event.current; @@ -500,24 +678,24 @@ public class SkeletonDataAssetInspector : Editor { } } } - - void MouseScroll (Rect position) { + + void MouseScroll(Rect position) { UnityEngine.Event current = UnityEngine.Event.current; int controlID = GUIUtility.GetControlID(sliderHash, FocusType.Passive); - + switch (current.GetTypeForControl(controlID)) { - case EventType.ScrollWheel: - if (position.Contains(current.mousePosition)) { - - m_orthoGoal += current.delta.y * ((SkeletonDataAsset)target).scale * 10; - GUIUtility.hotControl = controlID; - current.Use(); - } - break; + case EventType.ScrollWheel: + if (position.Contains(current.mousePosition)) { + + m_orthoGoal += current.delta.y * ((SkeletonDataAsset)target).scale * 10; + GUIUtility.hotControl = controlID; + current.Use(); + } + break; } - + } - + //TODO: Implement preview panning /* static Vector2 Drag2D(Vector2 scrollPosition, Rect position) @@ -559,45 +737,45 @@ public class SkeletonDataAssetInspector : Editor { return scrollPosition; } */ - - public override GUIContent GetPreviewTitle () { + + public override GUIContent GetPreviewTitle() { return new GUIContent("Preview"); } - - public override void OnPreviewSettings () { + + public override void OnPreviewSettings() { if (!m_initialized) { GUILayout.HorizontalSlider(0, 0, 2, GUILayout.MaxWidth(64)); } else { float speed = GUILayout.HorizontalSlider(m_skeletonAnimation.timeScale, 0, 2, GUILayout.MaxWidth(64)); - + //snap to nearest 0.25 float y = speed / 0.25f; int q = Mathf.RoundToInt(y); speed = q * 0.25f; - + m_skeletonAnimation.timeScale = speed; } } - + //TODO: Fix first-import error //TODO: Update preview without thumbnail - public override Texture2D RenderStaticPreview (string assetPath, UnityEngine.Object[] subAssets, int width, int height) { + public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height) { Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false); - + this.InitPreview(); - + if (this.m_previewUtility.m_Camera == null) return null; - + m_requireRefresh = true; this.DoRenderPreview(false); AdjustCameraGoals(false); - + this.m_previewUtility.m_Camera.orthographicSize = m_orthoGoal / 2; this.m_previewUtility.m_Camera.transform.position = m_posGoal; this.m_previewUtility.BeginStaticPreview(new Rect(0, 0, width, height)); this.DoRenderPreview(false); - + //TODO: Figure out why this is throwing errors on first attempt // if(m_previewUtility != null){ // Handles.SetCamera(this.m_previewUtility.m_Camera); diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs index 3c918ac89..7428c9522 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs @@ -33,7 +33,7 @@ using UnityEngine; [CustomEditor(typeof(SkeletonRenderer))] public class SkeletonRendererInspector : Editor { - protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles; + protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, submeshSeparators; protected virtual void OnEnable () { skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset"); @@ -42,6 +42,7 @@ public class SkeletonRendererInspector : Editor { tangents = serializedObject.FindProperty("calculateTangents"); meshes = serializedObject.FindProperty("renderMeshes"); immutableTriangles = serializedObject.FindProperty("immutableTriangles"); + submeshSeparators = serializedObject.FindProperty("submeshSeparators"); } protected virtual void gui () { @@ -52,8 +53,11 @@ public class SkeletonRendererInspector : Editor { float reloadWidth = GUI.skin.label.CalcSize(new GUIContent("Reload")).x + 20; if (GUILayout.Button("Reload", GUILayout.Width(reloadWidth))) { if (component.skeletonDataAsset != null) { - if (component.skeletonDataAsset.atlasAsset != null) - component.skeletonDataAsset.atlasAsset.Reset(); + foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { + if (aa != null) + aa.Reset(); + } + component.skeletonDataAsset.Reset(); } component.Reset(); @@ -92,6 +96,7 @@ public class SkeletonRendererInspector : Editor { new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility")); EditorGUILayout.PropertyField(normals); EditorGUILayout.PropertyField(tangents); + EditorGUILayout.PropertyField(submeshSeparators, true); } override public void OnInspectorGUI () { diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs new file mode 100644 index 000000000..cdc9a0e37 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs @@ -0,0 +1,456 @@ +using UnityEngine; +using UnityEditor; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Linq; +using System.Reflection; +using Spine; + + +public struct SpineDrawerValuePair { + public string str; + public SerializedProperty property; + + public SpineDrawerValuePair(string val, SerializedProperty property) { + this.str = val; + this.property = property; + } +} + +[CustomPropertyDrawer(typeof(SpineSlot))] +public class SpineSlotDrawer : PropertyDrawer { + SkeletonDataAsset skeletonDataAsset; + + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + if (property.propertyType != SerializedPropertyType.String) { + EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); + return; + } + + SpineSlot attrib = (SpineSlot)attribute; + + var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource); + + if (skeletonDataAssetProperty != null) { + if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue; + } else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue; + if (renderer != null) + skeletonDataAsset = renderer.skeletonDataAsset; + } else { + EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); + return; + } + + } else if (property.serializedObject.targetObject is Component) { + var component = (Component)property.serializedObject.targetObject; + if (component.GetComponent() != null) { + var skeletonRenderer = component.GetComponent(); + skeletonDataAsset = skeletonRenderer.skeletonDataAsset; + } + } + + if (skeletonDataAsset == null) { + EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); + return; + } + + position = EditorGUI.PrefixLabel(position, label); + + if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { + Selector(property); + } + + } + + void Selector(SerializedProperty property) { + SpineSlot attrib = (SpineSlot)attribute; + SkeletonData data = skeletonDataAsset.GetSkeletonData(true); + if (data == null) + return; + + GenericMenu menu = new GenericMenu(); + + menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); + menu.AddSeparator(""); + + for (int i = 0; i < data.Slots.Count; i++) { + string name = data.Slots[i].Name; + if (name.StartsWith(attrib.startsWith)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + + menu.ShowAsContext(); + } + + void HandleSelect(object val) { + var pair = (SpineDrawerValuePair)val; + pair.property.stringValue = pair.str; + pair.property.serializedObject.ApplyModifiedProperties(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + return 18; + } +} + +[CustomPropertyDrawer(typeof(SpineSkin))] +public class SpineSkinDrawer : PropertyDrawer { + SkeletonDataAsset skeletonDataAsset; + + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + if (property.propertyType != SerializedPropertyType.String) { + EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); + return; + } + + SpineSkin attrib = (SpineSkin)attribute; + + var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource); + + if (skeletonDataAssetProperty != null) { + if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue; + } else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue; + if (renderer != null) + skeletonDataAsset = renderer.skeletonDataAsset; + } else { + EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); + return; + } + + } else if (property.serializedObject.targetObject is Component) { + var component = (Component)property.serializedObject.targetObject; + if (component.GetComponent() != null) { + var skeletonRenderer = component.GetComponent(); + skeletonDataAsset = skeletonRenderer.skeletonDataAsset; + } + } + + if (skeletonDataAsset == null) { + EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); + return; + } + + position = EditorGUI.PrefixLabel(position, label); + + if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { + Selector(property); + } + + } + + void Selector(SerializedProperty property) { + SpineSkin attrib = (SpineSkin)attribute; + SkeletonData data = skeletonDataAsset.GetSkeletonData(true); + if (data == null) + return; + + GenericMenu menu = new GenericMenu(); + + menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); + menu.AddSeparator(""); + + for (int i = 0; i < data.Skins.Count; i++) { + string name = data.Skins[i].Name; + if (name.StartsWith(attrib.startsWith)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + + menu.ShowAsContext(); + } + + void HandleSelect(object val) { + var pair = (SpineDrawerValuePair)val; + pair.property.stringValue = pair.str; + pair.property.serializedObject.ApplyModifiedProperties(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + return 18; + } +} + +[CustomPropertyDrawer(typeof(SpineAtlasRegion))] +public class SpineAtlasRegionDrawer : PropertyDrawer { + Component component; + SerializedProperty atlasProp; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + if (property.propertyType != SerializedPropertyType.String) { + EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); + return; + } + + component = (Component)property.serializedObject.targetObject; + + if (component != null) + atlasProp = property.serializedObject.FindProperty("atlasAsset"); + else + atlasProp = null; + + + if (atlasProp == null) { + EditorGUI.LabelField(position, "ERROR:", "Must have AtlasAsset variable!"); + return; + } else if (atlasProp.objectReferenceValue == null) { + EditorGUI.LabelField(position, "ERROR:", "Atlas variable must not be null!"); + return; + } else if (atlasProp.objectReferenceValue.GetType() != typeof(AtlasAsset)) { + EditorGUI.LabelField(position, "ERROR:", "Atlas variable must be of type AtlasAsset!"); + } + + position = EditorGUI.PrefixLabel(position, label); + + if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { + Selector(property); + } + + } + + void Selector(SerializedProperty property) { + GenericMenu menu = new GenericMenu(); + AtlasAsset atlasAsset = (AtlasAsset)atlasProp.objectReferenceValue; + Atlas atlas = atlasAsset.GetAtlas(); + FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); + List regions = (List)field.GetValue(atlas); + + for (int i = 0; i < regions.Count; i++) { + string name = regions[i].name; + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + + + menu.ShowAsContext(); + } + + void HandleSelect(object val) { + var pair = (SpineDrawerValuePair)val; + pair.property.stringValue = pair.str; + pair.property.serializedObject.ApplyModifiedProperties(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + return 18; + } +} + +[CustomPropertyDrawer(typeof(SpineAnimation))] +public class SpineAnimationDrawer : PropertyDrawer { + SkeletonDataAsset skeletonDataAsset; + + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + + + if (property.propertyType != SerializedPropertyType.String) { + EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); + return; + } + + SpineAnimation attrib = (SpineAnimation)attribute; + + var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource); + + if (skeletonDataAssetProperty != null) { + if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue; + } else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue; + if (renderer != null) + skeletonDataAsset = renderer.skeletonDataAsset; + } else { + EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); + return; + } + } else if (property.serializedObject.targetObject is Component) { + var component = (Component)property.serializedObject.targetObject; + if (component.GetComponent() != null) { + var skeletonRenderer = component.GetComponent(); + skeletonDataAsset = skeletonRenderer.skeletonDataAsset; + } + } + + if (skeletonDataAsset == null) { + EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); + return; + } + + position = EditorGUI.PrefixLabel(position, label); + + if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { + Selector(property); + } + + } + + void Selector(SerializedProperty property) { + + SpineAnimation attrib = (SpineAnimation)attribute; + + GenericMenu menu = new GenericMenu(); + + var animations = skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations; + for (int i = 0; i < animations.Count; i++) { + string name = animations[i].Name; + if (name.StartsWith(attrib.startsWith)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + + menu.ShowAsContext(); + } + + void HandleSelect(object val) { + var pair = (SpineDrawerValuePair)val; + pair.property.stringValue = pair.str; + pair.property.serializedObject.ApplyModifiedProperties(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + return 18; + } +} + +[CustomPropertyDrawer(typeof(SpineAttachment))] +public class SpineAttachmentDrawer : PropertyDrawer { + + SkeletonDataAsset skeletonDataAsset; + SkeletonRenderer skeletonRenderer; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + + if (property.propertyType != SerializedPropertyType.String) { + EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); + return; + } + + SpineAttachment attrib = (SpineAttachment)attribute; + + var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource); + + if (skeletonDataAssetProperty != null) { + if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue; + } else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue; + if (renderer != null) + skeletonDataAsset = renderer.skeletonDataAsset; + else { + EditorGUI.LabelField(position, "ERROR:", "No SkeletonRenderer"); + } + } else { + EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); + return; + } + + } else if (property.serializedObject.targetObject is Component) { + var component = (Component)property.serializedObject.targetObject; + if (component.GetComponent() != null) { + skeletonRenderer = component.GetComponent(); + skeletonDataAsset = skeletonRenderer.skeletonDataAsset; + } + } + + if (skeletonDataAsset == null && skeletonRenderer == null) { + EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset or SkeletonRenderer"); + return; + } + + position = EditorGUI.PrefixLabel(position, label); + + if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { + Selector(property); + } + + } + + void Selector(SerializedProperty property) { + SkeletonData data = skeletonDataAsset.GetSkeletonData(true); + + if (data == null) + return; + + SpineAttachment attrib = (SpineAttachment)attribute; + + List validSkins = new List(); + + if (skeletonRenderer != null && attrib.currentSkinOnly) { + if (skeletonRenderer.skeleton.Skin != null) + validSkins.Add(skeletonRenderer.skeleton.Skin); + } else { + foreach (Skin skin in data.Skins) { + if (skin != null) + validSkins.Add(skin); + } + } + + GenericMenu menu = new GenericMenu(); + List attachmentNames = new List(); + string prefix = ""; + + if (skeletonRenderer != null && attrib.currentSkinOnly) + menu.AddDisabledItem(new GUIContent(skeletonRenderer.gameObject.name + " (SkeletonRenderer)")); + else + menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); + menu.AddSeparator(""); + + menu.AddItem(new GUIContent("Null"), property.stringValue == "", HandleSelect, new SpineDrawerValuePair("", property)); + menu.AddSeparator(""); + + Skin defaultSkin = data.Skins[0]; + + SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotSource); + string slotMatch = ""; + if (slotProperty != null) { + if (slotProperty.propertyType == SerializedPropertyType.String) { + slotMatch = slotProperty.stringValue.ToLower(); + } + } + + foreach (Skin skin in validSkins) { + string skinPrefix = skin.Name + "/"; + + if (validSkins.Count > 1) + prefix = skinPrefix; + + for (int i = 0; i < data.Slots.Count; i++) { + if (slotMatch.Length > 0 && data.Slots[i].Name.ToLower().Contains(slotMatch) == false) + continue; + + attachmentNames.Clear(); + skin.FindNamesForSlot(i, attachmentNames); + if (skin != defaultSkin) + defaultSkin.FindNamesForSlot(i, attachmentNames); + + for (int a = 0; a < attachmentNames.Count; a++) { + string attachmentPath = attachmentNames[a]; + string menuPath = prefix + data.Slots[i].Name + "/" + attachmentPath; + string name = attachmentNames[a]; + + if (attrib.returnFullPath) + name = skin.Name + "/" + data.Slots[i].Name + "/" + attachmentPath; + menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + } + } + + + menu.ShowAsContext(); + } + + void HandleSelect(object val) { + var pair = (SpineDrawerValuePair)val; + pair.property.stringValue = pair.str; + pair.property.serializedObject.ApplyModifiedProperties(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + return 18; + } +} diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs.meta b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs.meta new file mode 100644 index 000000000..69a87c913 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f2de282d583d4a641bf1c349f0a3eef9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index 3af7d3add..f939ce455 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -39,6 +39,8 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; +using System.Linq; +using System.Reflection; using Spine; [InitializeOnLoad] @@ -51,10 +53,12 @@ public class SpineEditorUtilities : AssetPostprocessor { public static Texture2D poseBones; public static Texture2D boneNib; public static Texture2D slot; + public static Texture2D slotRoot; public static Texture2D skinPlaceholder; public static Texture2D image; public static Texture2D boundingBox; public static Texture2D mesh; + public static Texture2D weights; public static Texture2D skin; public static Texture2D skinsRoot; public static Texture2D animation; @@ -78,7 +82,7 @@ public class SpineEditorUtilities : AssetPostprocessor { new Vector3(0.1f, 0.1f, 0) }; _boneMesh.uv = new Vector2[4]; - _boneMesh.triangles = new int[6]{0,1,2,2,3,0}; + _boneMesh.triangles = new int[6] { 0, 1, 2, 2, 3, 0 }; _boneMesh.RecalculateBounds(); _boneMesh.RecalculateNormals(); } @@ -108,17 +112,19 @@ public class SpineEditorUtilities : AssetPostprocessor { internal static Material _boneMaterial; - public static void Initialize () { + public static void Initialize() { skeleton = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skeleton.png"); nullBone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-null.png"); bone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-bone.png"); poseBones = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-poseBones.png"); boneNib = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boneNib.png"); slot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slot.png"); + slotRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slotRoot.png"); skinPlaceholder = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png"); image = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-image.png"); boundingBox = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boundingBox.png"); mesh = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-mesh.png"); + weights = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-weights.png"); skin = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png"); skinsRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinsRoot.png"); animation = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-animation.png"); @@ -140,12 +146,12 @@ public class SpineEditorUtilities : AssetPostprocessor { public static float defaultScale = 0.01f; public static float defaultMix = 0.2f; public static string defaultShader = "Spine/Skeleton"; - - static SpineEditorUtilities () { + + static SpineEditorUtilities() { DirectoryInfo rootDir = new DirectoryInfo(Application.dataPath); FileInfo[] files = rootDir.GetFiles("SpineEditorUtilities.cs", SearchOption.AllDirectories); editorPath = Path.GetDirectoryName(files[0].FullName.Replace("\\", "/").Replace(Application.dataPath, "Assets")); - editorGUIPath = editorPath + "/GUI"; + editorGUIPath = editorPath + "/GUI"; Icons.Initialize(); @@ -158,7 +164,7 @@ public class SpineEditorUtilities : AssetPostprocessor { HierarchyWindowChanged(); } - static void HierarchyWindowChanged () { + static void HierarchyWindowChanged() { skeletonRendererTable.Clear(); skeletonUtilityBoneTable.Clear(); @@ -172,122 +178,299 @@ public class SpineEditorUtilities : AssetPostprocessor { skeletonUtilityBoneTable.Add(b.gameObject.GetInstanceID(), b); } - static void HierarchyWindowItemOnGUI (int instanceId, Rect selectionRect) { + static void HierarchyWindowItemOnGUI(int instanceId, Rect selectionRect) { if (skeletonRendererTable.ContainsKey(instanceId)) { - Rect r = new Rect(selectionRect); + Rect r = new Rect(selectionRect); r.x = r.width - 15; r.width = 15; GUI.Label(r, Icons.spine); } else if (skeletonUtilityBoneTable.ContainsKey(instanceId)) { - Rect r = new Rect(selectionRect); - r.x -= 26; + Rect r = new Rect(selectionRect); + r.x -= 26; - if (skeletonUtilityBoneTable[instanceId] != null) { - if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0) - r.x += 13; - - r.y += 2; + if (skeletonUtilityBoneTable[instanceId] != null) { + if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0) + r.x += 13; - r.width = 13; - r.height = 13; + r.y += 2; - if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow) { - GUI.DrawTexture(r, Icons.bone); - } else { - GUI.DrawTexture(r, Icons.poseBones); - } + r.width = 13; + r.height = 13; + + if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow) { + GUI.DrawTexture(r, Icons.bone); + } else { + GUI.DrawTexture(r, Icons.poseBones); } - } - } - - [MenuItem("Assets/Spine/Ingest")] - static void IngestSpineProjectFromSelection () { - TextAsset spineJson = null; - TextAsset atlasText = null; - - List spineJsonList = new List(); - - foreach (UnityEngine.Object o in Selection.objects) { - if (o.GetType() != typeof(TextAsset)) - continue; - - string fileName = Path.GetFileName(AssetDatabase.GetAssetPath(o)); - - if (fileName.EndsWith(".json")) - spineJson = (TextAsset)o; - else if (fileName.EndsWith(".atlas.txt")) - atlasText = (TextAsset)o; - } - - if (spineJson == null) { - EditorUtility.DisplayDialog("Error!", "Spine JSON file not found in selection!", "OK"); - return; - } - - string primaryName = Path.GetFileNameWithoutExtension(spineJson.name); - string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)); - - if (atlasText == null) { - string atlasPath = assetPath + "/" + primaryName + ".atlas.txt"; - atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset)); } - AtlasAsset atlasAsset = IngestSpineAtlas(atlasText); - - IngestSpineProject(spineJson, atlasAsset); } - static void OnPostprocessAllAssets (string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) { - //debug -// return; - AtlasAsset sharedAtlas = null; + static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) { - System.Array.Sort(imported); + List atlasPaths = new List(); + List imagePaths = new List(); + List skeletonPaths = new List(); foreach (string str in imported) { - if (Path.GetExtension(str).ToLower() == ".json") { - TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)); - if (IsSpineJSON(spineJson)) { - - if (sharedAtlas != null) { - string spinePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)); - string atlasPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(sharedAtlas)); - if (spinePath != atlasPath) - sharedAtlas = null; + string extension = Path.GetExtension(str).ToLower(); + switch (extension) { + case ".txt": + if (str.EndsWith(".atlas.txt")) { + atlasPaths.Add(str); } - - SkeletonDataAsset data = AutoIngestSpineProject(spineJson, sharedAtlas); - if (data == null) - continue; - - sharedAtlas = data.atlasAsset; - - - string dir = Path.GetDirectoryName(Path.GetDirectoryName(AssetDatabase.GetAssetPath(data))); - string prefabPath = Path.Combine(dir, data.skeletonJSON.name + ".prefab").Replace("\\", "/"); - - if (File.Exists(prefabPath) == false) { - SkeletonAnimation anim = SpawnAnimatedSkeleton(data); - PrefabUtility.CreatePrefab(prefabPath, anim.gameObject, ReplacePrefabOptions.ReplaceNameBased); - if (EditorApplication.isPlaying) - GameObject.Destroy(anim.gameObject); - else - GameObject.DestroyImmediate(anim.gameObject); - } else { - + break; + case ".png": + case ".jpg": + imagePaths.Add(str); + break; + case ".json": + TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)); + if (IsSpineJSON(spineJson)) { + skeletonPaths.Add(str); } + break; + } + } + List atlases = new List(); + + //import atlases first + foreach (string ap in atlasPaths) { + TextAsset atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(ap, typeof(TextAsset)); + AtlasAsset atlas = IngestSpineAtlas(atlasText); + atlases.Add(atlas); + } + + //import skeletons and match them with atlases + bool abortSkeletonImport = false; + foreach (string sp in skeletonPaths) { + string dir = Path.GetDirectoryName(sp); + var localAtlases = FindAtlasesAtPath(dir); + var requiredPaths = GetRequiredAtlasRegions(sp); + var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); + + if (atlasMatch != null) { + IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch); + } else { + bool resolved = false; + while (!resolved) { + int result = EditorUtility.DisplayDialogComplex("Skeleton JSON Import Error!", "Could not find matching AtlasAsset for " + Path.GetFileNameWithoutExtension(sp), "Select", "Skip", "Abort"); + switch (result) { + case -1: + Debug.Log("Select Atlas"); + AtlasAsset selectedAtlas = GetAtlasDialog(Path.GetDirectoryName(sp)); + if (selectedAtlas != null) { + localAtlases.Clear(); + localAtlases.Add(selectedAtlas); + atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); + if (atlasMatch != null) { + resolved = true; + IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch); + } + } + + break; + case 0: + var atlasList = MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(sp), Path.GetFileNameWithoutExtension(sp)); + + if (atlasList != null) + IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasList.ToArray()); + + resolved = true; + break; + + case 1: + Debug.Log("Skipped importing: " + Path.GetFileName(sp)); + resolved = true; + break; + + + case 2: + //abort + abortSkeletonImport = true; + resolved = true; + break; + } + } + } + + if (abortSkeletonImport) + break; + } + + //TODO: any post processing of images + } + + static List MultiAtlasDialog(List requiredPaths, string initialDirectory, string header = "") { + + List atlasAssets = new List(); + + bool resolved = false; + string lastAtlasPath = initialDirectory; + while (!resolved) { + StringBuilder sb = new StringBuilder(); + sb.AppendLine(header); + sb.AppendLine("Atlases:"); + if (atlasAssets.Count == 0) { + sb.AppendLine("\t--none--"); + } + for (int i = 0; i < atlasAssets.Count; i++) { + sb.AppendLine("\t" + atlasAssets[i].name); + } + + sb.AppendLine(); + sb.AppendLine("Missing Regions:"); + + List missingRegions = new List(requiredPaths); + + foreach (var atlasAsset in atlasAssets) { + var atlas = atlasAsset.GetAtlas(); + for (int i = 0; i < missingRegions.Count; i++) { + if (atlas.FindRegion(missingRegions[i]) != null) { + missingRegions.RemoveAt(i); + i--; + } + } + } + + if (missingRegions.Count == 0) { + break; + } + + for (int i = 0; i < missingRegions.Count; i++) { + sb.AppendLine("\t" + missingRegions[i]); + } + + int result = EditorUtility.DisplayDialogComplex("Atlas Selection", sb.ToString(), "Select", "Finish", "Abort"); + + switch(result){ + case 0: + AtlasAsset selectedAtlasAsset = GetAtlasDialog(lastAtlasPath); + if (selectedAtlasAsset != null) { + var atlas = selectedAtlasAsset.GetAtlas(); + bool hasValidRegion = false; + foreach (string str in missingRegions) { + if (atlas.FindRegion(str) != null) { + hasValidRegion = true; + break; + } + } + + atlasAssets.Add(selectedAtlasAsset); + } + break; + + case 1: + resolved = true; + break; + + case 2: + atlasAssets = null; + resolved = true; + break; + } + + + } + + + return atlasAssets; + } + + static AtlasAsset GetAtlasDialog(string dirPath) { + string path = EditorUtility.OpenFilePanel("Select AtlasAsset...", dirPath, "asset"); + if (path == "") + return null; + + int subLen = Application.dataPath.Length - 6; + string assetRelativePath = path.Substring(subLen, path.Length - subLen).Replace("\\", "/"); + + Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAsset)); + + if (obj == null || obj.GetType() != typeof(AtlasAsset)) + return null; + + return (AtlasAsset)obj; + } + + public static List GetRequiredAtlasRegions(string jsonPath) { + List requiredPaths = new List(); + + TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(jsonPath, typeof(TextAsset)); + + StringReader reader = new StringReader(spineJson.text); + var root = Json.Deserialize(reader) as Dictionary; + + foreach (KeyValuePair entry in (Dictionary)root["skins"]) { + foreach (KeyValuePair slotEntry in (Dictionary)entry.Value) { + + foreach (KeyValuePair attachmentEntry in ((Dictionary)slotEntry.Value)) { + var data = ((Dictionary)attachmentEntry.Value); + if (data.ContainsKey("path")) + requiredPaths.Add((string)data["path"]); + else if (data.ContainsKey("name")) + requiredPaths.Add((string)data["name"]); + else + requiredPaths.Add(attachmentEntry.Key); + //requiredPaths.Add((string)sdf["path"]); } } } + + return requiredPaths; + } + static AtlasAsset GetMatchingAtlas(List requiredPaths, List atlasAssets) { + AtlasAsset atlasAssetMatch = null; + + foreach (AtlasAsset a in atlasAssets) { + Atlas atlas = a.GetAtlas(); + bool failed = false; + foreach (string regionPath in requiredPaths) { + if (atlas.FindRegion(regionPath) == null) { + failed = true; + break; + } + } + + if (!failed) { + atlasAssetMatch = a; + break; + } + + } + + return atlasAssetMatch; } - static bool IsSpineJSON (TextAsset asset) { + static List FindAtlasesAtPath(string path) { + List arr = new List(); + + DirectoryInfo dir = new DirectoryInfo(path); + FileInfo[] assetInfoArr = dir.GetFiles("*.asset"); + + int subLen = Application.dataPath.Length - 6; + + foreach (var f in assetInfoArr) { + string assetRelativePath = f.FullName.Substring(subLen, f.FullName.Length - subLen).Replace("\\", "/"); + + Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAsset)); + if (obj != null) { + arr.Add(obj as AtlasAsset); + } + + } + + + return arr; + } + + public static bool IsSpineJSON(TextAsset asset) { object obj = Json.Deserialize(new StringReader(asset.text)); if (obj == null) { Debug.LogError("Is not valid JSON"); @@ -307,51 +490,7 @@ public class SpineEditorUtilities : AssetPostprocessor { return true; } - static SkeletonDataAsset AutoIngestSpineProject (TextAsset spineJson, Object atlasSource = null) { - TextAsset atlasText = null; - AtlasAsset atlasAsset = null; - - if (atlasSource != null) { - if (atlasSource.GetType() == typeof(TextAsset)) { - atlasText = (TextAsset)atlasSource; - } else if (atlasSource.GetType() == typeof(AtlasAsset)) { - atlasAsset = (AtlasAsset)atlasSource; - } - } - - if (atlasText == null && atlasAsset == null) { - string primaryName = Path.GetFileNameWithoutExtension(spineJson.name); - string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)); - - if (atlasText == null) { - string atlasPath = assetPath + "/" + primaryName + ".atlas.txt"; - atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset)); - - if (atlasText == null) { - //can't find atlas, likely because using a shared atlas - bool abort = !EditorUtility.DisplayDialog("Atlas not Found", "Expecting " + spineJson.name + ".atlas\n" + "Press OK to select Atlas", "OK", "Abort"); - if (abort) { - //do nothing, let it error later - } else { - string path = EditorUtility.OpenFilePanel("Find Atlas source...", Path.GetDirectoryName(Application.dataPath) + "/" + assetPath, "txt"); - if (path != "") { - path = path.Replace("\\", "/"); - path = path.Replace(Application.dataPath.Replace("\\", "/"), "Assets"); - atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset)); - } - } - - } - } - } - - if (atlasAsset == null) - atlasAsset = IngestSpineAtlas(atlasText); - - return IngestSpineProject(spineJson, atlasAsset); - } - - static AtlasAsset IngestSpineAtlas (TextAsset atlasText) { + static AtlasAsset IngestSpineAtlas(TextAsset atlasText) { if (atlasText == null) { Debug.LogWarning("Atlas source cannot be null!"); return null; @@ -376,17 +515,17 @@ public class SpineEditorUtilities : AssetPostprocessor { string[] atlasLines = atlasStr.Split('\n'); List pageFiles = new List(); - for (int i = 0; i < atlasLines.Length-1; i++) { + for (int i = 0; i < atlasLines.Length - 1; i++) { if (atlasLines[i].Length == 0) pageFiles.Add(atlasLines[i + 1]); } - + atlasAsset.materials = new Material[pageFiles.Count]; - + for (int i = 0; i < pageFiles.Count; i++) { string texturePath = assetPath + "/" + pageFiles[i]; Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)); - + TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath); texImporter.textureFormat = TextureImporterFormat.AutomaticTruecolor; texImporter.mipmapEnabled = false; @@ -396,13 +535,13 @@ public class SpineEditorUtilities : AssetPostprocessor { EditorUtility.SetDirty(texImporter); AssetDatabase.ImportAsset(texturePath); AssetDatabase.SaveAssets(); - + string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]); - + //because this looks silly if (pageName == primaryName && pageFiles.Count == 1) pageName = "Material"; - + string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat"; Material mat = (Material)AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)); @@ -410,12 +549,12 @@ public class SpineEditorUtilities : AssetPostprocessor { mat = new Material(Shader.Find(defaultShader)); AssetDatabase.CreateAsset(mat, materialPath); } - + mat.mainTexture = texture; EditorUtility.SetDirty(mat); AssetDatabase.SaveAssets(); - + atlasAsset.materials[i] = mat; } @@ -429,40 +568,41 @@ public class SpineEditorUtilities : AssetPostprocessor { return (AtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAsset)); } - static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, AtlasAsset atlasAsset = null) { + static SkeletonDataAsset IngestSpineProject(TextAsset spineJson, params AtlasAsset[] atlasAssets) { string primaryName = Path.GetFileNameWithoutExtension(spineJson.name); string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)); string filePath = assetPath + "/" + primaryName + "_SkeletonData.asset"; - if (spineJson != null && atlasAsset != null) { + if (spineJson != null && atlasAssets != null) { SkeletonDataAsset skelDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset)); if (skelDataAsset == null) { skelDataAsset = SkeletonDataAsset.CreateInstance(); - skelDataAsset.atlasAsset = atlasAsset; + skelDataAsset.atlasAssets = atlasAssets; skelDataAsset.skeletonJSON = spineJson; skelDataAsset.fromAnimation = new string[0]; skelDataAsset.toAnimation = new string[0]; skelDataAsset.duration = new float[0]; skelDataAsset.defaultMix = defaultMix; skelDataAsset.scale = defaultScale; - + AssetDatabase.CreateAsset(skelDataAsset, filePath); AssetDatabase.SaveAssets(); } else { + skelDataAsset.atlasAssets = atlasAssets; skelDataAsset.Reset(); skelDataAsset.GetSkeletonData(true); } return skelDataAsset; } else { - EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and Atlas TextAsset", "OK"); + EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and AtlasAsset array", "OK"); return null; } } [MenuItem("Assets/Spine/Spawn")] - static void SpawnAnimatedSkeleton () { + static void SpawnAnimatedSkeleton() { Object[] arr = Selection.objects; foreach (Object o in arr) { string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(o)); @@ -474,59 +614,66 @@ public class SpineEditorUtilities : AssetPostprocessor { } [MenuItem("Assets/Spine/Spawn", true)] - static bool ValidateSpawnAnimatedSkeleton () { + static bool ValidateSpawnAnimatedSkeleton() { Object[] arr = Selection.objects; - + if (arr.Length == 0) return false; - + foreach (Object o in arr) { if (o.GetType() != typeof(SkeletonDataAsset)) return false; } - + return true; } - public static SkeletonAnimation SpawnAnimatedSkeleton (SkeletonDataAsset skeletonDataAsset, string skinName) { + public static SkeletonAnimation SpawnAnimatedSkeleton(SkeletonDataAsset skeletonDataAsset, string skinName) { return SpawnAnimatedSkeleton(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName)); } - public static SkeletonAnimation SpawnAnimatedSkeleton (SkeletonDataAsset skeletonDataAsset, Skin skin = null) { + public static SkeletonAnimation SpawnAnimatedSkeleton(SkeletonDataAsset skeletonDataAsset, Skin skin = null) { GameObject go = new GameObject(skeletonDataAsset.name.Replace("_SkeletonData", ""), typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation)); SkeletonAnimation anim = go.GetComponent(); anim.skeletonDataAsset = skeletonDataAsset; bool requiresNormals = false; - foreach (Material m in anim.skeletonDataAsset.atlasAsset.materials) { - if (m.shader.name.Contains("Lit")) { - requiresNormals = true; - break; + foreach (AtlasAsset atlasAsset in anim.skeletonDataAsset.atlasAssets) { + foreach (Material m in atlasAsset.materials) { + if (m.shader.name.Contains("Lit")) { + requiresNormals = true; + break; + } } } + + anim.calculateNormals = requiresNormals; SkeletonData data = skeletonDataAsset.GetSkeletonData(true); if (data == null) { - string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAsset); - skeletonDataAsset.atlasAsset = (AtlasAsset)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAsset)); + for(int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++){ + string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); + skeletonDataAsset.atlasAssets[i] = (AtlasAsset)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAsset)); + } + data = skeletonDataAsset.GetSkeletonData(true); } if (skin == null) skin = data.DefaultSkin; - + if (skin == null) skin = data.Skins[0]; anim.Reset(); - + anim.skeleton.SetSkin(skin); anim.initialSkinName = skin.Name; - + anim.skeleton.Update(1); anim.state.Update(1); anim.state.Apply(anim.skeleton); @@ -534,4 +681,4 @@ public class SpineEditorUtilities : AssetPostprocessor { return anim; } -} +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SkeletonDataAsset.cs b/spine-unity/Assets/spine-unity/SkeletonDataAsset.cs index 3e6242dcb..06afb8275 100644 --- a/spine-unity/Assets/spine-unity/SkeletonDataAsset.cs +++ b/spine-unity/Assets/spine-unity/SkeletonDataAsset.cs @@ -35,7 +35,7 @@ using UnityEngine; using Spine; public class SkeletonDataAsset : ScriptableObject { - public AtlasAsset atlasAsset; + public AtlasAsset[] atlasAssets; public TextAsset skeletonJSON; public float scale = 1; public String[] fromAnimation; @@ -45,13 +45,14 @@ public class SkeletonDataAsset : ScriptableObject { private SkeletonData skeletonData; private AnimationStateData stateData; - public void Reset () { + public void Reset() { skeletonData = null; stateData = null; } - public SkeletonData GetSkeletonData (bool quiet) { - if (atlasAsset == null) { + public SkeletonData GetSkeletonData(bool quiet) { + if (atlasAssets == null) { + atlasAssets = new AtlasAsset[0]; if (!quiet) Debug.LogError("Atlas not set for SkeletonData asset: " + name, this); Reset(); @@ -65,16 +66,33 @@ public class SkeletonDataAsset : ScriptableObject { return null; } - Atlas atlas = atlasAsset.GetAtlas(); - if (atlas == null) { + + + if (atlasAssets.Length == 0) { Reset(); return null; } + Atlas[] atlasArr = new Atlas[atlasAssets.Length]; + for (int i = 0; i < atlasAssets.Length; i++) { + if (atlasAssets[i] == null) { + Reset(); + return null; + } + atlasArr[i] = atlasAssets[i].GetAtlas(); + if (atlasArr[i] == null) { + Reset(); + return null; + } + } + + + + if (skeletonData != null) return skeletonData; - SkeletonJson json = new SkeletonJson(atlas); + SkeletonJson json = new SkeletonJson(atlasArr); json.Scale = scale; try { skeletonData = json.ReadSkeletonData(new StringReader(skeletonJSON.text)); @@ -95,7 +113,7 @@ public class SkeletonDataAsset : ScriptableObject { return skeletonData; } - public AnimationStateData GetAnimationStateData () { + public AnimationStateData GetAnimationStateData() { if (stateData != null) return stateData; GetSkeletonData(false); diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs index a483e47e6..e1dad6e58 100644 --- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs +++ b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs @@ -38,71 +38,71 @@ using System.Collections; using Spine; public static class SkeletonExtensions { - - public static void SetColor (this Slot slot, Color color) { + + public static void SetColor(this Slot slot, Color color) { slot.A = color.a; slot.R = color.r; slot.G = color.g; slot.B = color.b; } - public static void SetColor (this Slot slot, Color32 color) { + public static void SetColor(this Slot slot, Color32 color) { slot.A = color.a / 255f; slot.R = color.r / 255f; slot.G = color.g / 255f; slot.B = color.b / 255f; } - public static void SetColor (this RegionAttachment attachment, Color color) { + public static void SetColor(this RegionAttachment attachment, Color color) { attachment.A = color.a; attachment.R = color.r; attachment.G = color.g; attachment.B = color.b; } - public static void SetColor (this RegionAttachment attachment, Color32 color) { + public static void SetColor(this RegionAttachment attachment, Color32 color) { attachment.A = color.a / 255f; attachment.R = color.r / 255f; attachment.G = color.g / 255f; attachment.B = color.b / 255f; } - public static void SetColor (this MeshAttachment attachment, Color color) { + public static void SetColor(this MeshAttachment attachment, Color color) { attachment.A = color.a; attachment.R = color.r; attachment.G = color.g; attachment.B = color.b; } - public static void SetColor (this MeshAttachment attachment, Color32 color) { + public static void SetColor(this MeshAttachment attachment, Color32 color) { attachment.A = color.a / 255f; attachment.R = color.r / 255f; attachment.G = color.g / 255f; attachment.B = color.b / 255f; } - public static void SetColor (this SkinnedMeshAttachment attachment, Color color) { + public static void SetColor(this SkinnedMeshAttachment attachment, Color color) { attachment.A = color.a; attachment.R = color.r; attachment.G = color.g; attachment.B = color.b; } - public static void SetColor (this SkinnedMeshAttachment attachment, Color32 color) { + public static void SetColor(this SkinnedMeshAttachment attachment, Color32 color) { attachment.A = color.a / 255f; attachment.R = color.r / 255f; attachment.G = color.g / 255f; attachment.B = color.b / 255f; } - public static void SetPosition (this Bone bone, Vector2 position) { + public static void SetPosition(this Bone bone, Vector2 position) { bone.X = position.x; bone.Y = position.y; } - public static void SetPosition (this Bone bone, Vector3 position) { + public static void SetPosition(this Bone bone, Vector3 position) { bone.X = position.x; bone.Y = position.y; } -} +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index 30c39da73..07cabff32 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -51,6 +51,14 @@ public class SkeletonRenderer : MonoBehaviour { public float zSpacing; public bool renderMeshes = true, immutableTriangles; public bool logErrors = false; + + [SpineSlot] + public string[] submeshSeparators = new string[0]; + + [HideInInspector] + public List submeshSeparatorSlots = new List(); + + private MeshFilter meshFilter; private Mesh mesh1, mesh2; private bool useMesh1; @@ -62,6 +70,7 @@ public class SkeletonRenderer : MonoBehaviour { private Material[] sharedMaterials = new Material[0]; private readonly List submeshMaterials = new List(); private readonly List submeshes = new List(); + public virtual void Reset () { if (meshFilter != null) @@ -99,6 +108,12 @@ public class SkeletonRenderer : MonoBehaviour { skeleton = new Skeleton(skeletonData); if (initialSkinName != null && initialSkinName.Length > 0 && initialSkinName != "default") skeleton.SetSkin(initialSkinName); + + submeshSeparatorSlots.Clear(); + for (int i = 0; i < submeshSeparators.Length; i++) { + submeshSeparatorSlots.Add(skeleton.FindSlot(submeshSeparators[i])); + } + if (OnReset != null) OnReset(this); } @@ -156,7 +171,8 @@ public class SkeletonRenderer : MonoBehaviour { // Populate submesh when material changes. Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; - if ((lastMaterial != material && lastMaterial != null) || slot.Data.name[0] == '*') { + + if ((lastMaterial != material && lastMaterial != null) || submeshSeparatorSlots.Contains(slot)) { AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false); submeshTriangleCount = 0; submeshFirstVertex = vertexCount; diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs index c088353f2..86f96e942 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; public class SkeletonUtilityKinematicShadow : MonoBehaviour { public bool hideShadow = true; + public Transform parent; Dictionary shadowTable; GameObject shadowRoot; @@ -12,7 +13,10 @@ public class SkeletonUtilityKinematicShadow : MonoBehaviour { if (hideShadow) shadowRoot.hideFlags = HideFlags.HideInHierarchy; - shadowRoot.transform.parent = transform.root; + if(parent == null) + shadowRoot.transform.parent = transform.root; + else + shadowRoot.transform.parent = parent; shadowTable = new Dictionary(); diff --git a/spine-unity/Assets/spine-unity/SpineAttributes.cs b/spine-unity/Assets/spine-unity/SpineAttributes.cs new file mode 100644 index 000000000..727196d49 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SpineAttributes.cs @@ -0,0 +1,111 @@ +using UnityEngine; +using System.Collections; + +public class SpineSlot : PropertyAttribute { + public string startsWith = ""; + public string dataSource = ""; + + /// + /// + /// + /// + /// SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset + public SpineSlot(string startsWith = "", string dataSource = "") { + this.startsWith = startsWith; + this.dataSource = dataSource; + } +} + +public class SpineSkin : PropertyAttribute { + public string startsWith = ""; + public string dataSource = ""; + + /// + /// + /// + /// + /// SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset + public SpineSkin(string startsWith = "", string dataSource = "") { + this.startsWith = startsWith; + this.dataSource = dataSource; + } +} + +public class SpineAtlasRegion : PropertyAttribute { + +} + +public class SpineAnimation : PropertyAttribute { + public string startsWith = ""; + public string dataSource = ""; + + /// + /// + /// + /// + /// SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset + public SpineAnimation(string startsWith = "", string dataSource = "") { + this.startsWith = startsWith; + this.dataSource = dataSource; + } +} + +public class SpineAttachment : PropertyAttribute { + public bool returnFullPath; + public bool currentSkinOnly; + public string dataSource = ""; + public string slotSource = ""; + + + public SpineAttachment() { + + } + + public SpineAttachment(bool currentSkinOnly = true, bool returnFullPath = false, string slot = "", string dataSource = "") { + this.currentSkinOnly = currentSkinOnly; + this.returnFullPath = returnFullPath; + this.slotSource = slot; + this.dataSource = dataSource; + } + + public static Hierarchy GetHierarchy(string fullPath) { + return new Hierarchy(fullPath); + } + + public static Spine.Attachment GetAttachment(string fullPath, Spine.SkeletonData skeletonData) { + var hierarchy = SpineAttachment.GetHierarchy(fullPath); + if (hierarchy.name == "") + return null; + + return skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name); + } + + public static Spine.Attachment GetAttachment(string fullPath, SkeletonDataAsset skeletonDataAsset) { + return GetAttachment(fullPath, skeletonDataAsset.GetSkeletonData(true)); + } + + public struct Hierarchy { + public string skin; + public string slot; + public string name; + + public Hierarchy(string fullPath) { + string[] chunks = fullPath.Split(new char[]{'/'}, System.StringSplitOptions.RemoveEmptyEntries); + if (chunks.Length == 0) { + skin = ""; + slot = ""; + name = ""; + return; + } + else if (chunks.Length < 2) { + throw new System.Exception("Cannot generate Attachment Hierarchy from string! Not enough components! [" + fullPath + "]"); + } + skin = chunks[0]; + slot = chunks[1]; + name = ""; + for (int i = 2; i < chunks.Length; i++) { + name += chunks[i]; + } + } + } +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SpineAttributes.cs.meta b/spine-unity/Assets/spine-unity/SpineAttributes.cs.meta new file mode 100644 index 000000000..fe4c14b95 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SpineAttributes.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce216f51ebc1d3f40929f4e58d1c65e5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: From d60bc9241ceab9b4e0ac29aa46a29fd0459f5416 Mon Sep 17 00:00:00 2001 From: Fenrisul Date: Fri, 23 Jan 2015 00:01:32 -0800 Subject: [PATCH 2/4] more attributes more bug fixes more helper menus even more examples --- .../Scenes/Attributes and AtlasRegions.unity | Bin 20844 -> 23236 bytes .../Examples/Scenes/Mix and Match.unity | Bin 18572 -> 21156 bytes .../Examples/Scenes/Spineboy Movement.unity | Bin 9078 -> 21588 bytes .../Scripts/BasicPlatformerController.cs | 12 +- .../Assets/Examples/Scripts/Chimera.cs | 38 +++- .../Examples/Scripts/DynamicSpineBone.cs | 66 ++++++ .../Examples/Scripts/DynamicSpineBone.cs.meta | 8 + .../Examples/Scripts/FootSoldierExample.cs | 40 +++- .../Examples/Scripts/SpineboyController.cs | 36 +++- .../Spine/Spineboy/spineboy_Atlas.asset | Bin 531 -> 4184 bytes spine-unity/Assets/spine-unity/CustomSkin.cs | 36 ++++ .../Assets/spine-unity/CustomSkin.cs.meta | 8 + .../spine-unity/Editor/AtlasAssetInspector.cs | 18 ++ .../Editor/GUI/icon-weights.png.meta | 2 +- .../Editor/SkeletonDataAssetInspector.cs | 36 +++- .../Editor/SpineAttributeDrawers.cs | 191 +++++++++++++++--- .../Editor/SpineEditorUtilities.cs | 56 ++++- .../Assets/spine-unity/SpineAttributes.cs | 159 +++++++++++---- 18 files changed, 620 insertions(+), 86 deletions(-) create mode 100644 spine-unity/Assets/Examples/Scripts/DynamicSpineBone.cs create mode 100644 spine-unity/Assets/Examples/Scripts/DynamicSpineBone.cs.meta create mode 100644 spine-unity/Assets/spine-unity/CustomSkin.cs create mode 100644 spine-unity/Assets/spine-unity/CustomSkin.cs.meta diff --git a/spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity b/spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity index eadbc4873f48ce5994ef8c347e10bb2864c072c0..cc0f39f32e3b0e7df6ea0d5cfaa6a71699067dfc 100644 GIT binary patch delta 1235 zcmaKre@IhN6vyw=xml^XNZT^l~LQ1rv1f{36W6!d3MRDT9hL_hxOpP(Q1J#+I%e|X@$d+z6+opbIvci%24 z&+aJ=jOiK14n1RxErWd?E8E_Nm?dzAX2R?Z(dtzj4Xm2 z&|6{W{dO6#jAhFkC0@y!oo-uXvbGtaRJjNn$$2H^m}hmws%JfW6Shbv64ubHd%cXh zybam3P-8JMB<$Hz6qJIS=Y(t)fZpD4JfL{wWMFViFZ)>4gaZSZ&PgL+Q!sjA(^W_Z z>kl>j1Un16;Fkb9Q^Xht+nd)U*p)mx0Y-Wh>_wg(#-8*T*ykcPmUCDQKsp4NC|;bn zb#mWa{DA*e0$A>W$ zu*u0-J?ss6?F5U0E$l)U*nO}le17Kx`oKJ{#cX2Po1qaf0lz}g=fK{BEsR&X0}gXi zK4+m7$$s0gN4I3nWM-6$coHv#W8PNQj)}B%_KdsVe);kG;-4|_Xkdy7Sx!G+zqE)6s9;N8cli&wMDV3K)Jyq0u5^7h$_Q~&|Bl50R zDGzH0+!!c(KRTWBqK`v9*T&o!%OdKOePPRmo-w|H<90RjQ+Qn7YIDe~L8olg);Ce% z3*%s$6T19vVZ`wde+uoy{JRiEW$Z%N^0#%Z2)0gkXk|+V=(OUaj7>d(;)mz|58$CT z`wDHQ@lxs3LAO9!Np}>tx-Ce4zTd5z7G=ZcJqW diff --git a/spine-unity/Assets/Examples/Scenes/Mix and Match.unity b/spine-unity/Assets/Examples/Scenes/Mix and Match.unity index 06731d193734e3c12f259376965aca7553d6fc76..775cb6bf7db3097d97bbac2b472558eca9a6248c 100644 GIT binary patch delta 1003 zcmZ9K%TE+R5Ql5_1?aAV5ilII35$Z^5kL(=<+TsMCyGW6Bs%O4I}_PiGt+zUks$G+ z2?w>~^PsDNg9-|+s0R=0fy6`)c*2W@#6&&9AAoDs?x2gERJ!V$>i*SK_1Fz*d_t-O zI4}utd>jA@&`;qGyXyATH4HVt?{qp{i1A9YCV$d7<891;xuIK1J}7u(vuV2Macf0= zXEnW7)(kMw(KS6HQjXo?j;mO#bGna0K3xaUrRa*Gh1lVk9)qyVWx$)$TeBZQqWvm> z9XFF3cnO%XxDir1IG00eRMB}Rf1CL1st}`|Q=-dLB2`c%dBw7uNtI%~vs~IP9=glK z5s$0zzk@q6sa2WO>P+g+Wpii|LxX&Ux zX9M8qQ)`I5M)nKY8T3mndxNYSf5wY(xn*zZEV2_AJ1lFt`@QOe9Y)|Df>q(Y2vy7& zK(=Cu?4v|vxx)LAwL8}ew<1d*%N1^;v&eFVpG+^-GZ(d zx7a0QWRu92EJj6=O(84H%YNUCG1+ru*OBE4V+io$Fc3)bA81vJ#!aIXzl?1 z+cV0yh2{3C)W^q__h-I{mCkOl&{-pbzD>zNUr_3&9#TJPQIDzLv}gu23tBXzRi9=^ ztPCv@8ywbjvo@-jDy#CvO&*Ifdc4&DV#(j^phqBT0?dxX6bA$4tu!T7k;5Bt4=Y1* ze3;iq;yM`=Av3gy%9$$bVWx2<${LYjTfkH`WjHK4d}Y}?#{xX-ID!LN=e^Inh2$_f zXI*Y6x~r*l(d%>E3_3+^Ag_oDSUmsY@3nc! IK%mS12To%KVE_OC delta 371 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 diff --git a/spine-unity/Assets/Examples/Scripts/BasicPlatformerController.cs b/spine-unity/Assets/Examples/Scripts/BasicPlatformerController.cs index 071dc48cc..761ac31af 100644 --- a/spine-unity/Assets/Examples/Scripts/BasicPlatformerController.cs +++ b/spine-unity/Assets/Examples/Scripts/BasicPlatformerController.cs @@ -71,17 +71,17 @@ public class BasicPlatformerController : MonoBehaviour { #if UNITY_4_5 [Header("Animation")] #endif - [SpineAnimation(dataSource: "skeletonAnimation")] + [SpineAnimation(dataField: "skeletonAnimation")] public string walkName = "Walk"; - [SpineAnimation(dataSource: "skeletonAnimation")] + [SpineAnimation(dataField: "skeletonAnimation")] public string runName = "Run"; - [SpineAnimation(dataSource: "skeletonAnimation")] + [SpineAnimation(dataField: "skeletonAnimation")] public string idleName = "Idle"; - [SpineAnimation(dataSource: "skeletonAnimation")] + [SpineAnimation(dataField: "skeletonAnimation")] public string jumpName = "Jump"; - [SpineAnimation(dataSource: "skeletonAnimation")] + [SpineAnimation(dataField: "skeletonAnimation")] public string fallName = "Fall"; - [SpineAnimation(dataSource: "skeletonAnimation")] + [SpineAnimation(dataField: "skeletonAnimation")] public string crouchName = "Crouch"; #if UNITY_4_5 diff --git a/spine-unity/Assets/Examples/Scripts/Chimera.cs b/spine-unity/Assets/Examples/Scripts/Chimera.cs index 35cab0362..27f831f86 100644 --- a/spine-unity/Assets/Examples/Scripts/Chimera.cs +++ b/spine-unity/Assets/Examples/Scripts/Chimera.cs @@ -1,11 +1,45 @@ -using UnityEngine; +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Basic Platformer Controller created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ +using UnityEngine; using System.Collections; public class Chimera : MonoBehaviour { public SkeletonDataAsset skeletonDataSource; - [SpineAttachment(currentSkinOnly: false, returnFullPath: true, dataSource: "skeletonDataSource")] + [SpineAttachment(currentSkinOnly: false, returnAttachmentPath: true, dataField: "skeletonDataSource")] public string attachmentPath; [SpineSlot] diff --git a/spine-unity/Assets/Examples/Scripts/DynamicSpineBone.cs b/spine-unity/Assets/Examples/Scripts/DynamicSpineBone.cs new file mode 100644 index 000000000..c638f696e --- /dev/null +++ b/spine-unity/Assets/Examples/Scripts/DynamicSpineBone.cs @@ -0,0 +1,66 @@ +using UnityEngine; +using System.Collections; + +public class DynamicSpineBone : MonoBehaviour { + + public Transform speedReference; + + [SpineBone] + public string boneName; + + [Range(-90, 90)] + public float minRotation = -45; + [Range(-90, 90)] + public float maxRotation = 45; + + [Range(-2000, 2000)] + public float rotationFactor = 300; + + [Range(5, 30)] + public float returnSpeed = 10; + + [Range(100, 1000)] + public float boneSpeed = 300; + + public float returnThreshhold = 0.01f; + + public bool useAcceleration; + + + SkeletonAnimation skeletonAnimation; + float goalRotation; + Spine.Bone bone; + Vector3 velocity; + Vector3 acceleration; + Vector3 lastPosition; + + void Start() { + if (speedReference == null) + speedReference = transform; + + skeletonAnimation = GetComponent(); + bone = SpineBone.GetBone(boneName, skeletonAnimation); + skeletonAnimation.UpdateLocal += UpdateLocal; + lastPosition = speedReference.position; + } + + void FixedUpdate() { + acceleration = (speedReference.position - lastPosition) - velocity; + velocity = speedReference.position - lastPosition; + lastPosition = speedReference.position; + } + + void UpdateLocal(SkeletonAnimation animation) { + Vector3 vec = useAcceleration ? acceleration : velocity; + + if (Mathf.Abs(vec.x) < returnThreshhold) + goalRotation = Mathf.Lerp(goalRotation, 0, returnSpeed * Time.deltaTime); + else + goalRotation += vec.x * rotationFactor * Time.deltaTime * (bone.WorldFlipX ? -1 : 1); + + goalRotation = Mathf.Clamp(goalRotation, minRotation, maxRotation); + + bone.Rotation = Mathf.Lerp(bone.Rotation, bone.Rotation + goalRotation, boneSpeed * Time.deltaTime); + + } +} diff --git a/spine-unity/Assets/Examples/Scripts/DynamicSpineBone.cs.meta b/spine-unity/Assets/Examples/Scripts/DynamicSpineBone.cs.meta new file mode 100644 index 000000000..6aac53582 --- /dev/null +++ b/spine-unity/Assets/Examples/Scripts/DynamicSpineBone.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7dae3f4db9a24bf4abe2059526bfd689 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs b/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs index d85f99847..655445869 100644 --- a/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs +++ b/spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs @@ -1,4 +1,38 @@ -using UnityEngine; +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * FootSoldierExample created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ +using UnityEngine; using System.Collections; public class FootSoldierExample : MonoBehaviour { @@ -11,10 +45,10 @@ public class FootSoldierExample : MonoBehaviour { [SpineSlot] public string eyesSlot; - [SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")] + [SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")] public string eyesOpenAttachment; - [SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")] + [SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")] public string blinkAttachment; [Range(0, 0.2f)] diff --git a/spine-unity/Assets/Examples/Scripts/SpineboyController.cs b/spine-unity/Assets/Examples/Scripts/SpineboyController.cs index 4cebc7de3..064152df4 100644 --- a/spine-unity/Assets/Examples/Scripts/SpineboyController.cs +++ b/spine-unity/Assets/Examples/Scripts/SpineboyController.cs @@ -1,4 +1,38 @@ -using UnityEngine; +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * SpineboyController created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ +using UnityEngine; using System.Collections; [RequireComponent(typeof(SkeletonAnimation), typeof(Rigidbody2D))] diff --git a/spine-unity/Assets/Examples/Spine/Spineboy/spineboy_Atlas.asset b/spine-unity/Assets/Examples/Spine/Spineboy/spineboy_Atlas.asset index ae8491bec74d3e193f738ff88d2696e58fc2fd32..ae6be64dcb8048658a50f8f7e43c6b46ddc7e000 100644 GIT binary patch literal 4184 zcmeHKJ8u&~5FP^w@An(?NRc{HB!nnXWGC2Qqy$TVL`Agrt?iBMyJ&Y4*;M`mh#HB) z1uddQ)Je@>;6Ko%z|7-ppY5ZezOj7!`ex^wZ}v`i01Mv%F1-bS)7WAI@NnhP%4%a3 z{tSo19FDOWZbo6Wu3Ku~M0*z2mD4=Uc)Sn{`T%FK*$bU%hB{a>p@+`)%i4~v`{yRm z<+f@%IDrs`$L*+Jt$O>U6c``bQrBzTBnsEiziM?u)vC(s(92$M3SE!kpN!md_@l7| zESt8jJmomY34t~OQC~n+epM!LZH0j*{d{# zmPCxnh;kck2?B?ix2Hwo$jQ7_VK9^S?DOd>5OVS79*bkQb^KrR*bti zH`X{oYh0>(Gn>#*Qr(P$tx460?)@2XYLX8UpnoR0lmenD;#&Cql~?IGOvlY)OOaqF zU-{V2AC*6S-pIWx94*Te?Qn2d?+t>j53alTCFDTyEEdx)$}ei}Wc#tMZ~cIC#N0nF06Tr0ur*(Hklti71I)JdxLKi#5wG>2^(s;lJC37?&7(XwuHS zc{4M9o2?%anUZMyI$NSqH$onEqN}YxCgoH$`w7K_h$xQZ9wmgKn{eU&MC+z*ZuL8S z+NN_NLTJBzmLFRA2V3ez1-n)teE!}zZ9s0o>Dpf?0(}`<>D7IpoCcg#?X|0+`in1N zum78!*B~oh3PjFQ^V0gp{c-W4oIUt~G9mn&WP)~`4bzZHQZSR_ToN!TD+*O4j9|?% z1H|o~V*h%6YCSXBbi{B^Vjf M@=Wp{O?ryH0X8w6y8r+H diff --git a/spine-unity/Assets/spine-unity/CustomSkin.cs b/spine-unity/Assets/spine-unity/CustomSkin.cs new file mode 100644 index 000000000..5b98ad66c --- /dev/null +++ b/spine-unity/Assets/spine-unity/CustomSkin.cs @@ -0,0 +1,36 @@ +using UnityEngine; +using System.Collections; +using Spine; + +public class CustomSkin : MonoBehaviour { + + + [System.Serializable] + public class SkinPair { + [SpineAttachment(currentSkinOnly: false, returnAttachmentPath: true, dataField: "skinSource")] + public string sourceAttachment; + [SpineSlot] + public string targetSlot; + [SpineAttachment(currentSkinOnly: true, placeholdersOnly: true)] + public string targetAttachment; + } + + public SkeletonDataAsset skinSource; + public SkinPair[] skinning; + public Skin customSkin; + + SkeletonRenderer skeletonRenderer; + void Start() { + skeletonRenderer = GetComponent(); + Skeleton skeleton = skeletonRenderer.skeleton; + + customSkin = new Skin("CustomSkin"); + + foreach (var pair in skinning) { + var attachment = SpineAttachment.GetAttachment(pair.sourceAttachment, skinSource); + customSkin.AddAttachment(skeleton.FindSlotIndex(pair.targetSlot), pair.targetAttachment, attachment); + } + + skeleton.SetSkin(customSkin); + } +} diff --git a/spine-unity/Assets/spine-unity/CustomSkin.cs.meta b/spine-unity/Assets/spine-unity/CustomSkin.cs.meta new file mode 100644 index 000000000..3a7ba7a9d --- /dev/null +++ b/spine-unity/Assets/spine-unity/CustomSkin.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6e55c8477eccddc4cb5c3551a3945ca7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs index fc07c6fae..a58fc9340 100644 --- a/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs @@ -50,9 +50,27 @@ public class AtlasAssetInspector : Editor { serializedObject.Update(); AtlasAsset asset = (AtlasAsset)target; + EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(atlasFile); EditorGUILayout.PropertyField(materials, true); + if (EditorGUI.EndChangeCheck()) + serializedObject.ApplyModifiedProperties(); + if (materials.arraySize == 0) { + EditorGUILayout.LabelField(new GUIContent("Error: Missing materials", SpineEditorUtilities.Icons.warning)); + return; + } + + for (int i = 0; i < materials.arraySize; i++) { + SerializedProperty prop = materials.GetArrayElementAtIndex(i); + Material mat = (Material)prop.objectReferenceValue; + if (mat == null) { + EditorGUILayout.LabelField(new GUIContent("Error: Materials cannot be null", SpineEditorUtilities.Icons.warning)); + return; + } + } + + if (atlasFile.objectReferenceValue != null) { Atlas atlas = asset.GetAtlas(); diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png.meta index fa7031fc0..067337d4f 100644 --- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png.meta +++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png.meta @@ -21,7 +21,7 @@ TextureImporter: grayScaleToAlpha: 0 generateCubemap: 0 seamlessCubemap: 0 - textureFormat: -1 + textureFormat: -3 maxTextureSize: 1024 textureSettings: filterMode: -1 diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs index 0edf206e6..d2dfb0dbe 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs @@ -102,12 +102,18 @@ public class SkeletonDataAssetInspector : Editor { EditorGUILayout.PropertyField(skeletonJSON); EditorGUILayout.PropertyField(scale); if (EditorGUI.EndChangeCheck()) { - if (m_previewUtility != null) { - m_previewUtility.Cleanup(); - m_previewUtility = null; - } + if (serializedObject.ApplyModifiedProperties()) { - RepopulateWarnings(); + if (m_previewUtility != null) { + m_previewUtility.Cleanup(); + m_previewUtility = null; + } + + RepopulateWarnings(); + OnEnable(); + return; + } + } @@ -118,6 +124,8 @@ public class SkeletonDataAssetInspector : Editor { DrawSlotList(); } else { + + DrawReimportButton(); //Show Warnings foreach (var str in warnings) EditorGUILayout.LabelField(new GUIContent(str, SpineEditorUtilities.Icons.warning)); @@ -132,6 +140,24 @@ public class SkeletonDataAssetInspector : Editor { } } + void DrawReimportButton() { + EditorGUI.BeginDisabledGroup(skeletonJSON.objectReferenceValue == null); + if (GUILayout.Button(new GUIContent("Attempt Reimport", SpineEditorUtilities.Icons.warning))) { + SpineEditorUtilities.ImportSpineContent(new string[] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, true); + + if (m_previewUtility != null) { + m_previewUtility.Cleanup(); + m_previewUtility = null; + } + + RepopulateWarnings(); + OnEnable(); + return; + + } + EditorGUI.EndDisabledGroup(); + } + void DrawAnimationStateInfo() { showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data"); if (!showAnimationStateData) diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs index cdc9a0e37..9d9e3b3d2 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs @@ -1,4 +1,38 @@ -using UnityEngine; +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Spine Attribute Drawers created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ +using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; @@ -32,13 +66,13 @@ public class SpineSlotDrawer : PropertyDrawer { SpineSlot attrib = (SpineSlot)attribute; - var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource); + var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - if (skeletonDataAssetProperty != null) { - if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue; - } else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) { - var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue; + if (dataProperty != null) { + if (dataProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; + } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; if (renderer != null) skeletonDataAsset = renderer.skeletonDataAsset; } else { @@ -102,7 +136,6 @@ public class SpineSlotDrawer : PropertyDrawer { public class SpineSkinDrawer : PropertyDrawer { SkeletonDataAsset skeletonDataAsset; - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (property.propertyType != SerializedPropertyType.String) { EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); @@ -111,13 +144,13 @@ public class SpineSkinDrawer : PropertyDrawer { SpineSkin attrib = (SpineSkin)attribute; - var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource); + var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - if (skeletonDataAssetProperty != null) { - if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue; - } else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) { - var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue; + if (dataProperty != null) { + if (dataProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; + } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; if (renderer != null) skeletonDataAsset = renderer.skeletonDataAsset; } else { @@ -256,13 +289,13 @@ public class SpineAnimationDrawer : PropertyDrawer { SpineAnimation attrib = (SpineAnimation)attribute; - var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource); + var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - if (skeletonDataAssetProperty != null) { - if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue; - } else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) { - var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue; + if (dataProperty != null) { + if (dataProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; + } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; if (renderer != null) skeletonDataAsset = renderer.skeletonDataAsset; } else { @@ -332,13 +365,13 @@ public class SpineAttachmentDrawer : PropertyDrawer { SpineAttachment attrib = (SpineAttachment)attribute; - var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource); + var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - if (skeletonDataAssetProperty != null) { - if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue; - } else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) { - var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue; + if (dataProperty != null) { + if (dataProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; + } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; if (renderer != null) skeletonDataAsset = renderer.skeletonDataAsset; else { @@ -381,8 +414,11 @@ public class SpineAttachmentDrawer : PropertyDrawer { List validSkins = new List(); if (skeletonRenderer != null && attrib.currentSkinOnly) { - if (skeletonRenderer.skeleton.Skin != null) + if (skeletonRenderer.skeleton.Skin != null) { validSkins.Add(skeletonRenderer.skeleton.Skin); + } else { + validSkins.Add(data.Skins[0]); + } } else { foreach (Skin skin in data.Skins) { if (skin != null) @@ -392,6 +428,8 @@ public class SpineAttachmentDrawer : PropertyDrawer { GenericMenu menu = new GenericMenu(); List attachmentNames = new List(); + List placeholderNames = new List(); + string prefix = ""; if (skeletonRenderer != null && attrib.currentSkinOnly) @@ -405,7 +443,7 @@ public class SpineAttachmentDrawer : PropertyDrawer { Skin defaultSkin = data.Skins[0]; - SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotSource); + SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotField); string slotMatch = ""; if (slotProperty != null) { if (slotProperty.propertyType == SerializedPropertyType.String) { @@ -424,18 +462,31 @@ public class SpineAttachmentDrawer : PropertyDrawer { continue; attachmentNames.Clear(); + placeholderNames.Clear(); + skin.FindNamesForSlot(i, attachmentNames); - if (skin != defaultSkin) + if (skin != defaultSkin) { defaultSkin.FindNamesForSlot(i, attachmentNames); + skin.FindNamesForSlot(i, placeholderNames); + } + for (int a = 0; a < attachmentNames.Count; a++) { + string attachmentPath = attachmentNames[a]; string menuPath = prefix + data.Slots[i].Name + "/" + attachmentPath; string name = attachmentNames[a]; - if (attrib.returnFullPath) + if (attrib.returnAttachmentPath) name = skin.Name + "/" + data.Slots[i].Name + "/" + attachmentPath; - menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + + if (attrib.placeholdersOnly && placeholderNames.Contains(attachmentPath) == false) { + menu.AddDisabledItem(new GUIContent(menuPath)); + } else { + menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + + } } } @@ -454,3 +505,81 @@ public class SpineAttachmentDrawer : PropertyDrawer { return 18; } } + +[CustomPropertyDrawer(typeof(SpineBone))] +public class SpineBoneDrawer : PropertyDrawer { + SkeletonDataAsset skeletonDataAsset; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + if (property.propertyType != SerializedPropertyType.String) { + EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); + return; + } + + SpineBone attrib = (SpineBone)attribute; + + var dataProperty = property.serializedObject.FindProperty(attrib.dataField); + + if (dataProperty != null) { + if (dataProperty.objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; + } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { + var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; + if (renderer != null) + skeletonDataAsset = renderer.skeletonDataAsset; + } else { + EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); + return; + } + + } else if (property.serializedObject.targetObject is Component) { + var component = (Component)property.serializedObject.targetObject; + if (component.GetComponent() != null) { + var skeletonRenderer = component.GetComponent(); + skeletonDataAsset = skeletonRenderer.skeletonDataAsset; + } + } + + if (skeletonDataAsset == null) { + EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); + return; + } + + position = EditorGUI.PrefixLabel(position, label); + + if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { + Selector(property); + } + + } + + void Selector(SerializedProperty property) { + SpineBone attrib = (SpineBone)attribute; + SkeletonData data = skeletonDataAsset.GetSkeletonData(true); + if (data == null) + return; + + GenericMenu menu = new GenericMenu(); + + menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); + menu.AddSeparator(""); + + for (int i = 0; i < data.Bones.Count; i++) { + string name = data.Bones[i].Name; + if (name.StartsWith(attrib.startsWith)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + + menu.ShowAsContext(); + } + + void HandleSelect(object val) { + var pair = (SpineDrawerValuePair)val; + pair.property.stringValue = pair.str; + pair.property.serializedObject.ApplyModifiedProperties(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + return 18; + } +} diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index f939ce455..428860341 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -209,8 +209,10 @@ public class SpineEditorUtilities : AssetPostprocessor { } - static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) { + ImportSpineContent(imported, false); + } + public static void ImportSpineContent(string[] imported, bool reimport = false) { List atlasPaths = new List(); List imagePaths = new List(); @@ -242,6 +244,9 @@ public class SpineEditorUtilities : AssetPostprocessor { //import atlases first foreach (string ap in atlasPaths) { + if (!reimport && CheckForValidAtlas(ap)) + continue; + TextAsset atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(ap, typeof(TextAsset)); AtlasAsset atlas = IngestSpineAtlas(atlasText); atlases.Add(atlas); @@ -250,7 +255,14 @@ public class SpineEditorUtilities : AssetPostprocessor { //import skeletons and match them with atlases bool abortSkeletonImport = false; foreach (string sp in skeletonPaths) { + if (!reimport && CheckForValidSkeletonData(sp)) { + Debug.Log("Automatically skipping: " + sp); + continue; + } + + string dir = Path.GetDirectoryName(sp); + var localAtlases = FindAtlasesAtPath(dir); var requiredPaths = GetRequiredAtlasRegions(sp); var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); @@ -307,6 +319,48 @@ public class SpineEditorUtilities : AssetPostprocessor { //TODO: any post processing of images } + static bool CheckForValidSkeletonData(string skeletonJSONPath) { + + string dir = Path.GetDirectoryName(skeletonJSONPath); + TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonJSONPath, typeof(TextAsset)); + DirectoryInfo dirInfo = new DirectoryInfo(dir); + + FileInfo[] files = dirInfo.GetFiles("*.asset"); + + foreach (var f in files) { + string localPath = dir + "/" + f.Name; + var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object)); + if (obj is SkeletonDataAsset) { + var skeletonDataAsset = (SkeletonDataAsset)obj; + if (skeletonDataAsset.skeletonJSON == textAsset) + return true; + } + } + + return false; + } + + static bool CheckForValidAtlas(string atlasPath) { + + string dir = Path.GetDirectoryName(atlasPath); + TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset)); + DirectoryInfo dirInfo = new DirectoryInfo(dir); + + FileInfo[] files = dirInfo.GetFiles("*.asset"); + + foreach (var f in files) { + string localPath = dir + "/" + f.Name; + var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object)); + if (obj is AtlasAsset) { + var atlasAsset = (AtlasAsset)obj; + if (atlasAsset.atlasFile == textAsset) + return true; + } + } + + return false; + } + static List MultiAtlasDialog(List requiredPaths, string initialDirectory, string header = "") { List atlasAssets = new List(); diff --git a/spine-unity/Assets/spine-unity/SpineAttributes.cs b/spine-unity/Assets/spine-unity/SpineAttributes.cs index 727196d49..1bf15bca2 100644 --- a/spine-unity/Assets/spine-unity/SpineAttributes.cs +++ b/spine-unity/Assets/spine-unity/SpineAttributes.cs @@ -1,87 +1,138 @@ -using UnityEngine; +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +/***************************************************************************** + * Spine Attributes created by Mitch Thompson + * Full irrevocable rights and permissions granted to Esoteric Software +*****************************************************************************/ +using UnityEngine; using System.Collections; public class SpineSlot : PropertyAttribute { public string startsWith = ""; - public string dataSource = ""; + public string dataField = ""; /// - /// + /// Smart popup menu for Spine Slots /// - /// - /// SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset - public SpineSlot(string startsWith = "", string dataSource = "") { + /// Filters popup results to elements that begin with supplied string. + /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. + /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives). + /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. + /// + public SpineSlot(string startsWith = "", string dataField = "") { this.startsWith = startsWith; - this.dataSource = dataSource; + this.dataField = dataField; } } public class SpineSkin : PropertyAttribute { public string startsWith = ""; - public string dataSource = ""; + public string dataField = ""; /// - /// + /// Smart popup menu for Spine Skins /// - /// - /// SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset - public SpineSkin(string startsWith = "", string dataSource = "") { + /// Filters popup results to elements that begin with supplied string. + /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. + /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) + /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. + /// + public SpineSkin(string startsWith = "", string dataField = "") { this.startsWith = startsWith; - this.dataSource = dataSource; + this.dataField = dataField; } } - -public class SpineAtlasRegion : PropertyAttribute { - -} - public class SpineAnimation : PropertyAttribute { public string startsWith = ""; - public string dataSource = ""; + public string dataField = ""; /// - /// + /// Smart popup menu for Spine Animations /// - /// - /// SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset - public SpineAnimation(string startsWith = "", string dataSource = "") { + /// Filters popup results to elements that begin with supplied string. + /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. + /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) + /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. + /// + public SpineAnimation(string startsWith = "", string dataField = "") { this.startsWith = startsWith; - this.dataSource = dataSource; + this.dataField = dataField; } } public class SpineAttachment : PropertyAttribute { - public bool returnFullPath; - public bool currentSkinOnly; - public string dataSource = ""; - public string slotSource = ""; + public bool returnAttachmentPath = false; + public bool currentSkinOnly = false; + public bool placeholdersOnly = false; + public string dataField = ""; + public string slotField = ""; public SpineAttachment() { } - public SpineAttachment(bool currentSkinOnly = true, bool returnFullPath = false, string slot = "", string dataSource = "") { + /// + /// Smart popup menu for Spine Attachments + /// + /// Filters popup results to only include the current Skin. Only valid when a SkeletonRenderer is the data source. + /// Returns a fully qualified path for an Attachment in the format "Skin/Slot/AttachmentName" + /// Filters popup results to exclude attachments that are not children of Skin Placeholders + /// If specified, a locally scoped field with the name supplied by in slotField will be used to limit the popup results to children of a named slot + /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. + /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) + /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. + /// + public SpineAttachment(bool currentSkinOnly = true, bool returnAttachmentPath = false, bool placeholdersOnly = false, string slotField = "", string dataField = "") { this.currentSkinOnly = currentSkinOnly; - this.returnFullPath = returnFullPath; - this.slotSource = slot; - this.dataSource = dataSource; + this.returnAttachmentPath = returnAttachmentPath; + this.placeholdersOnly = placeholdersOnly; + this.slotField = slotField; + this.dataField = dataField; } public static Hierarchy GetHierarchy(string fullPath) { return new Hierarchy(fullPath); } - public static Spine.Attachment GetAttachment(string fullPath, Spine.SkeletonData skeletonData) { - var hierarchy = SpineAttachment.GetHierarchy(fullPath); + public static Spine.Attachment GetAttachment(string attachmentPath, Spine.SkeletonData skeletonData) { + var hierarchy = SpineAttachment.GetHierarchy(attachmentPath); if (hierarchy.name == "") return null; return skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name); } - public static Spine.Attachment GetAttachment(string fullPath, SkeletonDataAsset skeletonDataAsset) { - return GetAttachment(fullPath, skeletonDataAsset.GetSkeletonData(true)); + public static Spine.Attachment GetAttachment(string attachmentPath, SkeletonDataAsset skeletonDataAsset) { + return GetAttachment(attachmentPath, skeletonDataAsset.GetSkeletonData(true)); } public struct Hierarchy { @@ -108,4 +159,40 @@ public class SpineAttachment : PropertyAttribute { } } } +} + +public class SpineBone : PropertyAttribute { + public string startsWith = ""; + public string dataField = ""; + + /// + /// Smart popup menu for Spine Bones + /// + /// Filters popup results to elements that begin with supplied string. + /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. + /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) + /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. + /// + public SpineBone(string startsWith = "", string dataField = "") { + this.startsWith = startsWith; + this.dataField = dataField; + } + + public static Spine.Bone GetBone(string boneName, SkeletonRenderer renderer) { + if (renderer.skeleton == null) + return null; + + return renderer.skeleton.FindBone(boneName); + } + + public static Spine.BoneData GetBoneData(string boneName, SkeletonDataAsset skeletonDataAsset) { + var data = skeletonDataAsset.GetSkeletonData(true); + + return data.FindBone(boneName); + } +} + +public class SpineAtlasRegion : PropertyAttribute { + //TODO: Standardize with Skeleton attributes + //NOTE: For now, relies on locally scoped field named "atlasAsset" for source. } \ No newline at end of file From 9911183a3dc2628c061ab03595c62f2061d8e5bc Mon Sep 17 00:00:00 2001 From: Fenrisul Date: Fri, 23 Jan 2015 00:21:27 -0800 Subject: [PATCH 3/4] Initial import error fix --- .../Assets/spine-unity/Editor/AtlasAssetInspector.cs | 1 + .../spine-unity/Editor/SkeletonDataAssetInspector.cs | 2 ++ .../spine-unity/Editor/SkeletonRendererInspector.cs | 1 + .../Assets/spine-unity/Editor/SpineEditorUtilities.cs | 11 +++++++++++ 4 files changed, 15 insertions(+) diff --git a/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs index a58fc9340..72b0a68d0 100644 --- a/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs @@ -42,6 +42,7 @@ public class AtlasAssetInspector : Editor { private SerializedProperty atlasFile, materials; void OnEnable () { + SpineEditorUtilities.ConfirmInitialization(); atlasFile = serializedObject.FindProperty("atlasFile"); materials = serializedObject.FindProperty("materials"); } diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs index d2dfb0dbe..a47765d54 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs @@ -60,6 +60,8 @@ public class SkeletonDataAssetInspector : Editor { void OnEnable() { + SpineEditorUtilities.ConfirmInitialization(); + try { atlasAssets = serializedObject.FindProperty("atlasAssets"); skeletonJSON = serializedObject.FindProperty("skeletonJSON"); diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs index 7428c9522..5dbff2514 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs @@ -36,6 +36,7 @@ public class SkeletonRendererInspector : Editor { protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, submeshSeparators; protected virtual void OnEnable () { + SpineEditorUtilities.ConfirmInitialization(); skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset"); initialSkinName = serializedObject.FindProperty("initialSkinName"); normals = serializedObject.FindProperty("calculateNormals"); diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index 428860341..5624ad02d 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -146,8 +146,13 @@ public class SpineEditorUtilities : AssetPostprocessor { public static float defaultScale = 0.01f; public static float defaultMix = 0.2f; public static string defaultShader = "Spine/Skeleton"; + public static bool initialized; static SpineEditorUtilities() { + Initialize(); + } + + static void Initialize(){ DirectoryInfo rootDir = new DirectoryInfo(Application.dataPath); FileInfo[] files = rootDir.GetFiles("SpineEditorUtilities.cs", SearchOption.AllDirectories); editorPath = Path.GetDirectoryName(files[0].FullName.Replace("\\", "/").Replace(Application.dataPath, "Assets")); @@ -162,6 +167,12 @@ public class SpineEditorUtilities : AssetPostprocessor { EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI; HierarchyWindowChanged(); + initialized = true; + } + + public static void ConfirmInitialization(){ + if(!initialized || Icons.skeleton == null) + Initialize(); } static void HierarchyWindowChanged() { From 7638ed96ff1de5c33de8d69c7dc494757f7edb7d Mon Sep 17 00:00:00 2001 From: Fenrisul Date: Fri, 23 Jan 2015 00:23:41 -0800 Subject: [PATCH 4/4] Missing reference fix --- .../Spine/Spineboy/spineboy_Atlas.asset | Bin 4184 -> 4184 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/spine-unity/Assets/Examples/Spine/Spineboy/spineboy_Atlas.asset b/spine-unity/Assets/Examples/Spine/Spineboy/spineboy_Atlas.asset index ae6be64dcb8048658a50f8f7e43c6b46ddc7e000..7a117dfbe006f5ef10dd8e20c9373c23bca4a8e4 100644 GIT binary patch delta 55 zcmV-70LcH?AlM)T000Hfu>_X|0Rxkq1uzi=INT&sg)T*)CcFBZ^mSVTv(W`V3X>cV NGzbF#001BhAOP|O5Dx$V delta 41 scmcbia6^HGfq`|$MwaQUj7*c~uo`TB#%jhj`2(xeWElYy4hARy001lr