- Edited
One Frame Attachment Animations
IIRC a while ago, it seems to be hit and miss on whether these worked or not. I have a case where I need to play an animation (on track >=1, as track 0 is changing) I have stepped through, and the animation gets added to the correct track. I added break points to check that it wasn't being removed (via clearTrack
), When I did this the attachment disappeared!
-however it reappeared the frame after. Although the animation on track 1, does key the attachment on, it is on frame 0, and no keys exist anywhere else.
I had to look up "IIRC".
Did you keep track of the value of slot.attachment? (as opposed to what the render looks like)
It may be useful so we know if it's the underlying spine-csharp that's misbehaving, or the spine-unity renderer.
Pharan wroteI had to look up "IIRC".
Did you keep track of the value of slot.attachment? (as opposed to what the render looks like)
It may be useful so we know if it's the underlying spine-csharp that's misbehaving, or the spine-unity renderer.
the physical render of the spine object, As I 'continue' the code after a break point, the next frame* it hit another break point (setting animation on track 0) at which point the attachment was not visible. then, on the next `continue of the code and breakpoint hit' the attachment was visable again.
This repo's 100% of the time, so I will see if I can look at the slot's value
*I assume, previously animation current time was -1. now it is 0f, the length of the animation is also 0f
I forgot to say the rest of mny IIRC sentence :rofl: :bang: , iirc a while ago, this was a thing
I have isolated the problem:
Here we can see the slots turn off and on (which will get undone)(taken from attachmenttimeline apply) Image removed due to the lack of support for HTTPS. | Show Anyway
And then the next frame It plays the previous animation from the code in animation state:
public void Apply (Skeleton skeleton) {
ExposedList<Event> events = this.events;
for (int i = 0; i < tracks.Count; i++) {
TrackEntry current = tracks.Items[i];
if (current == null) continue;
events.Clear();
float time = current.time;
bool loop = current.loop;
if (!loop && time > current.endTime) time = current.endTime;
TrackEntry previous = current.previous;
if (previous == null) {
if (current.mix == 1)
current.animation.Apply(skeleton, current.lastTime, time, loop, events);
else
current.animation.Mix(skeleton, current.lastTime, time, loop, events, current.mix);
} else {
float previousTime = previous.time;
if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime;
previous.animation.Apply(skeleton, previous.lastTime, previousTime, previous.loop, null);
When this happens
int frameIndex = (time >= frames[frames.Length - 1] ? frames.Length : Animation.binarySearch(frames, time)) - 1;
returns 0. So despite The previous animation being 30 frames long, it plays the first frame, which is the frame the attachment get turned on.
I've been having trouble with these too - so I just started creating two-frame looping animations for all pieces I want turned "on".
Annoying, but it works.
time = 1f
frames[frames.Length - 1] = 0
frames.Length = 1
And here is the timeline where it turns it on Image removed due to the lack of support for HTTPS. | Show Anyway
(coming from play previous)
15 Jun 2016, 08:05
so... is this being looked into or?
23 Jun 2016, 16:52
I FIXED THIS by clearing the track before playing the animation. However I can not do this due to other reasons, hello@
Sorry, Pharan didn't abandon you by choice, he is having major problems with getting his internet reconnected.
I'm having trouble following along. The screenshots are confusing. Can you describe concisely what the problem is?
Sorry bcats. Coincidentally, repair guys from my ISP arrived about an hour ago to fix stuff. Took them ages.
Just from the logic you've traced, I'm guessing it's a problem with the core Spine animation logic (in spine-csharp).
I'm adding this to the list cases for the AnimationState update either way.
If I understand correctly, the case is:
track 0: a mixing between a previous and next animation is happening. and those have attachment keys.
track 1 or higher: play an animation with attachment keys.
Is that right?
Also, this line is a source of the problem? That's in AttachmentTimeline?
int frameIndex = (time >= frames[frames.Length - 1] ? frames.Length : Animation.binarySearch(frames, time)) - 1;
That is correct @[deleted]
Animation 1: turns an attachment A
on (20frames)
Animation 2: Does other stuff (20 frames)
Animation 3: Turns attachment A
off.
I play animation 1. - keys the attachment on frame 0 - track 0
10 frames in:
Interrupt track 0. with animation 2
play animation 3 on track 1
attachment A
stays visable.
24 Jun 2016, 09:37
Soo, I isolated the bug, and was planning on sending it to you.
However, I was unsure how to export just a scene rather than the whole project. So I made a new project with the latest stuff. And it doesn't happen! It is either the old runtime, or the modifications to that runtime that has caused this :sweat:
24 Jun 2016, 09:53
:doh: :angel: :clap: it is not our changes. this must have been fixed in the newer versions of spine
There is no bug? My favorite kind of bug! :clap:
Nate wroteThere is no bug? My favorite kind of bug! :clap:
there was a BUG! IN THE past, you got lucky (punk) with new runtimes
06 Jul 2016, 14:26
Nope. I was wrong! it still happens.
What do you need from me to help investigate this issue.
I cant get the bug to happen when break pointing now, so I'm stuck with debug logs, Image removed due to the lack of support for HTTPS. | Show Anyway
Here I have one animation running, Attack_Knife_intro
(60 frames track 0). Then I interrupt that animation (I damage the character) and it plays an animation TakeHit_Upper
( 30 frames track 0). On the same frame, I play animation Attachment_Knife_Off
(1 Frame, track 1)
Attack_Knife_intro
Turns Attachment knife_a
ON, in slot WeaponA
- first frame.
TakeHit_Upper
DOES NOT ALTER slot WeaponA
, At all.
Attack_Knife_intro
Turns Attachment knife_a
OFF, in slot WeaponA
- first frame.
The above image shows the following, the current anuimation playing (_anim_) and any time an attachment is set, in the format slot
: current image
to new image
currenttime
06 Jul 2016, 14:45
I have repo'ed it in a project using latest unity runtimes and goblin-mesh (altered)
It uses the script animationstuff to handle playing of animations,
https://drive.google.com/file/d/0B5ElW0WUt28eMG1UWlgtTGFoUXM/view?usp=sharing
06 Jul 2016, 14:54
its in the goblin scene
06 Jul 2016, 16:50
I have narrowed down the problem to
previous.animation.Apply(skeleton, previous.lastTime, previousTime, previous.loop, null);
line 119 Animation state. bug is fixed by removing it.
However, I am unsure why this line even exists. All this does is play the previous animation.
Take the attachment time like (only visable one causing a problem)
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame.
int frameIndex;
if (time >= frames[frames.Length - 1]) // Time is after last frame.
frameIndex = frames.Length - 1;
else
frameIndex = Animation.binarySearch(frames, time, 1) - 1;
String attachmentName = attachmentNames[frameIndex];
skeleton.slots.Items[slotIndex]
.Attachment = attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName);
}
for any timelines' frame < current time, it will apply it. However, this does not account for the current state of the attachment. I.e. if another track has turned it off.
I have noticed that you don't check the timeline's frame time against lastTime
. Is this so it never misses an attachment keyframe?
06 Jul 2016, 17:05
I changed the code to:
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame.
int frameIndex;
if (time >= frames[frames.Length - 1]) // Time is after last frame.
{
if (lastTime >= frames[frames.Length - 1]) // you missed your chance
return; //now bugger off
frameIndex = frames.Length - 1;
}
else
frameIndex = Animation.binarySearch(frames, time, 1) - 1;
String attachmentName = attachmentNames[frameIndex];
skeleton.slots.Items[slotIndex]
.Attachment = attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName);
}
It works, but I am unsure what knock-ons it will have.
We recently changed back to always setting the attachment rather than using lastTime
. This allows 2 tracks to key attachment changes and the higher track wins since it is applied last. If we checked lastTime
to trigger the attachment change then the most recent track to set the attachment wins, which doesn't make sense as the higher track wins for all other types of keys.
We recently changed back to always setting the attachment rather than using lastTime. This allows 2 tracks to key attachment changes and the higher track wins since it is applied last. If we checked lastTime to trigger the attachment change then the most recent track to set the attachment wins, which doesn't make sense as the higher track wins for all other types of keys.
I'm sorry I don't get your comment well. So do I need to turn an attachment off at a beginning of every animation if the animation doesn't need it? This isn't ideal at all because I need to modify all the animation if I add a new attachment. I want attachment's current state (on or off) to remain unless a higher track changes it when animation changes.
@[deleted]
I think yours is a separate issue though the recent changes above does solve part of the issue, so it's cool.
It certainly wouldn't be ideal if the setup pose defines the slot to have no attachments active, and you have a lot of animations. Muddying up the dopesheet is never a good workflow.
Clarification: It's technically the slot's state and not the attachment's (this is why the key icon is next to the slot in Spine editor).
Setting the slot's attachment to null means "hiding an attachment".
Also, Spine's behavior is that it leaves things alone (bones, slots, draw order), unless an animation keys it. So its state actually already "remains" unless something else changes it. The fact that your higher tracks (or any of the other tracks) never key the slot back to empty is why the attachment doesn't disappear. This is just by default and can be changed with code.
You clear a slot by saying slot.Attachment = null
. You return it to setup pose by saying slot.SetToSetupPose()
. You could conceivably do that whenever an animation starts or ends (using the existing animation callbacks). Spine-Unity actually has some extra methods that make it easier to find the right items to reset.
So, normally, if you're animating on a single track, this would be as simple as resetting slot/bone states every start of an animation, or resetting animated item states every frame during transitions.
If you're on multiple tracks, it sort of requires case-by-case handling. But this is more manageable if certain slots are sort of "managed" by a track: For example, if animations on a specific track key that slot's attachment (or turn it on or off), or leave it alone for a lower track to animate.
If you could describe your setup in more concrete terms, we may have something simple to recommend. I think opening a new topic would be best.
@[deleted]
Thank you for your detailed explanation. I already posted and described my situation at the following thread, but @BinaryCats pointed me this thread then I got confused after reading through all the comments
http://esotericsoftware.com/forum/Libgdx-Attachment-Bug-Fix-Proposal-6614
Could you take a look at my comment in the above thread and give some advise please? :$
Oh, so you're not a Spine-Unity user.
That complicates it just a tiny bit. But it's fine. We can advise you on the other topic.
Nate wroteWe recently changed back to always setting the attachment rather than using
lastTime
. This allows 2 tracks to key attachment changes and the higher track wins since it is applied last. If we checkedlastTime
to trigger the attachment change then the most recent track to set the attachment wins, which doesn't make sense as the higher track wins for all other types of keys.
So what is the solution here?
Maybe it should just ignore the attachment timeline when mixing (I assume that's why you are doing previous.apply
)?, or it should not apply any keys before the mixing happened?
Nate wroteIf we checked
lastTime
to trigger the attachment change then the most recent track to set the attachment wins, which doesn't make sense as the higher track wins for all other types of keys.
I am unsure what you mean by the most recent track to set the attachment
. If you mean that the most recent attachment-key to be fired( regardless of what track it is on ) to be applied, this is what you want... isn't it?
BinaryCats, honestly I'm still not sure what problem you are having. I need it to know 1) what you are doing, 2) what actually happened, and 3) what you expected to happen. If you can do that as concisely as possible that would help. If you leave out any of those, it is hard to guess at the problem and then confusing if I guess wrong.
BinaryCats wroteI am unsure what you mean by the most recent track to set the attachment.
Track 0 is applied, then track 1. If both key an attachment, track 1 will be the most recent track to set the attachment.
Nate wroteBinaryCats, honestly I'm still not sure what problem you are having. I need it to know 1) what you are doing, 2) what actually happened, and 3) what you expected to happen. If you can do that as concisely as possible that would help. If you leave out any of those, it is hard to guess at the problem and then confusing if I guess wrong.
BinaryCats wroteI am unsure what you mean by the most recent track to set the attachment.
Track 0 is applied, then track 1. If both key an attachment, track 1 will be the most recent track to set the attachment.
....
I Have provided a download link to a unity project and provided the spine file which has isolated the bug.
I will try to make it clearer when I get home (although I think I have outlined it in its simplest form)
07 Jul 2016, 19:49
If you have an animation playing that keys on an attachment in a slot, then interrupt that animation (by setting an animation on the same track) and simultaneously play an animation on a different animation that keys off THAT SAME ATTACHMENT, IN THE SAME SLOT. The attachment will turn off for ONE FRAME, then the next frame That attachment, due to mixing, will be keyed back on. Even if it happened a long time ago.
The attachment should remain off. Attachment keys outside of the mixing time SHOULD NOT have a say on if a slot is turned on or off.
07 Jul 2016, 19:52
I think: One Frame Attachment Animations explains it pretty well in a step by step
The attachment should remain off. Attachment keys outside of the mixing time SHOULD NOT have a say on if a slot is turned on or off.
Yeah, I agree with BinaryCats as I have the same problem.