• Unity
  • Equips, Customization and Mix and Match

Related Discussions
...

For equips, character customization and mix and match, the ideal solution is to use dynamic skins composed at runtime.


mix-and-match-spine-unity.zip

Attached is a .spine project you can open in Spine 3.1 or higher along with its images.
And a .unitypackage you can import into your project.
The .unitypackage includes sample scene, code and two separate jsons for compatibility with Spine 3.3/3.4 or Spine 3.0-3.2.
The Spine runtime is not included.

SPINE EDITOR SIDE
The Spine project shows how the different parts/equips are split into their own Skins.

See the Skin named "//preview" to preview the animations. Having a "// preview" skin will allow you to see a complete skeleton while you are animating in Animate Mode. The Spine editor currently has no other way of previewing a combination of multiple skins.

The skeleton has two equippable swords and two eye variants.
Each sword has 3 images drawn at different angles, to showcase that an equip can be animated, and can have more than one attachment. Each eye type also has open and closed images.

UNITY SIDE
The .unitypackage contains sample scene, exports and code on how multiple skins are combined into a custom skin at runtime.
Open the Unity scene and play it.
Press SPACEBAR to play the animation.
The character will swing the sword (swap between 3 images).
The character will also blink (swap between 2 images)

You can "customize" the sword and the eyes on the fly by pressing the 1 and 2 keys.

See "MixAndMatchSampleController.cs" to learn about the code.
Essentially, it shows you how to get references to skins defined in Spine Editor, and combine them into a new runtime-generated skin which you can then modify freely.

void GenerateSkin () {
   // Make a new Skin, and add the entries from existing skins defined in Spine Editor.
   Skin mySkin = new Skin("My Generated Skin");
   SkeletonData skeletonData = skeletonAnimation.skeletonDataAsset.GetSkeletonData(false);
   AddSkinEntries(skeletonData.FindSkin("sword:orange"), mySkin);
   AddSkinEntries(skeletonData.FindSkin("eyes:tall"), mySkin);

   // You can also set individual attachments by using Skin.AddAttachment
   // This way, you can populate your custom skin with Spine.Attachments from another source. It doesn't need to be from Skins you made in Spine editor.
   //mySkin.AddAttachment(noseSlotIndex, "nose", someNoseAttachment);

   // Removing is a bit tricky (for now)
   //mySkin.Attachments.Remove(new Skin.AttachmentKeyTuple(mustacheSlotIndex, "mustache"));

   // Now that your custom generated skin is complete, assign it to the skeleton...
   var skeleton = skeletonAnimation.skeleton;
   skeleton.SetSkin(mySkin);

   // ...and make sure the changed attachments are visually applied.
   skeleton.SetSlotsToSetupPose();
   skeletonAnimation.state.Apply(skeleton);
}

static void AddSkinEntries (Skin source, Skin destination) {
   var sourceAttachments = source.Attachments;
   var destinationAttachments = destination.Attachments;
   foreach (var m in sourceAttachments)
      destinationAttachments[m.Key] = m.Value;
}

The sample code prioritizes readability over architecture/optimization. So you should structure actual production code according to your needs.


22 Sep 2016 12:42 pm


Here is a separate set of sample experimental methods that can help integrate UnityEngine.Sprites or loose Texture assets into your Spine Skeleton. Similar basic functionality is also provided by the Spine.Unity.Modules.SpriteAttacher module.

AttachmentUtility.cs on Gist

Resulting attachments can be added to your dynamic skins.

But this still requires a pre-created single atlas image, it seems. I can see the orange and blue and different eye shades in the material before I run it.

That's where converting sprites to RegionAttachments comes in, as mentioned.

4 days later

It looks really great! How can I do this in cocos2d-x?

Thanks for your interest. I'm not too familiar with cocos2d-x.
You can post a new topic in the Runtimes forum. Other users may be able to help you.

We have a similar thing, we call it setting an addative skin (would be nice if it was default to the run times)

private SkeletonAnimation m_Animation;

public void SetSkinAddative(string name)
{
    Spine.Skin Current = m_Animation.skeleton.skin;
    Spine.Skin New = m_Animation.skeleton.data.FindSkin(name);
    Spine.Skin Merged = Current;
    foreach ( var a  in New.Attachments)
    {
        if (Merged.Attachments.ContainsKey(a.Key))
        {
            Merged.Attachments[a.Key] = a.Value;
        }
        else
            Merged.AddAttachment(a.Key.slotIndex,a.Value.Name, a.Value);
    }

m_Animation.skeleton.SetSkin(Merged);

}

We have other code, in another project, which has SetSkinSubtractive. We also keep a list of what skins are added or subtracted so we can re-create that model (as the order matters) if needed


