• Unity
  • One Frame Attachment Animations

Related Discussions
...

Wait. So your steps are:

//have mixing.
state.SetAnimation(0, "key a slot on", false);
//wait 0.5 seconds or something
state.SetAnimation(0, "interrupts the first animation", false);
state.SetAnimation(1, "key the slot off", false);

Is that correct? And the end result SHOULD be that the slot is empty.
But you end up with it being nulled for one frame and then coming back on?


08 Jul 2016 8:07 am


You said a bunch of things about removing a line from AnimationState or changing AttachmentTimeline.Apply. It's not clear what your current state is at the moment.


08 Jul 2016 8:36 am


using UnityEngine;
using System.Collections;
using Spine;
using Spine.Unity;

public class OneFrameRepro : MonoBehaviour {

   [SpineAnimation]
   public string keyOn, keyOff, somethingElse;

   IEnumerator Start () {
      var skeletonAnimation = GetComponent<SkeletonAnimation>();
      var state = skeletonAnimation.state;

  state.Data.defaultMix = 0.5f; // 0.5 second crossfade.
  state.SetAnimation(0, keyOn, true); // 1 second animation of the slot being keyed with an attachment.
  yield return new WaitForSeconds(0.3f);
  state.SetAnimation(0, somethingElse, true); // interrupt first animation. just translates the root bone.
  state.SetAnimation(1, keyOff, true); // 1 second animation of the slot being keyed null.

  // slot is empty at the end of the animations. nothing unusual happened.
   }
}

I did the above and the result was that it nulled the slot successfully. And no one-frame bug.
Used the latest spine-unity.

There must be something else going on.

@yookuna. Your issue is not the same. Your issue is from expected behavior. Please see the other topic.

............
Like have you even looked at the project I have provided?

And removing a line was only the determination of what was causing it.

It's working in your example because your 'turn off' animation is longer than the mix time. I have repeatedly said and it's in the title "one frame animation".

This is getting frustrating now. Maybe we can Skype this out.

And his issue is the same issue

It was pretty confusing.
I didn't even know where to look in the project.

Anyway, I found it.
The "bug" is that this is how AnimationState and Animation.apply is currently designed to behave.
I'm drawing it so Nate understands the problem at a glance.

Image removed due to the lack of support for HTTPS. | Show Anyway

I can't really offer much on my end to actually solve the problem for your setup except to hack away at AnimationState and AttachmentTimeline.apply so it suits your needs, or inconveniently key the attachment off in every animation that possibly comes after the animation that turns it on.

In the larger scheme, we know you particularly have many issues with AnimationState and Nate is aware of it too, as AnimationState in all runtimes has known issues and is due for updated logic: AnimationState improvements · Issue #621 · EsotericSoftware/spine-runtimes · GitHub

These use cases are informative.

the bug goes deeper than that.

not as pretty but:

Image removed due to the lack of support for HTTPS. | Show Anyway


here shows that tracks which end and have keys during the mix period, the slot's attachment gets changed back.

As for your suggestion of hacking around it, it is possible but it is causing a lot of other bugs. The best way for now is to clear the queue before playing track1, but we rely on queues quite a lot, the if statement is 5 compares log atm.

Another way of doing it is to ensure the 'off animation' is longer than the mix. However with the case above, that isn't really an option.

We also cant key everything off, in all other animations.

Sorry Bcats, I'm not able to make sense of your image. I don't know what the red lines are or what the animations are doing.

Pharan's image makes sense. The previous animation continues to be applied as it is mixed out, so its attachment change keys are applied after the animation on track 1 changes the attachment. yookunka has the the same scenario except the slot's attachment is being set via code rather than a 1 frame animation.

To be clear, this is not a bug. The current behavior is that attachment keys are applied during mixing. Issue #621 has a potential solution (#12) going forward. If you want a code change solution for now, that is entirely possible.

What you want is to avoid applying any attachment timelines for the previous animation during mixing. AnimationState has this line to apply the previous animation:

previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null);

If you look at apply, it's very simple:

public void apply (Skeleton skeleton, float lastTime, float time, boolean loop, Array<Event> events) {
   if (loop && duration != 0) {
      time %= duration;
      if (lastTime > 0) lastTime %= duration;
   }
   for (int i = 0, n = timelines.size; i < n; i++)
      timelines.get(i).apply(skeleton, lastTime, time, events, 1);
}

So, let's write our own apply function and call it instead of the previous.animation.apply line, above:

applyPrevious(previous.animation, skeleton, previousTime, previousTime, previous.loop, null);
...
private void applyPrevious (Animation animation, Skeleton skeleton, float lastTime, float time, boolean loop,
   Array<Event> events) {
   float duration = animation.getDuration();
   if (loop && duration != 0) {
      time %= duration;
      if (lastTime > 0) lastTime %= duration;
   }

   Array<Timeline> timelines = animation.getTimelines();
   for (int i = 0, n = timelines.size; i < n; i++) {
      Timeline timeline = timelines.get(i);
      if (timeline instanceof AttachmentTimeline) continue; // No attachment changes.
      timeline.apply(skeleton, lastTime, time, events, 1);
   }
}

Sorry, the red lines are attachment keys, for the same slot. - its to show you cant just change the length of the animation to be longer than the mix period and the black line is a few px to the left, it should be at the end of the orange. I'm not an artist.

I had something similar to that code at one point. But I don't like changing the runtimes, we already have done to add root motion, and its annoying as ___ when it come to updating the runtimes.

I disagree with it not being a bug. Or atleast, I disagree with how the attachment runtime behaves. In my eyes, the latest state of the slot should persist, no matter the track that changes it. And it should only change when a more recent attachment key is come across, on any tracks.

