Hello, I've been struggling with this for a few days and can't seem to get it.
I'm working with a model that essentially has 2 layers of slots, the first layer is the "skin" layer (I call it the ugly baby) and the second layer is the "armor" slots.
The model has attachments in every slot, to begin with. I tried to use a version that had empty slots in the "armor" slots (the ugly baby), but when adding attachments to these, they ended up layered wrong and turned 90 or 180 degrees depending on the position.
My solution was to go in and replace each slot with an "empty sprite", a 1x1 sprite with 0 opacity. I used the "Mix and match" code to get this to work. However, the next step, putting the armor back on the model, proved to be a challenge.
My script now takes the armor and replaces it with the "empty sprite", then when I try and replace the "empty sprite" with armor (using the same code, just a different sprite), it doesn't work. If I run the code backward, replacing the armor with a random sprite, then replacing it with the "empty sprite", the first swap works, but the second one fails.
Default armor:
No helmet:
Funny hat (not worried about the alignment, it's just some random sprite I'm using to test)
The code I'm using to set the "empty sprite":
void SetSkinSlotToNull(string[] slotnames)
{
var skeleton = skeletonAnimation.Skeleton;
customSkin = customSkin ?? skeleton.UnshareSkin(true, false, skeletonAnimation.AnimationState);
Slot slot;
int slotindex;
Attachment oldAttachment;
Attachment newAttachment;
foreach (string slotname in slotnames)
{
slot = skeleton.FindSlot(slotname);
slotindex = skeleton.FindSlotIndex(slotname);
oldAttachment = slot.attachment;
newAttachment = oldAttachment.GetRemappedClone(nullSprite, sourceMaterial);
if (newAttachment != null)
{
customSkin.SetAttachment(slotindex, oldAttachment.Name, newAttachment);
}
else
Debug.LogWarning("NULL ATTACHMENT " + slotname);
}
skeleton.SetSkin(customSkin);
skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose.
skeletonAnimation.Update(0);
Resources.UnloadUnusedAssets();
}
The code I'm using to change to the actual sprite:
void SetSkinSlotToSprite(EquipmentItem.SlotSpritePair[] entries)
{
var skeleton = skeletonAnimation.Skeleton;
customSkin = customSkin ?? skeleton.UnshareSkin(true, false, skeletonAnimation.AnimationState);
Slot slot;
int slotindex;
Attachment oldAttachment;
Attachment newAttachment;
foreach (EquipmentItem.SlotSpritePair pair in entries)
{
slot = skeleton.FindSlot(pair.slot);
slotindex = skeleton.FindSlotIndex(pair.slot);
oldAttachment = slot.attachment;
newAttachment = oldAttachment.GetRemappedClone(pair.sprite, sourceMaterial);
if (newAttachment != null)
{
customSkin.SetAttachment(slotindex, oldAttachment.Name, newAttachment);
}
else
Debug.LogWarning("NULL ATTACHMENT " + pair.slot);
}
skeleton.SetSkin(customSkin);
skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose.
skeletonAnimation.Update(0); // Use the pose in the currently active animation.
Resources.UnloadUnusedAssets();
}
I'm calling each function with a keypress in the "update" loop and have everything set in the inspector.
The question is, what am I doing wrong that I can't change the attachment twice? Am I going about this in the wrong way?
I can provide more code if needed, those lines are only the parts that affect the attachments in any way. Everything else is variables being set or the update loop waiting for a key press. Thanks in advance for any advice or input!
While going through the code and comparing to the Mix and Match code, I found that I had changed something:
I used:
slot = skeleton.FindSlot(pair.slot);
oldAttachment = slot.attachment;
instead of
var templateSkin = skeleton.Data.FindSkin(templateAttachmentsSkin);
oldAttachment = templateSkin.GetAttachment(slotindex, pair.key);
I changed the code to get the attachment with the other method, but now it won't even find the attachment and "oldAttachment" after the second line returns null.
I've set the value in the inspector with:
[SerializeField] [SpineSlot] public string slot;
[SpineAttachment(slotField: "slot", skinField:"baseSkinName")] public string key;
which shows the appropriate slots and the attachment in the slot, but the code still doesn't work. This version doesn't find the attachment for the first sprite change, so nothing changes at all.