28 Sep 2016, 10:12


our case handles if the default skin does not have a image visable in the slot, but the added skin does,

@[deleted]
1) You'll note from AddAttachment's code:

public void AddAttachment (int slotIndex, String name, Attachment attachment) {
   if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null.");
   attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment;
}

That you don't really need the (Merged.Attachments.ContainsKey) if block.
You can just use AddAttachment in all cases, or Attachments[a.Key] = a.Value in all cases. They're pretty much the same thing.

2) I think we'll have something very similar when skin composition is implemented officially for all runtimes. I think it'll be outside of SkeletonData/Skeleton's API though (skinName param would not make sense).
For any extra convenience, we can always add it on the Spine-Unity side of things, where it doesn't make a mess of things.

Hmm, I guess I didn't know what the new AttachmentKeyTuple(slotIndex, name) would have done if it already existed. i.e. why does it need to new up a key, when that key already exits. Surley it would be better (like my code) to check if the key exists first, if it does replace the value?

oh, its good to hear that skins are not complete in the runtimes. I thought they where pretty much a signed off feature.

4 months later

This is exactly what I need! But the problem is, I'm not a coder and I'm making my game mainly with visual scripting asset Fungus.

So I'm trying to make this work in the dumb way - making my own spine test file with similar skin setup and changing the names in script from "sword" to "jacket" while leaving the eyes as they were but giving them my own skin names. Unfortunately it did not work.

After an hour or two I've gotten my stickman test file next to Mix and Match Black dude. My stickman plays the idle animation and jumps for attack animation but my script edits keep getting compile errors:

string jacketSkinName = currentJacket == 0 ? bigJacket : smallJacket;
string eyesSkinName = currentEyes == 0 ? longEyes : smallEyes;

Says that things like "bigJacket", "smallJacket", "longEyes" and "smallEyes" do not exist in the context when I run debugger. I'd give my left foot for a video tutorial on this.

This is exactly what I was looking for.
I've been playing with skins and so far I've achieved similar effects in the editor.

Research tells me Spine does not allow multiple skins to be visible at the same time however.
That's a bit of a shame. I would like to be able to make all these combinations visible in the editor.
Or maybe it could use a higher manager tier for skins like a "skin set" that organizes parts and disallows clashes.

I also think some support for loopable clips would be nice. Ones that are independent from the bone animation timeline.
For example I could loop my traditionally drawn hair clips independent from all other bodily actions so that they are reusable and repeatable. Otherwise I'd have to change them manually every frame in the dopesheet, even if the loop is only 23 frames long.
(NVM I just realized there was such a thing as layering. Still not part of the editor if I'm correct... I must read the manual some more.)

I feel like it can do better concerning Equipment/Customization + Traditional Animation along with Bone/Mesh animations.
Somehow the editor gives the illusion that only one of either is intuitively feasible.

But I'm grateful it seems rather easy to implement in runtime.

3 months later

Hi!

I've been using Spine for a couple of weeks, I'm new...

How exactly does AddAttachment work? I can't seem to find a clear answer.

string originalKey = "sword:orange"; // the skin holder? is this the "string name" in AddAttachment?
int slotIndex = skeleton.FindSlotIndex("Weapon"); // name of the slot, in Spine?
var originalAttachment = mySkin.GetAttachment(slotIndex, originalKey); 

mySkin.AddAttachment(slotIndex, originalKey, originalAttachment);

Thanks in advance,
Peter

A skin is a dictionary of attachment names, slots and actual attachments.
Imagine its contents like this:

slot#     attachment name     attachment object
================================================
3         "red"               {a red-colored glove.}
3         "blue"              {a blue-colored glove.}
5         "large"             {a large shield.}
5         "red"               {a special red shield.}
6         "left shoe"         {the left shoe}
7         "right shoe"        {the right shoe}
...
...

During an animation that keys attachments, or when the skeleton returns to its setup pose, the system will use the skin to determine what attachment should be used.
AddAttachment works by adding or replacing items in the skin, so that the next time the skin is used for a lookup, it will use the value stored in it.

Pharan wrote

A skin is a dictionary of attachment names, slots and actual attachments.
Imagine its contents like this:

slot#     attachment name     attachment object
================================================
3         "red"               {a red-colored glove.}
3         "blue"              {a blue-colored glove.}
5         "large"             {a large shield.}
5         "red"               {a special red shield.}
6         "left shoe"         {the left shoe}
7         "right shoe"        {the right shoe}
...
...

During an animation that keys attachments, or when the skeleton returns to its setup pose, the system will use the skin to determine what attachment should be used.
AddAttachment works by adding or replacing items in the skin, so that the next time the skin is used for a lookup, it will use the value stored in it.

Thank you for the explanation Pharan :beer:
Maybe this is a stupid question: Is there a limit on how many materials Spine can generate for a character i Unity? Lets say you have 100 weapons, which requires 100 skins in Spine, which would have to generate 25-50-ish(?) sprites and materials in Unity. I just want to know if this is doable on a bigger scale. Cheers

You may not want the solution in this thread since it's a bit old.
The latest spine-unity unitypackage has a MixAndMatch.cs sample script and Mix and Match example scene that shows you how to source your attachments from Unity Sprites, rather than having to pre-define and pre-pack them in Spine.
The current example is a bit ridiculous. The upcoming Spine-Unity for 3.6 has a much more plausible setup. But the ideas should be there in the script

So you don't need to add the 100 weapons in Spine. (ie, you don't need a lot of materials)
In Spine, you just need to add the standard-sized weapons and things and pattern the dimensions of your other weapons on those.

