- Modifié
Multiple skins approach
I want to use multiple skins in one animation. Main skin is the complete outfit of the character (blouse, trousers, boots etc.) and some secondary skins that doesn't tied with main one
like head, weapon and hand band. (And in advance I'd like to change skin tone...)
Should I extend basic Skin class in order to fully correspond to my demands?
I suppose that my CompositeSkin class should contain collection of common Skins and return first non-empty value after traversal all collection elements.
The suggested way to do this is to create a new, empty skin and populate it with multiple other skins.
I have made dummy skin "empty" where filled all skin placeholders (clothes hanger icon) with same empty png texture. And now applying skin in runtime looks like setting basic "empty" skin and then sequential applying needed skins like outfit, weapon and hand band.
But to do it right, I have created new method SetSkinOverride at Skin class that simply iterates through all skin attachments and place them into skeleton slots and finally not overwriting private skin member with new one.
Everything works fine, but I think it's look very cumbersome, especially making of empty skin. Or probably I have not understood your point.
By making an empty skin, I mean:
Skin skin = new Skin();
There's no need to put any "empty" attachments into it. If there is no entry for a skin placeholder name -> attachment, then there is no attachment for that placeholder. Next you fill it with skins:
SkeletonData skeletonData = ...
skin.addAttachments(skeletonData.findSkin("skin1"));
skin.addAttachments(skeletonData.findSkin("skin2"));
Now that you have your skin, you apply it to one or more skeletons:
Skeleton skeleton = ...
skeleton.setSkin(skin);
Note that Skin addAttachments
is in the reference implementation (spine-libgdx), but doesn't appear to be in the other runtimes. Pharan can show how to do it in C#, if needed. We have an issue to provide this for all runtimes:
https://waffle.io/EsotericSoftware/spine/cards/58aebb3957f9608b0127af3a
I've managed to use multiskin option as you proposed. I create empty instance of skin and then apply another skins in particular order so later applied skins can override some slots of earlier applied ones. Then I set my multiskin to the skeleton through setSkin method.
But this works only for first pass when I create instance of skeleton and then apply multiskin. If I'll set new multiskin to the same skeleton
strange behavior of Skin's method attachAll will update just slots of current skin.
So I have to write my own version of setting skin method that overrides this behavior and acts like branch for empty current skin in Skeleton's setSkin method. Moreover to cleanup slots that became empty in new multiskin I'm not checking attachments for null and simply pass them to slots like this:
var slots = skeleton.slots;
for (i in 0...slots.length) {
var slot = slots[i];
var name = slot.data.attachmentName;
if (name != null) {
var attachment = skin.getAttachment(i, name);
slot.setAttachment(attachment);
}
}
skeleton.skin = skin;
It leads me to the next problem
after such update I have lost traversing of defaultSkin values for empty slots. I think my solution is slightly incorrect.
Oh, I have found the
skeleton.setSlotsToSetupPose();
method!
But my main question about continuous setting up skins still actual.
See Skeleton setSkin
for what happens when you change a skin. It doesn't assume you want the setup pose attachments, so call Skeleton setSlotsToSetupPose
afterwards if that is what you need, as you found.
Not sure if you still have a question?