Pharan

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

mixnmatch.gif

mix-and-match-spine-unity.zip
(89.09 KiB) Downloaded 399 times


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.
placeholders.png
skins.png

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.
mixmatchatlas.png


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.
User avatar
Pharan

Pharan
Posts: 4444

SavedByZero

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.
SavedByZero
Posts: 9

Pharan

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

Pharan
Posts: 4444

Ken

It looks really great! How can I do this in cocos2d-x?
Ken
Posts: 8

Pharan

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.
User avatar
Pharan

Pharan
Posts: 4444

BinaryCats

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,
User avatar
BinaryCats
Posts: 1299

Pharan

@BinaryCats
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.
User avatar
Pharan

Pharan
Posts: 4444

BinaryCats

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.
User avatar
BinaryCats
Posts: 1299


Arnissan

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.
Arnissan
Posts: 17

sonolil

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 2~3 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.
sonolil
Posts: 1

PeterBacall

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
PeterBacall
Posts: 35

Pharan

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.
User avatar
Pharan

Pharan
Posts: 4444

PeterBacall

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
PeterBacall
Posts: 35

Pharan

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.
User avatar
Pharan

Pharan
Posts: 4444

PeterBacall

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.
PeterBacall
Posts: 35

Pharan

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?
User avatar
Pharan

Pharan
Posts: 4444

PeterBacall

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".
PeterBacall
Posts: 35

DavidSmit

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.
DavidSmit
Posts: 2

Pharan

MixAndMatch.cs is a sample script. It wasn't designed to be used with anything but the sample assets.
As with the other sample scripts, they're designed to be read so you understand what code needs to be used to achieve their effect, and use them in your own scripts. This is why it's in the Examples folder.

Here's how the sample MixAndMatch.cs script works in short:
You give it the name of your base/template skin as an information source, where it can find the template attachments.
You give it the slot and names of those template attachments you intend to use.
You give it sprites to use as the new images for those templates.

then
It uses the specific sprites, and the template attachments for them, and puts them in a new custom skin.
It optionally repacks all the sprites into a runtime atlas. If it does this, it also includes the default skin (the stuff that's not in skin placeholders in the editor) in the packing.
Then it gives the new custom skin to the Skeleton as its new active skin.

We're open to suggestions and feedback if you find that the examples aren't clear enough. :)
User avatar
Pharan

Pharan
Posts: 4444

DavidSmit

Thanks ! ^^

I'm not sure why it did not work with my older assets.
I remade my asset in spine and created an custom script (based on MixAndMatch) to modify it. Now it works just fine! ^^

I love that the MeshAnimations are just transferred and this skin-swapping is so much easier now! ^^
DavidSmit
Posts: 2

IndieDoroid

@Pharan This looks awesome!! Is there time from you guys to create a tutorial video? It'd be much appreciated by the less tech savy guys on this forum (including me)
IndieDoroid
Posts: 8


Return to Unity