2019-11-20 Unity中Spine动态局部换装实现方案

以下分享仅基于目前个人所知的经验总结,如有错误欢迎指正

【思路】

在Unity中的Spine实现局部换装的方式有很多种,如

1、使用Sprite动态替换Attachment

2、在Spine文件中提前预设好各个Slot的Attachment,在运行时使用代码直接切换具体Slot下对应的Attachment

3、动态组装新的皮肤套用到Spine角色上

这里举例的是第三种方式

【原理】

Spine元素主要包含皮肤(Skin)、骨骼(Bone)、插槽(Slot)、附件(Attachment)、及附件下的图片

而皮肤(Skin)包含了插槽信息、附件信息,如果我们有两套相同构成的皮肤,原理上就可以通过拼装皮肤上的插槽实现局部换肤功能

【实现方式】

代码:

using Spine;
using Spine.Unity;
using UnityEngine;

public class DynamicChangeSkin: MonoBehaviour
{
    public SkeletonAnimation targetSkeleton;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.T))
        {
            string slotName = "YourSlotName";
            string skinName = "YourSkinName";
            SkeletonData skeletonData = targetSkeleton.SkeletonDataAsset.GetSkeletonData(false);
            Skin skin = skeletonData.FindSkin(skinName);
            int slotIndex = skeletonData.FindSlotIndex(slotName);
            ChangeAttachment(slotName, GetAttachmentFromSkin(skin, slotIndex, slotName));
        }
    }

    public Attachment GetAttachmentFromSkin(Skin skin, int slotIndex, string slotName)
    {
        return skin.GetAttachment(slotIndex, slotName);
    }

    /// <summary>
    /// 传入的是新部件所在皮肤的Attachment
    /// </summary>
    /// <param name="slotName"></param>
    /// <param name="attachment"></param>
    public void ChangeAttachment(string targetSlotName, Attachment attachment)
    {
        if (attachment == null)
        {
            Debug.LogWarning("GetAttachmentFromSkin() return , attachment == null");
        }
        //  遍历targetSkeleton所有slot,创建新皮肤
        Skin newSkin = new Skin("NewSkin");
        foreach (var item in targetSkeleton.skeleton.Slots)
        {
            string slotName = item.ToString();
            int slotIndex = item.Skeleton.FindSlotIndex(slotName);
            Attachment tempAttackment = null;
            if (slotName.Equals(targetSlotName))
            {
                tempAttackment = attachment;
                Debug.LogWarning("Replace slotIndex: " + slotIndex + ", slotName: " + slotName);
            }
            else
            {
                tempAttackment = item.Attachment;
            }
            Skin.SkinEntry entry = new Skin.SkinEntry(slotIndex, slotName, tempAttackment);
            newSkin.Attachments.Add(entry, tempAttackment);
            Debug.Log("slotIndex: " + slotIndex + ", slotName: " + slotName);
        }
        targetSkeleton.skeleton.SetSkin(newSkin);
    }
}

同时修改多个slot的方法

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

public class DynamicChangeSkin: MonoBehaviour
{
    public SkeletonAnimation targetSkeleton;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.T))
        {
            string skinName = "YourSkinName";
            List<string> slotNames = new List<string>();
            slotNames.Add("YourSlotName1");
            slotNames.Add("YourSlotName2");
            slotNames.Add("YourSlotName3");
            ChangePartSkin(skinName, slotNames);
        }
    }

    private void ChangePartSkin(string skinName, List<string> slotNames)
    {
        SkeletonData skeletonData = targetSkeleton.SkeletonDataAsset.GetSkeletonData(false);
        Skin skin = skeletonData.FindSkin(skinName);
        Dictionary<string, Attachment> slotAttachmentDic = new Dictionary<string, Attachment>();
        for (int i = 0; i < slotNames.Count; i++)
        {
            string slotName = slotNames[i];
            int slotIndex = skeletonData.FindSlotIndex(slotName);
            slotAttachmentDic.Add(slotName, skin.GetAttachment(slotIndex, slotName));
        }
        ApplyNewSkinFromPartAttachment(slotAttachmentDic);
    }

    /// <summary>
    /// 传入的是新部件所在皮肤的Attachment
    /// </summary>
    /// <param name="slotName"></param>
    /// <param name="attachment"></param>
    public void ApplyNewSkinFromPartAttachment(Dictionary<string, Attachment> slotAttachmentDic)
    {
        //  遍历targetSkeleton所有slot,创建新皮肤
        Skin newSkin = new Skin("NewSkin");
        foreach (var item in targetSkeleton.skeleton.Slots)
        {
            string slotName = item.ToString();
            int slotIndex = item.Skeleton.FindSlotIndex(slotName);
            Attachment tempAttackment = null;
            if (slotAttachmentDic.ContainsKey(slotName))
            {
                tempAttackment = slotAttachmentDic[slotName];
            }
            else
            {
                tempAttackment = item.Attachment;
            }
            Skin.SkinEntry entry = new Skin.SkinEntry(slotIndex, slotName, tempAttackment);
            newSkin.Attachments.Add(entry, tempAttackment);
            Debug.Log("slotIndex: " + slotIndex + ", slotName: " + slotName);
        }
        targetSkeleton.skeleton.SetSkin(newSkin);

    }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。