GetTimeOfKeyframe always fail

Problem: A keyframe named “EndKF” can never be found by AnimationTrack:GetTimeOfKeyframe(). But the same keyframe will always trigger an event when using AnimationTrack:KeyframeReached()

I used the simple code from this documentation example under Playing Animations Directly > Humanoids

I have a Keyframe named “EndKF” in my animation.

When I run this code, it always works:

kickAnimationTrack.KeyframeReached:Connect(function(keyframeName)
	print('KF is named "' .. keyframeName .. '"')
end)

It finds the Keyframe named “EndKF” and prints that

But when I run this code, it always fails:

local mountMarker = kickAnimationTrack:GetTimeOfKeyframe("EndKF")
print('found marker at', mountMarker)

I attach file which is only Baseplate with 1 LocalScript in StarterPlayerScripts with the code from the documentation link above. The LocalScript will throw the error on line 23. Comment out line 23 and you’ll see it successfully find that Keyframe.

AnimationWorkbench.rbxlx (245.6 KB)

I attach a screen shot of my Animation Editor that shows the named Keyframe right before the end of Anim.

I took also a screen shot of hoverstate of Keyframe where it is showing the name “EndKF” in tooltip
image

It is on Keyframe 29/30. There is also Marker named “End” on that frame.

4 Likes

Thanks for the report! We’ve filed a ticket to our internal database and we’ll follow up when we have an update for you.

3 Likes

I can confirm that this issue also occurs with KeyframeReached, but only when the last keyframe is named specifically - KeyframeReached seems to work fine for other non-rearmost keyframes, on the other hand.

Is there a current solution to this?

This still does not work please help.
I am trying to speed up my animation to reach the “Hit” keyframe in .15 seconds always, via

local Anim_Desired_KF_Reach = 3.5
local HitKF = Anim_To_Play[1]:GetAttribute("HitKF")
local Anim_Speed = (HitKF / Anim_Desired_KF_Reach)
Anim_To_Play[2]:Play(0,9,Anim_Speed)
--Will make the animation reach the "Hit" keyframe in .15 seconds regardless where the Hit keyframe is at

but since it does not return the keyframe value it will not work unless I manually add it which is time consuming. I keep getting this
image

image

1 Like

Are you sure the animation is loaded and that you’ve renamed the keyframe and not added a marker? The only times I’ve had an issue with ::GetTimeOfKeyframe is when I either (a) thought I’d renamed the keyframe but had added a marker instead, or (b) when I’d forgotten to wait for the animation to load.

See the relevant documentation - you’re expected to use a named keyframe and wait for the length property of AnimationTrack to be greater than 0.

2 Likes

You’ve gotten GetTimeOfKeyFrame to work?
The animation is loaded. You can tell it’s loaded by the error saying
"Invalid operation for this **Animation** format".
Meaning it recognizes it’s an animation.

Yes I’ve also made sure that the keyframe is named correctly and it was not a marker that was inserted. GetMarkerReachedSignal works correctly.

The only other reason I can guess this isn’t working is that KeyframeReached is deprecated and they’re switching everything over to GetMarkerReachedSignal; however, it’d be nice if they added a GetMarkerTime() instead then.

It works in the project I’m currently working on when testing in studio, so unless there’s an issue with it within a server it should work - or at least, I hope?

How are you determining that it’s loaded? The documentation, as described here, recommends that you use something similar to the following:

local RunService = game:GetService('RunService')

local function isLoaded(track)
  return track.Length > 0
end

local function awaitTrackLoaded(track)
   while track.Length <= 0 do
      RunService.Heartbeat:Wait()
   end
end

For reference, my IsLoaded() and _awaitLoaded() methods look similar to the above and my wrapper methods look like this:

Wrapper
function wrapper:GetTimeOfKeyframe(name)
  assert(typeof(name) == 'string', 'Invalid keyframe name, expected str')

  if not self:IsLoaded() then
    self:_awaitLoaded()
  end

  return self._track:GetTimeOfKeyframe(name)
end

function wrapper:GetTimeBetweenKeyframes(k0, k1)
  local success, result = validateKeyFrameNames(k0, k1)
  if not success then
    return error(string.format('[%s] %s', tostring(self), result or 'Unknown keyframe'))
  end

  local t0 = self:GetTimeOfKeyframe(k0)
  local t1 = self:GetTimeOfKeyframe(k1)
  return t1 - t0
end

Agreed it would be nice to have a method to do this with the animation directly as with AnimationTrack::GetTimeOfKeyframe but just to note, you can actually do this already using the AnimationClipProvider via its ::GetAnimationClipAsync method.

This replaces the legacy KeyframeSequenceProvider which we were able to use in the past to do this.

It’s a little bit more of a faff compared to ::GetTimeOfKeyframe since you would have to iterate through each of them to find the markers/keyframe name(s) and their timepoints, but it’s doable nonetheless.

1 Like

Oh I guess it wasn’t loaded, I tried it again after checking for the length being greater than 0 and it worked! Thank you friend.

1 Like