blueberrydev

Hello, thank you for taking the time to read this and see if you can help me out.

First of all, I just want to say that I'm sort of new to Spine, I've been learning for around a year in my free time and it has been melting my brain (specifically learning how to code with Spine.Unity)

I've been working on a personal project that uses mix and match logic in two different ways; one from the Mix and Match Equip demo scene and one from the Mix and Match Skins demo scene, but I've run into a brick wall that I can't find a way around.

I've been searching through the forums trying to see if other users have tried this, and I've scoured through the API & other materials provided to try to make sure I don't miss an obvious answer. I'm sorry if this is something that is covered somewhere that I missed.

All that out of the way, on to the meat and potatoes of my issue:
I have a Generic Character Animator that I'm working on, the default skin is a nude character. It currently has four skins, the eyes, helmet, body armor and leg armor.
SpriteSwappingWorkingBeforeSkins.png

I had the sprite swapping logic working with the Spine Dummy when it didn't have skins, but I learned that skins were the way forwards for equipping gear like this-
EquipmentSkinsworkingGif.gif

and now I have the logic for equipping / unequipping gear working flawlessly; however- I cannot seem to figure out the sprite swap code again now that I have skins involved.

Specifically, the sprite swap code still works for the slots that are on the base skin, but the slots that have been moved to their own skins aren't being referred to properly and I'm having trouble figuring out how they need to be referred to.

