I’m making a custom animation module, basically a stripped down version of roblox’s default Animate script and modularised, with a few extra features such as detecting signals within the animation. While testing, I’ve noticed that the animtable property turns to nil at some point, and I’m not sure why. I have a function inside the util module required which prints the table and the animtable is correctly loaded. However, all my errors come from accessing the animtable to actually play the animations. Any help would be appreciated.
local player = game:GetService("Players").LocalPlayer
local repstore = game:GetService("ReplicatedStorage").repstore
local util = require(repstore.modules.util)
local animids = require(script.anims)
local signals = require(script.signals)
local animate = {}
animate.__index = animate
function animate.new(char)
local root = char:FindFirstChild("HumanoidRootPart")
--local hum = char.Humanoid
--[[for name,anim in next,animids do
local animation = Instance.new("Animation")
animation.AnimationId = anim.id
animation.Name = name
animation.Parent = repstore.anims
anims[name] = hum:LoadAnimation(animation)
end]]
return setmetatable({
char =char,
root =root,
rightshoulder =char:WaitForChild("RightUpperArm"):FindFirstChild("RightShoulder"),
leftshoulder =char:WaitForChild("LeftUpperArm"):FindFirstChild("LeftShoulder"),
righthip =char:WaitForChild("RightUpperLeg"):FindFirstChild("RightHip"),
lefthip =char:WaitForChild("LeftUpperLeg"):FindFirstChild("LeftHip"),
neck =char:WaitForChild("Head"):FindFirstChild("Neck"),
hum =char:WaitForChild("Humanoid"),
pose ="idle",
currentanim =nil,
currentidx =1,
currentanimspeed =1,
animtable ={},
jumpanimtime =0,
jumpanimduration =0.3,
enabled =true,
preloaded ={},
lasttick =nil,
currentsignalhandlers ={},
loopertime =1/10
},animate)
end
function animate:setchar(char) self.char=char end
function animate:getchar() return self.char end
function animate:getenabled() return self.enabled end
function animate:setenabled(bool) self.enabled = bool end
function animate:getlasttick() return self.lasttick end
function animate:randomint(a,b) return Random.new(tick()):NextInteger(a,b) end
function animate:stopcurrent(time) self.currentanim:Stop(time) self:setpose("") end
function animate:getanim(name) return self.animtable[name] end
function animate:load(name,filelist)
print("animate:load(",name,filelist,")")
if self.animtable[name] then return end
self.animtable[name] = { count=0,totalweight=0 }
self.animtable[name].getcount = function(self) return self.count end
self.animtable[name].gettotalweight = function(self) return self.totalweight end
if self.animtable[name].count <= 0 then
for idx,anim in next,filelist do
self.animtable[name][idx] = {}
self.animtable[name][idx].anim = Instance.new("Animation")
self.animtable[name][idx].anim.Parent = repstore.anims
self.animtable[name][idx].anim.Name = name
self.animtable[name][idx].anim.AnimationId = anim.id
self.animtable[name][idx].weight = anim.weight
self.animtable[name][idx].looped = anim.looped
self.animtable[name].count += 1
self.animtable[name].totalweight += anim.weight
end
end
for i,animtype in next,self.animtable do
for idx=1,animtype.count,1 do
if self.preloaded[animtype[idx].anim.AnimationId] == nil then
self.animtable[i][idx].track = self.hum:LoadAnimation(animtype[idx].anim)
self.animtable[name][idx].track.Looped = animtype[idx].looped
self.preloaded[animtype[idx].anim.AnimationId] = true
end
end
end
end
function animate:setup()
for name,filelist in next,animids do
if type(filelist)~="function" then
self:load(name,filelist)
end
end
end
function animate:stopall()
local oldanim = self.currentanim
if self.currentkeyframehandler then self.currentkeyframehandler:Disconnect() end
if self.currentanim then self:stopcurrent() end
return oldanim
end
function animate:setspeed(speed)
if speed ~= self.currentanimspeed and self.currentanim then
self.currentanimspeed = speed
self.currentanim:AdjustSpeed(self.currentanimspeed)
end
end
function animate:rollanim()
if self.animtable[self.pose] == nil then return nil end
local roll = self:randomint(1,self.animtable[self.pose].totalweight)
local origroll = roll
local idx=1
while roll > self.animtable[self.pose][idx].weight do
roll -= self.animtable[self.pose][idx].weight
idx += 1
end
return idx
end
function animate:play(name,time)
self.pose = name
self.currentidx = self:rollanim()
self.currentanim = self.animtable[self.pose][self.currentidx].track
if signals[name] then
for signalname,signal in next,signals[name] do
if self.currentsignalhandlers[signalname] then self.currentsignalhandlers[signalname]:Disconnect() end
self.currentsignalhandlers[signalname] = self.currentanim:GetMarkerReachedSignal(signalname):Connect(function()
signals[name][signalname]()
end)
end
end
self:setspeed(1)
self.currentanim:Play(time)
end
function animate:setpose(pose,time)
time = time or 0.2
if self.animtable[pose] then
animate:play(pose,time)
else
self.pose = pose
end
end
function animate:ondied() return function() self:setpose("dead") end end
function animate:onrunning()
return function(speed)
if speed > 0.1 then
if self.hum.WalkSpeed > 16 then
self:setpose("run")
else
self:setpose("walk")
end
else
self:setpose("idle")
end
end
end
function animate:onjumping()
return function()
self:setpose("jump",0)
self.jumpanimtime = self.jumpanimduration
end
end
function animate:onclimbing()
return function(speed)
self:setpose("climb",0.1)
self:setspeed(speed/12)
end
end
function animate:ongettingup() return function() self:setpose("gettingup") end end
function animate:onfreefalling()
return function()
if self.jumpanimtime <= 0 then self:setpose("fall",self.falltransitiontime) end
end
end
function animate:onfallingdown() return function() self:setpose("fallingdown") end end
function animate:onseated() return function() self:setpose("sit") end end
function animate:onplatformstanding() return function() self:setpose("platformstanding") end end
function animate:step(t)
local ts = self.lasttick and t-self.lasttick or self.loopertime
self.lasttick=t
if not self.hum then return end
if self.jumpanimtime then if self.jumpanimtime > 0 then self.jumpanimtime -= ts end end
if self.pose == "dead" or self.pose == "gettingup" or self.pose == "fallingdown" or self.pose == "seated" or self.pose == "platformstanding" then
self:stopall()
end
end
function animate.init(char)
local newanimate = animate.new(char)
newanimate:setup()
local hum = newanimate.hum
hum.Died:Connect(newanimate:ondied())
hum.Running:Connect(newanimate:onrunning())
hum.Jumping:Connect(newanimate:onjumping())
hum.Climbing:Connect(newanimate:onclimbing())
hum.GettingUp:Connect(newanimate:ongettingup())
hum.FreeFalling:Connect(newanimate:onfreefalling())
hum.FallingDown:Connect(newanimate:onfallingdown())
hum.Seated:Connect(newanimate:onseated())
hum.PlatformStanding:Connect(newanimate:onplatformstanding())
util.printtable(newanimate.animtable)
newanimate:play("idle",0)
coroutine.wrap(function()
while newanimate.char and newanimate.char.Parent do
local _,t = wait(newanimate.loopertime)
newanimate:step(t)
end
end)()
return animate
end
return animate