Pharan wrote

You may not want the solution in this thread since it's a bit old.
The latest spine-unity unitypackage has a MixAndMatch.cs sample script and Mix and Match example scene that shows you how to source your attachments from Unity Sprites, rather than having to pre-define and pre-pack them in Spine.
The current example is a bit ridiculous. The upcoming Spine-Unity for 3.6 has a much more plausible setup. But the ideas should be there in the script

So you don't need to add the 100 weapons in Spine. (ie, you don't need a lot of materials)
In Spine, you just need to add the standard-sized weapons and things and pattern the dimensions of your other weapons on those.

My problem with the 'Mix And Match' example was the "Runtime Repack", together with ToddRivers "Sprite Shaders for Unity" or Spine/Sprite/VertexLit. I dragged his shader into the "Repack Shader" slot, but couldn't figure out how to make it Repack with my own settings that I want. The results was just a black sprite. If I untoggled "Runtime Repack", it loaded the sprite with the default "Spine/Skeleton" shader So my question is: How do you lit the sprites correctly with the methods from 'Mix And Match'?

I figured if you do it from Spine, like the example you provided in this topic, you can really go into depth how each weapon is going to be displayed, different meshes (for like capes and good for VertexLit shaders etc). So It's still the better option in my opinion. But I'm a beginner, so I don't really know the down or ups with either method. Just letting you know my experience.

It's actually the same "method". It's loading attachments into custom-defined skins.

MixAndMatch just builds on this. It essentially does the same thing, and also shows examples of how to use the new runtime features like 1) Using Unity Sprites to make new attachments. 2) using Unity Sprites to map to copies of existing meshes 3) Repacking so you can fit more into one texture, which improves performance and reduces chances of Unity's rendering quirks from using multiple materials.

Doing it the old way is just too cumbersome to recommend to people who need to do arbitrarily large collections of items and equips. The more equips you have, the more difficult it becomes to manage in Spine's interface, and you would have to repack every time you add something new. It's probably fine for games that aren't sprawling RPGs and just have limited customization.

Can you start a new topic describing the problem you had with "just a black sprite"?
It's not much to go on to be able to tell give advice.
Can you give a description of your setup and screenshots?

Pharan wrote

It's actually the same "method". It's loading attachments into custom-defined skins.

MixAndMatch just builds on this. It essentially does the same thing, and also shows examples of how to use the new runtime features like 1) Using Unity Sprites to make new attachments. 2) using Unity Sprites to map to copies of existing meshes 3) Repacking so you can fit more into one texture, which improves performance and reduces chances of Unity's rendering quirks from using multiple materials.

Doing it the old way is just too cumbersome to recommend to people who need to do arbitrarily large collections of items and equips. The more equips you have, the more difficult it becomes to manage in Spine's interface, and you would have to repack every time you add something new. It's probably fine for games that aren't sprawling RPGs and just have limited customization.

Can you start a new topic describing the problem you had with "just a black sprite"?
It's not much to go on to be able to tell give advice.
Can you give a description of your setup and screenshots?

Thank you Pharan! I'll start a new topic on the "just a black sprite".

2 months later

Heya!

I've been trying to use the Mix and Match script from 3.6 to see how it works, but when I apply unity sprites through the script it applies those sprites at the right slots, but removes the old skin completely. So the new skin only consists of those new sprites.

The example MixAndMatch scene works perfectly though.. I'm I missing a setting?

Thanks!

EDIT: It seems to have something to do with the Skeleton animation. If I replace the Mix and Match skeleton asset with my own exported skeletondata, it also removes all the old atlas elements, and only uses the newly assigned onces.