So heya as said in the title i am working on a custom animator that can use KeyframeSequence instead of animations i think it can be useful for free models because KeyframeSequence do not need to be published it also have functions to modify animations or save them in datastores as a table.
here is the code: (early prototype)
local TweenService = game:GetService('TweenService')
local RunService = game:GetService("RunService")
local AnimationEditor = {}
local Animator = {}
function FindMotorFromName(Character:Model,Name:string):Motor6D
for i,v in pairs(Character:GetDescendants()) do
if v:IsA("Motor6D") and v.Part1 and v.Part1.Name == Name then
return v
end
end
end
function GetClosestS(MotorAnimation,Time)
local Return = MotorAnimation[1]
local I = -1
for i,v in pairs(MotorAnimation) do
if v.Time>Time then
return Return,I
else
Return = v
I = i
end
end
return Return,I
end
function Animator.CreateAnimation(Character:Model,Animation,Repeat,Speed:number):{Speed:number,Time:number,AdjustSpeed:(speed:number)->(),AdjustTime:(time:number)->(),Play:(FadeTime:number?)->(),Stop:()->(),Remove:()->(),Completed:RBXScriptSignal}
local Ret = {}
Speed = Speed or 1
local Time = 0
local Playing = false
local Completed = Instance.new("BindableEvent",script)
local function Play(FadeTime:number)
if RunService:IsServer() then return end
if FadeTime>0 then
local FTime = 0
local TrF:{CFrame} = {}
while FTime<FadeTime do
if Playing == false then return end
for MotorN,Motor in pairs(Animation) do
if TrF[MotorN] == nil then
TrF[MotorN] = FindMotorFromName(Character,MotorN).Transform
end
local Last:{Time:number,CFrame:CFrame},LN = GetClosestS(Motor,Time)
local Next = Motor[LN+1] or Last
local Per = math.clamp((Time-Last.Time)/(Next.Time-Last.Time),0,1)
local Target = Last.CFrame:Lerp(Next.CFrame,TweenService:GetValue(Per,Enum.EasingStyle[Next.EasingStyle.Name],Enum.EasingDirection[Next.EasingDirection.Name]))
FindMotorFromName(Character,MotorN).Transform = TrF[MotorN]:Lerp(GetClosestS(Motor,Time).CFrame,FTime/FadeTime)
end
local delta = RunService.RenderStepped:Wait()
FTime+=delta
end
end
while Playing do
repeat
if Playing == false then return end
local delta = RunService.RenderStepped:Wait()
Time += delta*Speed
Ret.Time = Time
for MotorN,Motor in pairs(Animation) do
local Last:{Time:number,CFrame:CFrame},LN = GetClosestS(Motor,Time)
local Next = Motor[LN+1] or Last
local Per = math.clamp((Time-Last.Time)/(Next.Time-Last.Time),0,1)
FindMotorFromName(Character,MotorN).Transform = Last.CFrame:Lerp(Next.CFrame,TweenService:GetValue(Per,Enum.EasingStyle[Next.EasingStyle.Name],Enum.EasingDirection[Next.EasingDirection.Name]))
end
until Time>AnimationEditor.GetAnimationLenght(Animation) or Time<=0 and Speed<0
if Speed<0 then
Time = AnimationEditor.GetAnimationLenght(Animation)
else
Time = 0
end
if not Repeat then
Playing = false
end
end
Completed:Fire()
end
Ret.Time = 0
Ret.Speed = Speed
function Ret.AdjustSpeed(speed:number)
Speed = speed
Ret.Speed = speed
end
function Ret.AdjustTime(Time2:number)
Time = Time2
end
function Ret.Play(FadeTime:number?)
if Playing then return end
Playing = true
spawn(function()
Play(FadeTime or 0)
end)
end
function Ret.Stop()
Playing = false
end
function Ret.Remove()
Completed:Destroy()
Playing = false
end
Character.Destroying:Connect(Ret.Remove)
Ret.Completed = Completed.Event
--local test = Instance.new("Humanoid"):LoadAnimation(Instance.new("Animation"))
return Ret
end
function Animator.GetfromKeyframe(Character:Model,Keyframeanimation:KeyframeSequence)
local Animation = {}
for i,Step in pairs(Keyframeanimation:GetChildren()) do
for i,Motor:Pose in pairs(Step:GetDescendants()) do
Animation[Motor.Name] = Animation[Motor.Name] or {}
Animation[Motor.Name][-1] = {Time=Step.Time,CFrame=Motor.CFrame,EasingStyle=Motor.EasingStyle,EasingDirection=Motor.EasingDirection}
Animation[Motor.Name] = AnimationEditor.SortSteps(Animation[Motor.Name])
end
end
return AnimationEditor.CreateAnimation(Character,Animation)
end
function StopCharacterAnimations(Character)
StopAnimations:Fire(Character)
end
function AnimationEditor.CreateAnimation(Character:Model,BaseAnimation)
BaseAnimation = BaseAnimation or {}
local Animation = {}
local Motors = {} for i,v in pairs(Character:GetDescendants())do if v:IsA("Motor6D")then table.insert(Motors,v)end end
for i,Motor6D:Motor6D in pairs(Motors) do
Animation[Motor6D.Name] = BaseAnimation[Motor6D.Name] or {}
end
return Animation
end
function AnimationEditor.SortSteps(Key:{})
--sort Key by Time
local Unsorted = Key
local Sorted = {}
repeat
local Biggest = {Time=math.huge}
local I = nil
local Number = 0
for i,v in pairs(Unsorted) do
if v.Time<Biggest.Time then
Biggest = v
I = i
end
Number+=1
end
if Number == 0 then return Sorted end
Unsorted[I or -1] = nil
table.insert(Sorted,Biggest)
until Number == 0
return Sorted
end
function AnimationEditor.FindStep(Key,Time)
for i,v in pairs(Key) do
if v.Time==Time then
return i
end
end
return -1
end
function AnimationEditor.ModifyStep(Animation,Motor,Data)
Animation[Motor][AnimationEditor.FindStep(Animation[Motor],Data.Time) or -1] = Data
Animation[Motor] = AnimationEditor.SortSteps(Animation[Motor])
end
function AnimationEditor.RemoveStep(Animation,Motor,Time)
Animation[Motor][AnimationEditor.FindStep(Animation[Motor],Time)] = nil
end
function AnimationEditor.GetAnimationLenght(Animation:{})
local Time = 0
for i,Motor in pairs(Animation) do
for i,Step:{Time:number} in pairs(Motor) do
if Step.Time>Time then
Time = Step.Time
end
end
end
return Time
end
local Module = {}
Module.AnimationEditor = AnimationEditor
Module.Animator = Animator
return Module
to use this code remove any animator in the character you try to animate
An example of what you can do with it: Table animation - Roblox
Why you should NOT use it:
-not replicated (Transphorm is not possible to modify on the server but im gonna try to fix it later )
-glitch if multiple animations are applied on the same character at the same time but will be fixed
-disable normal animation will be fixed
if you find bugs tell me i would be happy to fix it or if you have suggestions thank for reading hope you enjoy this prototype
Edit: roblox code block made my life hell on this one