Ahh, that docs page was definitely the missing link I needed to explain the current system, and your script also works perfectly. Thanks!
shawnblais

- 24 de Ago de 2018
- Se unió 17 de Ago de 2018
Hey guys, having a very frustrating time trying to get a very simple implementation working, where I swap 1 sprite for another in Unity 2018.1.9f1. We have a generic in-hand attachment in spine, and would like to swap it with any number of sprites in Unity, all with the same origin pt, and texture size.
I've tried 3 different methods, and encountered 3 totally different bugs. To make it worse, many links on your forums and faqs just 404 to github (ie: https://github.com/pharan/spine-unity-docs/blob/master/Mix-and-Match.md)
BoneFollower
I tried using a bone follower, attached to the slot, which almost works... but when flipping the X, there's a a 1-frame flicker where the rotation is inverted: http://treefortress.com/shared/2018-08-24_10-58-42.mp4,I tried changing from LateUpdate to Update, but there are dependancies littered through the code-base calling into this class with LateUpdate, so it turned into a can of worms. Tried changing script execution order, didn't work.
SpriteAttacher
I tried using SpriteAttacher, but it rendered a white sprite for no discernible reason.
If I select "PMA Vertex Colors" on the Skeleton, it then decides to work... But it took me a long time to notice that, and I'm still confused as to why?
AddAttachment Method
I then tried the method shown in EquipMixAndMatch example, and despite doing everything properly, the editor is throwing errors.NullReferenceException: Object reference not set to an instance of an object
Spine.Unity.MeshGenerator.GenerateSkeletonRendererInstruction (Spine.Unity.SkeletonRendererInstruction instructionOutput, Spine.Skeleton skeleton, System.Collections.Generic.Dictionary2 customSlotMaterials, System.Collections.Generic.List
1 separatorSlots, Boolean generateMeshOverride, Boolean immutableTriangles) (at Assets/Plugins/Spine/spine-unity/Mesh Generation/SpineMesh.cs:366)
Spine.Unity.SkeletonRenderer.LateUpdate () (at Assets/Plugins/Spine/spine-unity/Components/SkeletonRenderer.cs:274)The weird thing about the error above, if I step through it in the debugger... nothing is null. So confused...
UPDATE: If I set PMA to true, in the templateAttachment.GetRemappedClone() call, Method 3 works, and the error goes away. So it seems I need to use the ToRegionAttachmentPMAClone() API regardless if I want PMA or not, just to get a valid attachment, something is broken with sprite.ToAtlasRegion()
Overall I find it very hard to diagnose what is going wrong at any step in the process, there's so many dependancies, extension scripts, editor utilities, and so much complexity, and all I want to do, is just attach 1 sprite to 1 bone, and it's been a massive headache.
It's great that the advanced use cases are served, but it would be nice to add like a single, self-contained code-based example, of attaching a unity sprite, to a bone in the most straightforward way with as little architecture in the way to obfuscate the actual API calls.
In the interest of being constructive, here's the bare minimum script I could come up with, that works currently in Unity to swap a sprite:
using UnityEngine; using Spine.Unity.Modules.AttachmentTools; using Spine.Unity; using Spine; public class SpineSlotAttacher : MonoBehaviour { public SkeletonAnimation skeletonAnimation; [SpineSkin] public string skinName; [SpineSlot] public string targetSlot; [SpineAttachment(currentSkinOnly = true)] public string attachmentName; //Sprite to swap public Sprite sprite; //Internal int slotIndex; Material sourceMaterial; Attachment templateAttachment; Skin defaultSkin; Skin equipsSkin = new Skin("Equips"); Material runtimeMaterial; Texture2D runtimeAtlas; void Start() { var dataAsset = skeletonAnimation.SkeletonDataAsset; var skeletonData = dataAsset.GetSkeletonData(true); sourceMaterial = dataAsset.atlasAssets[0].materials[0]; defaultSkin = skeletonData.FindSkin(skinName); slotIndex = skeletonData.FindSlotIndex(targetSlot); templateAttachment = defaultSkin.GetAttachment(slotIndex, attachmentName); //Append the baseSkin to our new skin, so we don't lose any existing attachments. equipsSkin.Append(defaultSkin); //Attach unity sprite AttachSprite(sprite); } public void AttachSprite(Sprite sprite, bool optimize = true) { //PMA must be true here, or null reference errors will be thrown var attachment = templateAttachment.GetRemappedClone(sprite, sourceMaterial, premultiplyAlpha: true); equipsSkin.AddAttachment(slotIndex, attachmentName, attachment); if (optimize) { skeletonAnimation.Skeleton.Skin = equipsSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].materials[0], out runtimeMaterial, out runtimeAtlas); } else { skeletonAnimation.Skeleton.Skin = equipsSkin; } RefreshSkeletonAttachments(); } void RefreshSkeletonAttachments() { skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); //skeletonAnimation.Update(0); } }
With the script above, it now becomes trivial to swap-sprites from some other control script:
void Update() { if (Input.GetKeyDown(KeyCode.Alpha1)) { slotAttacher.AttachSprite(axe); } if (Input.GetKeyDown(KeyCode.Alpha2)) { slotAttacher.AttachSprite(shovel); } //ETC }
- Editado