• Unity
  • Skin Change Clarification

Hi there!

I'm sorry, I know this is asked frequently, but I can't seem to find some solid information on what is actually happening in the included examples. I basically just want to clarify that what I'm doing is correct, and that I'm not misunderstanding and/or causing unnecessary overhead. Here is my code:

public SkeletonAnimation SkeletonAnimation;
AnimationState _spineAnimationState;
Skeleton _spineSkeleton;

Skin _loadoutSkin;

public override void Init(AgentLoadout loadout) {
    _spineAnimationState = SkeletonAnimation.AnimationState;
    _spineSkeleton = SkeletonAnimation.Skeleton;

UpdateSkin(loadout.PrimaryWeaponName, loadout.SecondaryWeaponName);
}

void UpdateSkin(int primaryName, int secondaryName) {
    Skin primary = _spineSkeleton.Data.FindSkin(primaryName);
    Skin secondary = _spineSkeleton.Data.FindSkin(secondaryName);

_loadoutSkin = _loadoutSkin ?? (_loadoutSkin = new Skin("Loadout"));
_loadoutSkin.Append(primary);
_loadoutSkin.Append(secondary);

_spineSkeleton.SetSkin(_loadoutSkin);

_spineSkeleton.SetSlotsToSetupPose();
_spineAnimationState.Update(0);
}

primaryName and secondaryName can change during play. We have one 'swap' animation, to change between the current primary and secondary weapons. Is it fine to call UpdateSkin each time the player's primary or secondary weapon change?

If I'm reusing the same skin over and over, is it a problem calling Skin.Append? Am I adding to an ever-increasing skin, or will the old skins be removed? For example, if a new primary weapon doesn't have an attachment that an old one did, will the old one's attachment be removed? Or should I be calling a different function? Or should I be creating a new skin? There are multiple characters, all with different loadouts, in case that's relevant.

Finally Skeleton.SetSlotsToSetupPose and AnimationState.Update(float) - these are used in most examples, though sometimes Apply is used instead of Update. What are these doing exactly? Simple ensuring the new skin is actually applied? If so, is there a reason this couldn't be called automatically by Skeleton.SetSkin? (Actual question, not smarmy observation.)

Related Discussions
...
  1. Yes, it's fine to call UpdateSkin each weapon change.
    But note that you're only adding Primary and Secondary every time.
    If you needed to remove some parts of the old primary or secondary skin, you would need to clear _loadoutSkin.

  2. Skins are implemented as a C# Dictionary<T,K>.
    You can read the "Can Skins Really Help Me?" part for an explanation. https://github.com/pharan/spine-unity-docs/blob/master/Mix-and-Match.md#can-skins-really-help-me

Append here just means you're replacing dictionary entries using entries from another skin. If the entry exists, it overwrites. Otherwise, it adds. So if you keep calling Append, it will just keep updating the dictionary. It won't add unless the entry wasn't there before.
But note Append also won't remove anything. So if your skins happen to be storing attachments for different placeholders, older ones using different placeholders won't be removed.

This API is likely to change slightly in 3.7 when it becomes standard with the base runtimes. Currently, this is only for Unity.

And if you have different characters with different loadouts, each instance needs its own instance of a loadoutSkin.

  1. That last part is a bit incorrect. it shouldn't be AnimationState.Update(0).
    It should be AnimationState.Apply(skeleton).
    Previously, it was SkeletonAnimation.Update(0), which calls AnimationState.Apply.

Skeleton.SetSlotsToSetupPose makes sure it uses setup pose attachments using the skin you just set.
AnimationState.Apply(skeleton) makes sure it uses the attachments in the currently active animation frame, using the skin you just set.

Hey Pharan, thanks for the reply!

Alright so I changed the last line to use Apply instead of Update. Each primary/secondary weapon can contain any range of attachments, so to ensure the character is displaying properly, I need to create a new skin each time, is that correct?

No need. Just clear the skin every time before making the Append calls.

For now, that would look like this:

_loadoutSkin = _loadoutSkin ?? new Skin("Loadout"));
_loadoutSkin.Clear();
_loadoutSkin.Append(primary);
_loadoutSkin.Append(secondary);

Oh, excellent! Alright, that's in. Thanks very much!