• Editor
  • Frame by frame animation or image change with skins

Greetings!
Let me tell you: I have a new asset to animate that involves the use of several skins (let's call them "normal," "damaged," and "defeated"). They are the same elements with changed color details, nothing serious. The problem is that in addition to these elements, I have parts that change appearance within the animation itself, for example: open hands, closed hands, furrowed brows, or "happy" expressions... which do not belong to a specific skin.

My idea is to have skins for the parts that will be affected (in this case, for example, the clothing) but also frame-by-frame animations or skins that will require a sprite change (as far as I know, a placeholder skin only supports one attachment).

I'm not sure if I'm being clear enough, but if there's any doubt, I'll try to explain it in another way. I greatly appreciate the effort and assistance!

Related Discussions
...

You can place only the elements that belong to a skin in skin placeholders, and leave the common parts outside of them, then use them in animations by attaching one or the other at the right time as you normally would 😃

Thank you for your answer @Erika !

What should I do when those common parts should disappear?

For example, this is the "defeat" skin (the bones) selected, but all the slots with multiple attachments not included in any skin placeholder are also shown:

How could I avoid these parts showing up if they are not linked to a placeholder (as they should change, for example, opening and closing hands)?

I'm not sure I understand, but in case you mean how to make some attachments or skin placeholders not visible, you can just click on their visibility icon in the tree at the right part of the animation. If this death animation should be visible only in said death animation, then you can make sure none of the related images are visible in setup.
Then, in animate mode, just click on each little attachment icon that is not the one you want to be visible to disable it.

Hello again, @Erika, I've been working on this project and found a simple solution that works for me.

The issue now I have is about mixing skins.

I want to achieve what happens when I pin 2 skins in my preview window:

Each one has it own placeholder:

(this is the same for every part)

And I'm trying to do what the mixing skins documentation mentions here:
https://es.esotericsoftware.com/spine-unity-mix-and-match

However, instead of achieving this:

I'm getting this:

The code where I try to mix both skins is

private const string shockingWithBones = "shockWithBone";
[SerializeField] [SpineSkin] private string bonesSkin;
[SerializeField] [SpineSkin] private string shockSkin;
[...]
mixSkin = new Skin(shockingWithBones);
mixSkin.AddSkin(skeletonData.FindSkin(shockSkin));
mixSkin.AddSkin(skeletonData.FindSkin(bonesSkin));
skeleton.SetSkin(mixSkin);

I also tried changing the addskin lines order, with no change.

Could you help me with this?
Thank you very much in advance, let me know if you need anything else to explain the problem!

The order you add the skins matters. In your code boneSkin will override attachments in shockSkin. You may want to add shockSkin last to reverse this.

  • Yimec님이 이에 답장했습니다.

    Nate The order you add the skins matters.

    As I said, it is not working either, at last, the visible result is the same

    The skin change is responding a spine event, here the complete script logic related to this:

    public void Shocking()
        {
            TrackEntry shockAnimation = spineAnimationState.SetAnimation(0, shock, false);
            shockAnimation.Event += EventManager;
            spineAnimationState.SetAnimation(4, hideParts, true);
            shockAnimation.Complete += EndShock;
        }
        void EndShock(TrackEntry track)
        {
            spineAnimationState.ClearTrack(4);
            skeleton.SetSkin(normalSkin);
            currentSkin = normalSkin;
            skeleton.SetSlotsToSetupPose();
            spineAnimationState.AddAnimation(0, idleBody, true, 0);
        }
    void EventManager(TrackEntry trackEntry, Spine.Event e)
        {
    
            switch (e.Data.Name)
            {
             
                case "BonesSwitch":
                    if (bonesOn)
                    {
                        skeleton.SetSkin(shockSkin);
                        currentSkin = shockSkin;
                        bonesOn = false;
                        break;
                    }
                    else
                    {
                        mixSkin = new Skin(shockingWithBones);
                        mixSkin.AddSkin(skeletonData.FindSkin(bonesSkin));
                        mixSkin.AddSkin(skeletonData.FindSkin(shockSkin));
                        skeleton.SetSkin(mixSkin);
                        bonesOn = true;
                        break;
                    }
    
                default:
                    break;
            }
        }

    Thank you!

    Sorry I missed that part.

    See how setSkin works:
    http://esotericsoftware.com/spine-api-reference#Skeleton-setSkin
    It doesn't change attachments unless it's sure you want them (because the equivalent in the old skin was attached). This means you may want to use skeleton.SetSlotsToSetupPose() or manually set which attachments are visible after changing the skin.

    Alright, brief update:

    changing "mixSkin.AddSkin(skeletonData.FindSkin(bonesSkin));" with the actual name of the skin ("Shock-Bones") made this work.

    However, how could I reference the skin as defined in the inspector?

    • Harald님이 이에 답장했습니다.

      Yimec However, how could I reference the skin as defined in the inspector?

      Could you please describe what you mean by this sentence? Which "skin as defined in the inspector"?

      Sorry, sometimes I have troubles explaining myself as my language is not English.

      I meant I created a variable ([SerializeField] [SpineSkin] private string shockSkin😉 and wanted to use "shockSkin" instead of the string name, and... I realised this is possible as long the problem is not that, it was the lack of SetSlotsToSetupPose() line. I'm sorry.

      Skins is a really difficult topic to me to understand, so I apologize for my silly questions. However, with your guidance and my brute force testing, I found a way to achieve what I wanted, so I'm pretty thankful.

      I'm talking with my game's producer to include you all in the game credits once it is launched haha!
      Thank you all again!

      • Nate 님이 이 게시물을 좋아합니다..

      Yimec changing "mixSkin.AddSkin(skeletonData.FindSkin(bonesSkin));" with the actual name of the skin ("Shock-Bones") made this work.

      I just noticed that you likely mean how to make it work using the Inspector property [SpineSkin] private string bonesSkin; instead of using the hard-coded name string. There must be some error with either the string attribute value then, or some other issue with the game logic. A string variable set to "Shock-Bones" can't really be any different from passing "Shock-Bones" as a parameter in a hard-coded way.

      @Yimec Sorry, just noticed you already answered, I was late to post. Glad to hear you've figured it out, thanks very much for your kind words! 🙂