Hi,
We're trying to use the mix and match example script using attachments, but can't get clearing the attachment to work.
In our example, we can change the equipment and set attachments without problem. But we can't remove by setting the slot's attachment to null. The second image is what we'd like to achieve (hiding the shoes completely)
Here's the code we are using, we equip the shoe which works but when we try clearing the shoe we are stuck with the red shoe (which we just equipped).
using UnityEngine;
using Spine;
using Spine.Unity;
using Spine.Unity.AttachmentTools;
using NightGarden.Core.Systems;
using System;
using System.Collections.Generic;
[Serializable]
public class Clearable
{
[SpineSlot] public string SpineSlot;
[SpineAttachment(slotField = "SpineSlot")] public string SpineAttachment = "";
}
[Serializable]
public class Equipable
{
public Sprite SourceSprite;
[SpineSlot] public string SpineSlot;
[SpineAttachment(slotField: "SpineSlot")] public string SpineAttachment = "";
}
[RequireComponent(typeof(SkeletonAnimation))]
public class MixAndMatchEquip : BaseBehaviour
{
#region -- Inspector --
[SpineSkin] public string CharacterSkin = "";
[SpineSkin] public string TemplateAttachmentsSkin = "";
public List<Clearable> Clearables = new List<Clearable>();
public List<Equipable> Equipables = new List<Equipable>();
public Material SourceMaterial;
[SerializeField] private Material RuntimeMaterial = default;
[SerializeField] private Texture2D RuntimeAtlas = default;
#endregion
#region -- Private Member Vars --
private Skin _characterSkin;
private SkeletonAnimation _skeletonAnimation;
#endregion
#region -- Private Methods --
private void Awake()
{
_skeletonAnimation = GetComponent<SkeletonAnimation>();
}
private void OnValidate()
{
if (SourceMaterial == null)
{
SkeletonAnimation skeletonAnimation = GetComponent<SkeletonAnimation>();
if (skeletonAnimation != null)
{
SourceMaterial = skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial;
}
}
}
#endregion
#region -- Protected Methods --
protected override void Start()
{
base.Start();
Generate();
}
#endregion
#region -- Public Methods --
public void Generate()
{
Skeleton skeleton = _skeletonAnimation.Skeleton;
if (SourceMaterial == null)
{
if (_skeletonAnimation != null)
{
SourceMaterial = _skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial;
}
}
_characterSkin = _characterSkin ?? new Skin("Custom Skin");
_characterSkin.AddSkin(skeleton.Data.FindSkin(CharacterSkin));
Skin templateSkin = skeleton.Data.FindSkin(TemplateAttachmentsSkin);
foreach(var equipable in Equipables)
{
int slotIndex = skeleton.Data.FindSlot(equipable.SpineSlot).Index;
Attachment templateAttachement = templateSkin.GetAttachment(slotIndex, equipable.SpineAttachment);
Attachment newAttachment = templateAttachement.GetRemappedClone(equipable.SourceSprite, SourceMaterial, pivotShiftsMeshUVCoords: false);
if (newAttachment != null)
{
_characterSkin.SetAttachment(slotIndex, equipable.SpineAttachment, newAttachment);
}
}
foreach (var clearable in Clearables)
{
int slotIndex = skeleton.Data.FindSlot(clearable.SpineSlot).Index;
//templateSkin.RemoveAttachment(slotIndex, clearable.SpineAttachment);
Slot slot = skeleton.FindSlot(clearable.SpineSlot);
slot.Attachment = null;
}
skeleton.SetSkin(_characterSkin);
skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose.
_skeletonAnimation.Update(0); // Use the pose in the currently active animation.
}
public void OptimizeSkin()
{
Skin previousSkin = _skeletonAnimation.Skeleton.Skin;
if (RuntimeMaterial != null)
{
Destroy(RuntimeMaterial);
}
if (RuntimeAtlas != null)
{
Destroy(RuntimeAtlas);
}
Skin repackedSkin = previousSkin.GetRepackedSkin("Repacked skin", _skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out RuntimeMaterial, out RuntimeAtlas);
previousSkin.Clear();
_skeletonAnimation.Skeleton.Skin = repackedSkin;
_skeletonAnimation.Skeleton.SetSlotsToSetupPose();
_skeletonAnimation.AnimationState.Apply(_skeletonAnimation.Skeleton);
AtlasUtilities.ClearCache();
Resources.UnloadUnusedAssets();
}
#endregion
}
Cheers!