Take this example, where the rows are tracks, and colours are track entries, and red bars are Attachment keys (labeled with letters)

Image removed due to the lack of support for HTTPS. | Show Anyway

At the thin black line, what attachment would you expect to be visible? Am I correct that a would be visible? I would have thought c should be visible as it is the most recent change of that slot.

It would be a with the current implementation, because when an animation is applied, all the state that is keyed gets applied.

Image your keys were for rotation instead of attachment visibility. At the black ? line, would you want the rotation for a or the rotation for c? If you want c, does it make sense for attachment visibility to work differently than rotation or other key types?

Another code change option would be to change AttachmentTimeline to only apply keys encountered since the lastTime. It's still a runtime change though.

You could make your runtime changes and save them as a Git stash. Then you could update your runtimes and apply the stash and you'd only have to fix up where there were conflicts, if any. I suggest SmartGit, which makes this easy: Repository -> Clone spine-runtimes, make your changes to the spine-runtimes files, Local -> Save Stash.

ugh, I randomly logged out when writing this reply :bang:

I would expect c to be active, And yes I would say that it makes sense for attachments to work differently when applied. The reason is this, attachments are binary in nature, they are either this or that they cant be blended or interpolated in between. imo the most recent state should persist.

I can understand in some instances, when T2 has ended, you will want to go back to A. and without setting it everyframe, it is hard to do this. However, I think that that is a rare case, but I may be wrong about that.

What was the reason you removed LastTime From apply? Was it to fix a bug? if so maybe there is another way of fixing that allows attachments to persist?

and thanks about the GitStash Stuff

lastTime for attachment changes goes against how every other property is applied. The tracks are intended to be layered, with higher tracks overriding lower tracks. Track 0 is applied and configures the skeleton a certain way, then track 1 is applied and can override changes that track 0 did. Imagine if track 1 shows attachment a, then track 0 shows b for the same slot. When using lastTime then b would be shown. This results in track 1 not being able to override attachment changes in lower tracks (track 0), which goes against how we intended tracks to work.

I'm a bit confused why BinaryCats can't do what I did on my project.

[Track 0] - Major Body motions
[Track 1] - [ActiveWeapon] Start -> Loop -> Disable - [NextWeapon] Start - Loop - Disable
[Track 2] - Any instantaneous overrides

This way, Track 1 is keeping track of which attachments are currently running. I will confess, I did expect the ability to have a 'Sticky track' that could be written to which would allow any number of state changes to be instantaneously written and preserved, but in the end, this solution ended up looking and acting better.

???

So, effectively (attachment) keys for lower tracks are ignored for that timeline.

i.e.

Image removed due to the lack of support for HTTPS. | Show Anyway


C would be shown at ?

I am unsure why it is a bad thing for the most recent change to be applied to the skeleton. I cant think of an instance where you would want to ignore all of the lower track's [type] of keys.

in this example, T1 over rides the slot, then T2, then T1, and finally T2 overrides the slot.

Image removed due to the lack of support for HTTPS. | Show Anyway

If you specifically intended this not to happen, that's fine. I don't agree with it, but its fine! 😉 🙂

Regarding the problem in the thread. once mixing starts, that previous animation is no longer playing. The Track entry name is the next animation's name, but keys are still being fed through from before the mix time. - but you provided a 'solution' to this.


11 Jul 2016, 14:22


Xelnath wrote

I'm a bit confused why BinaryCats can't do what I did on my project.

[Track 0] - Major Body motions
[Track 1] - [ActiveWeapon] Start -> Loop -> Disable - [NextWeapon] Start - Loop - Disable
[Track 2] - Any instantaneous overrides

This way, Track 1 is keeping track of which attachments are currently running. I will confess, I did expect the ability to have a 'Sticky track' that could be written to which would allow any number of state changes to be instantaneously written and preserved, but in the end, this solution ended up looking and acting better.

???

We rely on animation queues for waiting until things finishes and timing, blah blah blah. Its true there are solutions, to enable a hack around the problem. But hacks often cause even more problems. Problems should be solved rather than ignored. you would be surprised how many bugs we have had (and solved one way or another) that we now realise are due to this feature

Would it be possible for you to simply keep the track 'running' but not looping on Track 2?

no, it needs to end 😐. Although I haven't tried. Nates solution looks promising: One Frame Attachment Animations

This far into the project, changing how things work is like removing a card in a house of cards. (I wasn't on this project for a year, and our spine implementation....... isn't how I would have done it.)

It makes sense. Are you an independent contractor or a full-time dev at your studio?

Fulltime dev, I was working on a (c++) mobile title (my post in your showcase thread). my implementation was lovely :heart: :love: , then got pulled onto this project for reasons.

BinaryCats wrote

Regarding the problem in the thread. once mixing starts, that previous animation is no longer playing. The Track entry name is the next animation's name, but keys are still being fed through from before the mix time.

I agree, in some scenarios it may be odd for attachment changes from the previous animation to be applied. If the new animation keys the slot, the new animation's attachment changes would override the previous animation. If the new animation doesn't key the slot, then whatever the previous animation does during the mix will stay that way. This makes sense in some cases, like maybe the attachment visibility changes are frame-by-frame images for a fan that should keep spinning during mixing and then stop one completely mixed out. I have a feeling both have use cases, so we need a TrackEntry setting so the behavior can be configured on a case-by-case basis.

4 months later

ITS F*CKING FIXED!!

:') :love: :heart: :heart: :heart: :heart: :makeup: :love: :love: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party: :party:

Weeeee! 8)