Forum rules - please read before posting.

Spine Skins

2

Comments

  • Ok thanks Chris!
  • So, I have finally got SkinExample working! See my modified code!

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using Spine;
    using Spine.Unity;
    using AC;
    
    public class SkinExample : MonoBehaviour
    {
    
        // Drag your skeleton onto this component slot in Unity:
        private SkeletonAnimation skeletonAnimation;
        private Skeleton skeleton;
    
    
    
        // Start is called before the first frame update
        void Start()
        {
    
            //try {
            //    skeletonAnimation = GetComponent<SkeletonAnimation>();
            //} catch (MissingComponentException e) {
            //    Debug.LogWarning(e.Message);
            //    skeletonAnimation = gameObject.AddComponent<SkeletonAnimation>();
            //}
    
            //if(skeletonAnimation != null) {
            //    spineAnimationState = skeletonAnimation.AnimationState;
            //    spineAnimationState.Data.DefaultMix = 0.01f;
            //    skeleton = skeletonAnimation.Skeleton;
    
            //    Debug.Log((skeleton == null) ? name + " skeleton null!" : name + " skeleton here!");
            //}
            print("Start");
            ChangeSkin();
    
            //prepare skin function
    
    
    
            //newSkin = new Skin("new-skin"); // 1. Create a new empty skin
            //newSkin.AddSkin(skeleton.Data.FindSkin("Clothes/Suit")); // 2. Add items
            //newSkin.AddSkin(skeleton.Data.FindSkin("Accessories/BriefcaseL")); // 2. Add items
        }
        Skin newSkin;
        /// <summary>
        /// Info found here: http://en.esotericsoftware.com/spine-runtime-skins#Skin-changes
        /// </summary>
        public void ChangeSkin()
        {
            Invoke("DelayedChange", 10f);
    
        }
    
        public void DelayedChange()
        {
    
            print("CHANGED SKIN");
            skeletonAnimation = KickStarter.player.GetComponentInChildren<SkeletonAnimation>();
    
            skeleton = skeletonAnimation.Skeleton;
    
            newSkin = new Skin("new-skin"); // 1. Create a new empty skin
            newSkin.AddSkin(skeleton.Data.FindSkin("Clothes/Suit")); // 2. Add items
            newSkin.AddSkin(skeleton.Data.FindSkin("Accessories/BriefcaseL")); // 2. Add items
    
            print("Update Skin " + skeletonAnimation.transform.position.x);
            skeleton.SetSkin(newSkin); // 1. Set the active skin
            skeleton.SetSlotsToSetupPose();
    
            //skeletonAnimation.AnimationState.Apply(skeleton); // 3. Use AnimationState to set attachments active in the current movement.
    
            // 4. Set attachments that were manually changed.
    
    
            //skel.skeleton.SetSkin("Clothes/Suit");
            //skel.skeleton.SetSlotsToSetupPose(); // 2. Use setup pose to set base attachments.
            //spineAnimationState.Apply(skel.skeleton); // 3. Use AnimationState to set attachments active in the current movement.
            // 4. Set attachments that were manually changed.
        }
        public void LateUpdate()
        {
            DelayedChange();
    
            if (newSkin != null)
            {
                //newSkin = new Skin("new-skin"); // 1. Create a new empty skin
                //newSkin.AddSkin(skeleton.Data.FindSkin("Clothes/Suit")); // 2. Add items
                //newSkin.AddSkin(skeleton.Data.FindSkin("Accessories/BriefcaseL")); // 2. Add items
    
                //print("Update Skin " + skeletonAnimation.transform.position.x);
                //skeleton.SetSkin(newSkin); // 1. Set the active skin
                //skeleton.SetSlotsToSetupPose();
    
                //skeletonAnimation.AnimationState.Apply(skeleton); // 3. Use AnimationState to set attachments active in the current movement.
    
            }
        }
    }
    

    If you are therefore able to help me turn this into a CustomActionScript that would be so handy! We can stick it on the WIKI!

    I need to be able to turn on and off particular skins on scene start and within player interactions, ie turn off briefcase accessory and then ad it on pick up briefcase when wearing Suit etc. That doable?

  • edited May 2022

    The DelayedChange function is being called in three ways - in Start, LateUpdate, and ChangeSkin. Are you invoking ChangeSkin, and are the calls from Start/LateUpdate necessary?

  • Not sure, the script is just on a game object in scene currently

  • I will want to call change skin i guess?

  • I got some help with it so I am unsure myself :)

  • Remove the Start and LateUpdate functions then, and call ChangeSkin with an Action - does it work?

  • Not sure what exactly to remove in the script?

  • If i have done it correctly, it does not change the skin with script modified when calling action

  • edited May 2022
    Ok ignore last post, it does work. Adapted code below. I can call event and set change skins. Is there a way to make this custom action script and call particular skin rather than it being in the script?




    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using Spine;
    using Spine.Unity;
    using AC;

    public class SkinExample : MonoBehaviour
    {

    // Drag your skeleton onto this component slot in Unity:
    private SkeletonAnimation skeletonAnimation;
    private Skeleton skeleton;




    Skin newSkin;
    /// <summary>
    /// Info found here: http://en.esotericsoftware.com/spine-runtime-skins#Skin-changes
    /// </summary>
    public void ChangeSkin()
    {
    Invoke("DelayedChange", 10f);

    }

    public void DelayedChange()
    {

    print("CHANGED SKIN");
    skeletonAnimation = KickStarter.player.GetComponentInChildren<SkeletonAnimation>();

    skeleton = skeletonAnimation.Skeleton;

    newSkin = new Skin("new-skin"); // 1. Create a new empty skin
    newSkin.AddSkin(skeleton.Data.FindSkin("Clothes/Suit")); // 2. Add items
    newSkin.AddSkin(skeleton.Data.FindSkin("Accessories/BriefcaseL")); // 2. Add items

    print("Update Skin " + skeletonAnimation.transform.position.x);
    skeleton.SetSkin(newSkin); // 1. Set the active skin
    skeleton.SetSlotsToSetupPose();

    //skeletonAnimation.AnimationState.Apply(skeleton); // 3. Use AnimationState to set attachments active in the current movement.

    // 4. Set attachments that were manually changed.


    //skel.skeleton.SetSkin("Clothes/Suit");
    //skel.skeleton.SetSlotsToSetupPose(); // 2. Use setup pose to set base attachments.
    //spineAnimationState.Apply(skel.skeleton); // 3. Use AnimationState to set attachments active in the current movement.
    // 4. Set attachments that were manually changed.
    }

    }
  • using UnityEngine;
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    using Spine;
    using Spine.Unity;
    
    namespace AC
    {
    
        [System.Serializable]
        public class ActionTemplate : Action
        {
    
            public override ActionCategory Category { get { return ActionCategory.Character; }}
            public override string Title { get { return "Set skin"; }}
    
    
            public bool isPlayer;
            public Char character;
            public int _charID = 0;
            private Char runtimeCharacter;
    
            public string[] newSkinNames = new string[1] { "" };
    
    
    
            public override void AssignValues()
            {
                if (isPlayer)
                {
                    runtimeCharacter = KickStarter.player;
                }
                else
                {
                    runtimeCharacter = AssignFile<Char> (_charID, character);
                }
            }
    
    
            public override float Run ()
            {
                if (runtimeCharacter)
                {
                    SkeletonAnimation skeletonAnimation = runtimeCharacter.GetComponentInChildren<SkeletonAnimation>();
    
                    Skeleton skeleton = skeletonAnimation.Skeleton;
    
                    Skin newSkin = new Skin("new-skin");
                    foreach (string newSkinName in newSkinNames)
                    {
                        newSkin.AddSkin(skeleton.Data.FindSkin(newSkinName));
                    }
    
                    skeleton.SetSkin(newSkin);
                    skeleton.SetSlotsToSetupPose();
                }
    
                isRunning = false;
                return 0f;
            }
    
    
            #if UNITY_EDITOR
    
            public override void ShowGUI ()
            {
                isPlayer = EditorGUILayout.Toggle ("Affect Player?", isPlayer);
                if (!isPlayer)
                {
                    character = (Char) EditorGUILayout.ObjectField ("Character:", character, typeof (Char), true);
                    _charID = FieldToID <Char> (character, _charID);
                    character = IDToField <Char> (character, _charID, true);
                }
    
                if (newSkinNames == null)
                {
                    newSkinNames = new string[0];
                }
                int numSkins = newSkinNames.Length;
                numSkins = EditorGUILayout.DelayedIntField ("# of skins:", numSkins);
                if (newSkinNames.Length != numSkins)
                {
                    string[] backup = new string[newSkinNames.Length];
                    for (int i = 0; i < newSkinNames.Length; i++)
                    {
                        backup[i] = newSkinNames[i];
                    }
                    newSkinNames = new string[numSkins];
                    for (int i = 0; i < Mathf.Min (numSkins, backup.Length); i++)
                    {
                        newSkinNames[i] = backup[i];
                    }
                }
    
                for (int i = 0; i < newSkinNames.Length; i++)
                {
                    newSkinNames[i] = EditorGUILayout.TextField ("Skin #" + i, newSkinNames[i]);
                }
            }
    
            #endif
    
        }
    
    }
    
  • edited May 2022

    Hi Chris, almost there except it updates and reverts back after first setting the skin as soon as I move the Player

    See video:

    https://www.dropbox.com/s/p1znwtuzatcwspu/WalkRemovesSkin.mov?dl=0

  • You should be getting the same issue with your original script, in that case - the Action is just adapting that code.

  • ok so, it works with the Start and Late update functions:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using Spine;
    using Spine.Unity;
    using AC;

    public class SkinExample : MonoBehaviour
    {

    // Drag your skeleton onto this component slot in Unity:
    private SkeletonAnimation skeletonAnimation;
    private Skeleton skeleton;
    
    
    
    // Start is called before the first frame update
    void Start()
    {
    
        //try {
        //    skeletonAnimation = GetComponent<SkeletonAnimation>();
        //} catch (MissingComponentException e) {
        //    Debug.LogWarning(e.Message);
        //    skeletonAnimation = gameObject.AddComponent<SkeletonAnimation>();
        //}
    
        //if(skeletonAnimation != null) {
        //    spineAnimationState = skeletonAnimation.AnimationState;
        //    spineAnimationState.Data.DefaultMix = 0.01f;
        //    skeleton = skeletonAnimation.Skeleton;
    
        //    Debug.Log((skeleton == null) ? name + " skeleton null!" : name + " skeleton here!");
        //}
        print("Start");
        ChangeSkin();
    
        //prepare skin function
    
    
    
        //newSkin = new Skin("new-skin"); // 1. Create a new empty skin
        //newSkin.AddSkin(skeleton.Data.FindSkin("Clothes/Suit")); // 2. Add items
        //newSkin.AddSkin(skeleton.Data.FindSkin("Accessories/BriefcaseL")); // 2. Add items
    }
    Skin newSkin;
    /// <summary>
    /// Info found here: http://en.esotericsoftware.com/spine-runtime-skins#Skin-changes
    /// </summary>
    public void ChangeSkin()
    {
        Invoke("DelayedChange", 10f);
    
    }
    
    public void DelayedChange()
    {
    
        print("CHANGED SKIN");
        skeletonAnimation = KickStarter.player.GetComponentInChildren<SkeletonAnimation>();
    
        skeleton = skeletonAnimation.Skeleton;
    
        newSkin = new Skin("new-skin"); // 1. Create a new empty skin
        newSkin.AddSkin(skeleton.Data.FindSkin("Clothes/Suit")); // 2. Add items
        newSkin.AddSkin(skeleton.Data.FindSkin("Accessories/BriefcaseL")); // 2. Add items
    
        print("Update Skin " + skeletonAnimation.transform.position.x);
        skeleton.SetSkin(newSkin); // 1. Set the active skin
        skeleton.SetSlotsToSetupPose();
    
        //skeletonAnimation.AnimationState.Apply(skeleton); // 3. Use AnimationState to set attachments active in the current movement.
    
        // 4. Set attachments that were manually changed.
    
    
        //skel.skeleton.SetSkin("Clothes/Suit");
        //skel.skeleton.SetSlotsToSetupPose(); // 2. Use setup pose to set base attachments.
        //spineAnimationState.Apply(skel.skeleton); // 3. Use AnimationState to set attachments active in the current movement.
        // 4. Set attachments that were manually changed.
    }
    public void LateUpdate()
    {
        DelayedChange();
    
        if (newSkin != null)
        {
            //newSkin = new Skin("new-skin"); // 1. Create a new empty skin
            //newSkin.AddSkin(skeleton.Data.FindSkin("Clothes/Suit")); // 2. Add items
            //newSkin.AddSkin(skeleton.Data.FindSkin("Accessories/BriefcaseL")); // 2. Add items
    
            //print("Update Skin " + skeletonAnimation.transform.position.x);
            //skeleton.SetSkin(newSkin); // 1. Set the active skin
            //skeleton.SetSlotsToSetupPose();
    
            //skeletonAnimation.AnimationState.Apply(skeleton); // 3. Use AnimationState to set attachments active in the current movement.
    
        }
    }
    

    }

  • but not without them it seems?

    As when i change to this code it doesn't work:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using Spine;
    using Spine.Unity;
    using AC;
    
    public class SkinExample : MonoBehaviour
    {
    
        // Drag your skeleton onto this component slot in Unity:
        private SkeletonAnimation skeletonAnimation;
        private Skeleton skeleton;
    
    
    
    
        Skin newSkin;
        /// <summary>
        /// Info found here: http://en.esotericsoftware.com/spine-runtime-skins#Skin-changes
        /// </summary>
        public void ChangeSkin()
        {
            Invoke("DelayedChange", 10f);
    
        }
    
        public void DelayedChange()
        {
    
            print("CHANGED SKIN");
            skeletonAnimation = KickStarter.player.GetComponentInChildren<SkeletonAnimation>();
    
            skeleton = skeletonAnimation.Skeleton;
    
            newSkin = new Skin("new-skin"); // 1. Create a new empty skin
            newSkin.AddSkin(skeleton.Data.FindSkin("Clothes/Suit")); // 2. Add items
            newSkin.AddSkin(skeleton.Data.FindSkin("Accessories/BriefcaseL")); // 2. Add items
    
            print("Update Skin " + skeletonAnimation.transform.position.x);
            skeleton.SetSkin(newSkin); // 1. Set the active skin
            skeleton.SetSlotsToSetupPose();
    
            //skeletonAnimation.AnimationState.Apply(skeleton); // 3. Use AnimationState to set attachments active in the current movement.
    
            // 4. Set attachments that were manually changed.
    
    
            //skel.skeleton.SetSkin("Clothes/Suit");
            //skel.skeleton.SetSlotsToSetupPose(); // 2. Use setup pose to set base attachments.
            //spineAnimationState.Apply(skel.skeleton); // 3. Use AnimationState to set attachments active in the current movement.
            // 4. Set attachments that were manually changed.
        }
    
    }
    
  • edited November 2022

    Create and attach to your Player a new C# file, SkinSetter:

    using UnityEngine;
    using Spine;
    using Spine.Unity;
    
    public class SkinSetter : MonoBehaviour
    {
    
        public string[] newSkinNames = new string[0];
    
        public void LateUpdate ()
        {
            SkeletonAnimation skeletonAnimation = GetComponentInChildren<SkeletonAnimation> ();
            if (skeletonAnimation == null) return;
    
            Skeleton skeleton = skeletonAnimation.Skeleton;
            Skin newSkin = new Skin ("new-skin"); // 1. Create a new empty skin
            foreach (string newSkinName in newSkinNames)
            {
                Skin existingSkin = skeleton.Data.FindSkin (newSkinName);
                if (existingSkin != null)
                {
                    newSkin.AddSkin (existingSkin);
                }
                else
                {
                    Debug.LogWarning ("Cannot find Skin with name '" + newSkinName + "'", skeletonAnimation);
                }
            }
    
            skeleton.SetSkin (newSkin);
            skeleton.SetSlotsToSetupPose ();
        }
    
    }
    

    Then update the Action:

    using UnityEngine;
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    
    namespace AC
    {
    
        [System.Serializable]
        public class ActionSkinSetter : Action
        {
    
            public override ActionCategory Category { get { return ActionCategory.Character; }}
            public override string Title { get { return "Set skin"; }}
    
            public bool isPlayer;
            public Char character;
            public int _charID = 0;
            private Char runtimeCharacter;
    
            public string[] newSkinNames = new string[1] { "" };
    
    
            public override void AssignValues()
            {
                if (isPlayer)
                {
                    runtimeCharacter = KickStarter.player;
                }
                else
                {
                    runtimeCharacter = AssignFile<Char> (_charID, character);
                }
            }
    
    
            public override float Run ()
            {
                if (runtimeCharacter)
                {
                    runtimeCharacter.GetComponent<SkinSetter> ().newSkinNames = newSkinNames;
                }
                isRunning = false;
                return 0f;
            }
    
    
            #if UNITY_EDITOR
    
            public override void ShowGUI ()
            {
                isPlayer = EditorGUILayout.Toggle ("Affect Player?", isPlayer);
                if (!isPlayer)
                {
                    character = (Char) EditorGUILayout.ObjectField ("Character:", character, typeof (Char), true);
                    _charID = FieldToID <Char> (character, _charID);
                    character = IDToField <Char> (character, _charID, true);
                }
    
                if (newSkinNames == null)
                {
                    newSkinNames = new string[0];
                }
                int numSkins = newSkinNames.Length;
                numSkins = EditorGUILayout.DelayedIntField ("# of skins:", numSkins);
                if (newSkinNames.Length != numSkins)
                {
                    string[] backup = new string[newSkinNames.Length];
                    for (int i = 0; i < newSkinNames.Length; i++)
                    {
                        backup[i] = newSkinNames[i];
                    }
                    newSkinNames = new string[numSkins];
                    for (int i = 0; i < Mathf.Min (numSkins, backup.Length); i++)
                    {
                        newSkinNames[i] = backup[i];
                    }
                }
    
                for (int i = 0; i < newSkinNames.Length; i++)
                {
                    newSkinNames[i] = EditorGUILayout.TextField ("Skin #" + i, newSkinNames[i]);
                }
            }
    
            #endif
    
        }
    
    }
    
  • edited May 2022
    Getting this error:

    Assets/Sleepytime Village/Scripts/CustomActions/ActionSkinSwap.cs(41,34): error CS0119: 'Component.GetComponent<T>()' is a method, which is not valid in the given context

    And I'm guessing due t this I cannot place SkinSetter script on the player spritechild
  • I think that some other code runs after and puts it back to the default skin
    It happens in SetCurrentDirection?

  • Fixed a typo in the Action code.

  • edited May 2022

    It works!

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.