loodakrawa / SpriterDotNet

A pure C# Spriter implementation
zlib License
220 stars 75 forks source link

Find name of sprite that sprite transform applies to #106

Open TravisGesslein opened 5 years ago

TravisGesslein commented 5 years ago

In the Spriter software, sprites in animations are always associated with a named sprite object that shows up in the timeline. As far as I can tell, those are represented in the timeline information in SpriterDotNet's SpriterAnimation structure as well, in the .Timelines array, specified as entries with ObjectType "Sprite". Of course, only for available keyframes.

But when I want to update sprites after updating an animation, either by reacting to it in ApplySpriteTransform or by manually checking the latest FrameData, the library tells us (in the form of SpriterObjects) which images are used in the latest frame (via folder&file id), where they are and so forth, but not which sprite in the animation that image actually belongs to. Is there any way to reconstruct that information in the available data?

TravisGesslein commented 5 years ago

After a quick look around the source code, the information is definitely there and available, it just isn't handed around to API consumers. I was able to hack it in for my specific use case, but I'm not comfortable enough with the codebase or have the time to implement it to make sure it works all over the codebase. Here's what I did:

In FrameDataCalculator.GetFrameData (at line 120) there's a loop that interpolates the objects between the keyframes. These objectRefs have a timelineID, which can be used to retrieve the timeline the object belongs to, which in turn contains the name of the sprite (or bone in the case of bones) that the resulting SpriterObject references.

Just to get it working I added a name field to SpriterObject and just set it in that loop right then and there. It's probably wasteful though, you could just give the SpriterObject the timelineID or something similarly small and compact so you can retrieve the name that way later.

TravisGesslein commented 5 years ago

(my fork's commit in question is https://github.com/Heishe/SpriterDotNet/commit/a931b97cc06def29274bfae098c2788680a95c84#diff-80ac421ada1d8569e29d129ed036b8a2 , but I also deleted all projects I don't need from there so the changes might be hard to find. it's in FrameDataCalculator.cs and SpriteModel.cs)

TravisGesslein commented 5 years ago

By the way, the reason this is useful at all is because a 'retained' way of dealing with the sprite objects is just more efficient. If you do extra stuff with the sprites at runtime, like changing the pictures for others (for dynamic equipment), or applying different materials to them, you want to minimize the amount of switching that happens because especially rendering related stuff can have quite some overhead, which can be problematic if you're trying to display a lot of spriter-animated stuff at once.

So in Unity for example you always want to apply the same 'ApplySpriteTransform' and whatever you do in there to the same GameObject in the background that you allocate at startup time from all the object definitions in (SpriterEntity).ObjectInfos.

loodakrawa commented 5 years ago

Hey, thanks for reporting and analysing it in detail. I'll implement it as soon as I get back to it.