A KeyframeSequence player

I made a function that plays KeyframeSequences

local function playKeyframes(rig : Model, keyframes : KeyframeSequence)
	local Humanoid = rig:FindFirstChildWhichIsA("Humanoid")
	local Animator = Humanoid.Animator
	
	for i, v in Animator:GetPlayingAnimationTracks() do
		v:Stop()
	end
	
	local offset = {}
	
	local function getMotor6DFromPose(pose : Pose) : Motor6D		
		for i, v in rig:GetDescendants() do
			if v:IsA("Motor6D") and v.Part1.Name == pose.Name and v.Part0.Name == pose.Parent.Name then -- and v.Part0.Name == poseParentName
				return v
			end
		end
	end
	
	local children : {Keyframe}? = keyframes:GetKeyframes()
	
	table.sort(children, function(a, b)
		return a.Time < b.Time
	end)
	
	for nth, keyframe in children do
		local time = 0

		if children[nth + 1] then
			time = children[nth + 1].Time - keyframe.Time
		end

		for _, pose : Pose? in keyframe:GetDescendants() do
			local limb = getMotor6DFromPose(pose)

			if limb and pose.CFrame ~= CFrame.new() then
				offset[limb] = offset[limb] or limb.C0

				local EasingStyle, EasingDirection = 
					Enum.EasingStyle[pose.EasingStyle.Name], 
					Enum.EasingDirection[pose.EasingDirection.Name]

				pcall(function() 
					TweenService:Create(limb, TweenInfo.new(time, EasingStyle, EasingDirection), {C0 = offset[limb] * pose.CFrame}):Play() 
				end)
			end
		end

		wait(time)
	end
	
	for i, v in offset do
		TweenService:Create(i, TweenInfo.new(0.5), {C0 = v}):Play() 
	end
end

Unrelated but if you want to get the Animation Rig type of a keyframe sequence just use this function

local function getAnimationRigType(keyframes : KeyframeSequence)
	local function rigLimbExists(keyframe, rigType)
		local result = Rigs[rigType]:FindFirstChild(keyframe.Name)
		return (result and result.Name ~= "HumanoidRootPart")
	end
	
	for _, keyframe in keyframes:GetDescendants() do
		if rigLimbExists(keyframe, "R6") then
			return "R6"
		elseif rigLimbExists(keyframe, "R15") then
			return "R15"		
		end
	end
end

Feedback will be appreciated

1 Like

i dont see how this is better, its just manually animating the rig with tweens which is very performance impactful.

Ok Im just gonna name it to a keyframe sequence player

How do I make it less peformanec Impactful

perhaps try doing something other than tweens, like lerping

2 Likes

How is that any more performant?

Is this better @kalabgs

local function playKeyframes(rig : Model, keyframes : KeyframeSequence)
	local offset = {}
	
	local function getMotor6DFromPose(pose : Pose) : Motor6D		
		for i, v in rig:GetDescendants() do
			if v:IsA("Motor6D") and v.Part1.Name == pose.Name and v.Part0.Name == pose.Parent.Name then -- and v.Part0.Name == poseParentName
				return v
			end
		end
	end
	
	local children : {Keyframe}? = keyframes:GetKeyframes()
	
	table.sort(children, function(a, b)
		return a.Time < b.Time
	end)
	
	for nth, keyframe in children do
		local time = 0
		
		if children[nth + 1] then
			time = children[nth + 1].Time - keyframe.Time
		end
		
		for _, pose : Pose? in keyframe:GetDescendants() do
			local limb = getMotor6DFromPose(pose)

			if limb and pose.CFrame ~= CFrame.new() then
				offset[limb] = offset[limb] or limb.C0
				
				local EasingStyle, EasingDirection = 
					Enum.EasingStyle[pose.EasingStyle.Name], 
					Enum.EasingDirection[pose.EasingDirection.Name]

				local ticked = tick()

				spawn(function()
					--transform
					while tick() - ticked < time do
						local cframe = limb.C0

						-- n / time
						limb.C0 = cframe:Lerp(offset[limb] * pose.CFrame, TweenService:GetValue((tick() - ticked) / time, EasingStyle, EasingDirection))
						RunService.PreSimulation:Wait()	
					end

					limb.C0 = offset[limb] * pose.CFrame
				end)
			end
		end
		
		wait(time)
	end
end

it isn’t but its better. There is no way that it can be as performant as animations

I highly doubt there is a difference. They all do the same thing.

apologies fro reviving im on my customanimator rampage

one critique is this assumes the animation has keyframes for every joint every keyframe.
Roblox’s account for this if this isn’t the case, it gets the previous joint cf to the next cf checking every keyframe after for it so we can do that sick smooth lerp overtime.

1 Like