以下分享仅基于目前个人所知的经验总结,如有错误欢迎指正
【思路】
在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);
}
}