When I have the armored slots disabled; the animation will add the skins but the atlas will be messy like this; because the logic to add sprites before the repack is disabled- and if it doesn't have sprites to place in the repack, the repack doesn't work (enabling them causes it to abort as soon as it can't find the slot I ask it to)
AtlasRepackFailsBecaseNotAllSlotsAccountedForGif.gif

I did this for testing purposes, to make sure the part that adds the skins worked at all.
customSkin.AddSkin(skeletonData.FindSkin("Head/Armored"));
customSkin.AddSkin(skeletonData.FindSkin("Torso/Armored"));
customSkin.AddSkin(skeletonData.FindSkin("Legs/Armored"));
customSkin.AddSkin(skeletonData.FindSkin("Eyes/Open"));
When I have the armored slots enabled (Code:
int helmetSlotIndex = skeleton.Data.FindSlot(helmetSlot).Index;
Attachment templateHelmet = templateSkin.GetAttachment(helmetSlotIndex, helmetKey);
Attachment newHelmetAttachment = templateHelmet.GetRemappedClone(helmetSprite, sourceMaterial, pivotShiftsMeshUVCoords: false);
if (newHelmetAttachment != null) customSkin.SetAttachment(helmetSlotIndex, helmetKey, newHelmetAttachment);
); the animation fails to add the sprites to it because I am not calling it in the code properly, and nothing appears to happen to the large dummy. (the smaller dummies remain on the scene to show that the other rigs are still working and that I didn't break the scene)
DummyDoesntRepackAtAllBecauseHelmetSlotNull.gif


The error message I get in the console shows me this:
NullReferenceException: Object reference not set to an instance of an object
Spine.Unity.AttachmentTools.AttachmentCloneExtensions.GetRemappedClone (Spine.Attachment o, Spine.AtlasRegion atlasRegion, System.Boolean cloneMeshAsLinked, System.Boolean useOriginalRegionSize, System.Single scale) (at Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs:104)
Spine.Unity.AttachmentTools.AttachmentCloneExtensions.GetRemappedClone (Spine.Attachment o, UnityEngine.Sprite sprite, UnityEngine.Material sourceMaterial, System.Boolean premultiplyAlpha, System.Boolean cloneMeshAsLinked, System.Boolean useOriginalRegionSize, System.Boolean pivotShiftsMeshUVCoords, System.Boolean useOriginalRegionScale) (at Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs:74)
Spine.Unity.Equipper2.SpriteSwap () (at Assets/Scripts/Equipper2.cs:199)
Spine.Unity.Equipper2+<Start>d__116.MoveNext () (at Assets/Scripts/Equipper2.cs:175)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <be28439f7b014fc38435d198c0640ff7>:0)
Spine.Unity.Equipper2.SpriteSwap () (at Assets/Scripts/Equipper2.cs:199) seems to be the important line, and when I bring up that line of code:
Attachment newHelmetAttachment = templateHelmet.GetRemappedClone(helmetSprite, sourceMaterial, pivotShiftsMeshUVCoords: false);
Thats the line it specifically refers to, which is part of this:
int helmetSlotIndex = skeleton.Data.FindSlot(helmetSlot).Index;
Attachment templateHelmet = templateSkin.GetAttachment(helmetSlotIndex, helmetKey);
Attachment newHelmetAttachment = templateHelmet.GetRemappedClone(helmetSprite, sourceMaterial, pivotShiftsMeshUVCoords: false);
if (newHelmetAttachment != null) customSkin.SetAttachment(helmetSlotIndex, helmetKey, newHelmetAttachment);
The part where I think it is broken is in the helmetKey. When I go in the inspector on the slots that sprite swap currently works on, each of those slots & keys finds its respective option on the inspector.
WorkingKeyInspector.gif

But when it is for one of the slots that I added to the skins, null is the only field that comes up.
BrokenKeyInspector.gif


Here is the code for the bare head compared to the armored helmet.

Bare Head
[Header("Bare_Head")]
public Sprite bareHeadSprite;
[SpineSlot] public string bareHeadSlot;
[SpineAttachment(slotField: "bareHeadSlot", skinField: "baseSkinName")] public string bareHeadKey = "Nu_Head";
Armored Head
[Header("Helmet")]
public Sprite helmetSprite;
[SpineSlot] public string helmetSlot;
[SpineAttachment(slotField: "helmetSlot", skinField: "Head/Armored")] public string helmetKey = "Leather_Head";
and I know that the helmetKey is a string that is determined by filenames in Spine, so here are what those respective slots look like in Spine.

SpineSlotNames.png


This makes me think that the string for the helmetKey (and all of the slots that are on skins) isn't properly set up, but my guesses haven't been working and I'm at a loss.

My goal with this is to be able to equip items and have the sprites that are on each scriptable object/item pass their sprites to the script that is doing the sprite swap so that those sprites will show on the animation.

If you've made it this far, thank you for reading this and taking the time to help me out. If there is any more information I can provide that would make this easier to assist with I'm happy to provide it.

---

I solved this by making variables for each of the skins and then using those variables in the skinField: portion of the SpineAttachment fields.
Non hai i permessi necessari per visualizzare i file allegati in questo messaggio.
Avatar utente
blueberrydev
  • Messaggi: 3

Harald

Glad to hear you've figured it out, thanks for sharing. Admittedly I didn't completely grasp what your actual problem was, but anyway glad you could resolve it.

A remark on the side: The following line looks as if you are using skins where they are not recommended to be used:
AddSkin(skeletonData.FindSkin("Eyes/Open"));
Do you have a skin for "Eyes/Open" and a skin for "Eyes/Closed"? If so, then we would instead recommend to have skin placeholders for the closed and the open state, so that you can enable and disable the eyes-closed and eyes-open attachments in an animation. You can then use skins to change from e.g. Elf to Human which each provide their versions of the closed and open eye attachments.
Avatar utente
Harald

Harri
  • Messaggi: 4196

blueberrydev

I'm sorry about the lack of clarity in my original post, I was tired.
I wanted to have the animator play a skin that had placeholder art for something being equipped and swap those placeholder sprites with sprites from the item that was equipped.
I appreciate the advice for the skins, that's brilliant! I've been experimenting with skins and trying to figure out different situations like that where its helpful to have skins set up and how to set it up. I've been simultaneously learning Unity/C#/Spine for about a year now with no code background but I'm starting to get a better grasp on things.
Thank you for taking the time to respond and a big thank you for that tip!
Avatar utente
blueberrydev
  • Messaggi: 3

Harald

No need to apologize, thanks for the clarification and for your kind words.
blueberrydev ha scritto:I wanted to have the animator play a skin that had placeholder art for something being equipped and swap those placeholder sprites with sprites from the item that was equipped.
This is a rather unusual workflow. The more common approach would be to just "stack" skins on top of each other. You would e.g. be adding each equipped item to a combined skin from inside to outside, like first adding e.g. a "naked" base human or elf skin, then adding the equipped white-underwear skin, followed by golden-leg-armour, silver-dragon-helmet and fiery-gloves skins. This way e.g. an upper-leg skin placeholder of your skeleton would be defined by the last-added skin that sets this attachment, being the golden-leg-armour in this example (overriding the attachment of white-underwear, which was overriding the attachment of human). You could then as a last layer also either set weapons and shields as skins as well, or set them as normal attachments since they only need a single attachment most of the time, and creating a skin for each weapon might be overkill.

In general, skins are recommended where multiple attachments form an "inseparable whole", like trousers which need attachments for upper legs, lower legs and the pelvis part.
Avatar utente
Harald

Harri
  • Messaggi: 4196

blueberrydev

Harald ha scritto:This is a rather unusual workflow. The more common approach would be to just "stack" skins on top of each other. You would e.g. be adding each equipped item to a combined skin from inside to outside, like first adding e.g. a "naked" base human or elf skin, then adding the equipped white-underwear skin, followed by golden-leg-armour, silver-dragon-helmet and fiery-gloves skins. This way e.g. an upper-leg skin placeholder of your skeleton would be defined by the last-added skin that sets this attachment, being the golden-leg-armour in this example (overriding the attachment of white-underwear, which was overriding the attachment of human)
I believe I am doing both; when I am setting the skins in my equipment animator that is exactly how I am assigning the currently active skins, but with template skins.
I am following this web page's instructions on mix and match:
spine-unity Mix and Match
Specifically, towards the bottom where it says:
copy pasted from the above linked reference ha scritto:Option 2: Use template attachments in Spine, and generate Attachments from UnityEngine.Sprites in Unity.
See the sample project named "MixAndMatch-ESS.spine". You can download the zip here. You'll notice that the skeleton only has the template skin. All the customization options will use Sprites in Unity editor, and will need to be based on the attachments in the template skin.

This can be handy if you have an arbitrarily large number of equips and customization, or ones that can come from anywhere- DLC, game updates, etc...

The first step is to create a skeleton in Spine and use a set of images that are supposed to be templates for your eventual equips. Those template images will need to be the right height and width because they will form the bases of your actual equips. If they can't all fit into one size, you may want to use more than one template. (eg. instead of just one "sword" template, you can have templates for "short sword", "wide sword", "dagger", "long sword", etc...) For best results, you should animate with those template images in Spine. Create a skin called "template" and add your template swords and armor and whatever images into Skin Placeholders. (see: Spine User Guide - Skins).

The next step is to create those actual equip/customization images with the same height and width as your template images.
You will import these individual (unpacked) images into your Unity project as Sprites.
Requirements:

You can pack these Sprites using Unity's packer, but they need to use Full Rect packing mode. If you plan to use these Sprites with Premultiply Alpha (PMA) shaders or with runtime repacking (see the next section), then you will need to use "Read/Write Enabled".
You need to know the type of shader you are using. If you are using a Premultiply Alpha shader, such as the default "Spine/Skeleton", you need to use "PMAClone" methods. More on this later.

Then you write your C# code that can combine use your template skin. This will vary as your equip or character customization system depends on how your game works.
There is also this readme from that mix and match ess file:
readme ha scritto:These custom equips were created by opening the template image in Photoshop, then drawing over the template shape on a separate layer.

For REGION ATTACHMENTS (plain rectanglular image attachments):
======================
If you make sure the images are exactly the same width and height, no extra work needs to be done.
With this in mind, it's best to have your template images have some extra padding, especially in the direction where you expect things to be bigger.

Using images that have slightly different width or height will move it off alignment accordingly. The tolerances and negative visual effect will depend on the art style and skeleton's construction.

If you need to use an image that's bigger (eg, for a longer sword), you can do that, but code needs to be added to adjust the pivot/offset for each attachment that diverges from the template's alignment.


For MESH ATTACHMENTS
====================
You must make sure the images have the same width and height.
With this in mind, it's best to have your template images have some extra padding, especially in the direction where you expect things to be bigger. And when modeling the mesh, make sure to include the extra padding within its shape.
So right now, in Spine everything is just template art (the gray artwork is the Spine template art, and the recolored are sprites from Unity; its simple artwork for now but I was more focused on getting it working). I hope that clears up any confusion on my previous explanation.
Avatar utente
blueberrydev
  • Messaggi: 3

Harald

Thanks for the additional clarification, now I understand your background much better!

Your workflow makes sense if you need to use attachment assets that are only present in the Unity project (e.g. Unity Sprites) and (for whatever reason) exporting the assets from Spine as a set of separate atlas assets is not an option. Please note that you can also use the Spine texture packer separately to export atlas assets without a skeleton, in case you didn't already know:
Texture packing - Spine User Guide: Texture packing
This way you could also e.g. provide skins as content-only updates or DLCs that are downloaded after your main game executable is shipped, without having to re-publish your existing assets with added attachments.

May I ask what your motivation for using placeholder attachments instead of skins (and multiple additional separately packed atlas assets) is?

I will adjust the referenced spine-unity Mix and Match documentation page to more explicitly state the current relationship to the new Skin API and what alternatives exist to using Unity Sprites, e.g. for later content-only updates or DLC additions.
Avatar utente
Harald

Harri
  • Messaggi: 4196


Torna a Unity