Annoying animation bug ingame (Door animation is too strong)

Don’t suppose you could provide a file with the keyframe sequence and door?

You can simplify the door if you don’t wish to share the details, but then id reccoment testing to ensure 100% that the door copy has the bug too

1 Like

What’s the verdict? Did it work? Did it not work? @kalet14

As you can see i’m on the edge of my seat

Well, I’m still stuck since I still have no idea how to use the module due to it still giving me errors, but from what I can tell this is supposed to work through a local script which is something that I’m not looking for due to the fact that I’m making a multiplayer game and I need the doors to open for everyone.

local CutsceneAnimation = require(game.ReplicatedStorage.CutsceneAnimation)

local pathToKeyframeSequence = script.Parent.AnimSaves.Untitled
local DoorOpen = CutsceneAnimation.new(pathToKeyframeSequence)

script.Parent.Door:WaitForChild("Handle").ProximityPrompt.Triggered:Connect(function()
	DoorOpen:Play(script.Parent)
end)

I got you covered replace the module you have with this

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local CutsceneAnimation = {}
CutsceneAnimation.__index = CutsceneAnimation

function CutsceneAnimation.new(sequence : KeyframeSequence)
   local self = {}
   setmetatable(self, CutsceneAnimation)
   self.KeyframeSequence = sequence
   self.Keyframes = sequence:GetKeyframes()
   self.Frame = 1
   self.Motors = {}
   return self
end

function CutsceneAnimation:UpdatePose(frame, DT : number)
   for _, pose : Pose in ipairs(frame:GetDescendants()) do
      if pose:IsA("Pose") then
         local Motor = self.Motors[pose.Name]
         if Motor then
            local x,y,z = pose.CFrame:ToEulerAnglesXYZ()
            if x == 0 and y == 0 and z == 0 and pose.CFrame.Position.Magnitude == 0 then
               continue
            end
            Motor.Transform:Lerp(pose.CFrame, DT)
         end
      end
   end
end

function CutsceneAnimation:Play(Rig : Model, startCFrame : CFrame)
   local CutsceneRig = Rig
   self.CutsceneRig = CutsceneRig
   local accumulatedTime = self.AccumulatedTime or 0

   for _, motor in ipairs(self.CutsceneRig:GetDescendants()) do
      if motor:IsA("Motor6D") then
         self.Motors[motor.Name] = motor
      end
   end

   if not startCFrame then
      startCFrame = CutsceneRig.PrimaryPart.CFrame
   end

   CutsceneRig.PrimaryPart.Anchored = true
   CutsceneRig.PrimaryPart.CFrame = startCFrame

   CutsceneAnimation[Rig] = true

   table.sort(self.Keyframes, function(a, b)
      return a.Time < b.Time
   end)

   self:UpdatePose(self.Keyframes[self.Frame])

   local Connection = nil

   Connection = RunService.Heartbeat:Connect(function(DT)
      if self.Paused then return end

      accumulatedTime += DT

      while self.Frame < #self.Keyframes and accumulatedTime >= self.Keyframes[self.Frame + 1].Time  do
         self.Frame += 1
         self:UpdatePose(self.Keyframes[self.Frame], DT * 7)
      end


      if accumulatedTime >= self.Keyframes[self.EndKeyframe or #self.Keyframes].Time then
         Connection:Disconnect()
         Connection = nil
         CutsceneAnimation[Rig] = false
      end
   end)
end

return CutsceneAnimation

I won’t give up on this, we’re going to get this working

Alright so I’m guessing the ProximityPrompt is on the client, okay so all you need to do is create a remote event and then tell it which door to open and then you do the door module stuff setup on the server and play it on the server

I won’t be providing a file for that due to the fact that the issue doesn’t lie within the animation itself since it works perfectly when I import it through Blender to Studio and in the playback/Moon animator.

This is all the of what I’m able to provide right now simply because I do not like giving out my models to people rather than scripts. I’ve also seen multiple people have an issue exactly like mines but they didn’t seem to get any help at all despite having different rigs on their end.

1 Like

image
Unfortunately it still gives me the same error without any changes made to the script.

local CutsceneAnimation = require(game.ReplicatedStorage.CutsceneAnimation)

local pathToKeyframeSequence = script.Parent.AnimSaves.Untitled
local DoorOpen = CutsceneAnimation.new(pathToKeyframeSequence)

script.Parent.Door:WaitForChild("Handle").ProximityPrompt.Triggered:Connect(function()
	DoorOpen:Play(script.Parent)
end)

Okay hold on let’s just work through this let’s first get it working on the client so we know it can work and then i’ll help you with having it animate for all clients!

1 Like

Okay replace the module with this

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local CutsceneAnimation = {}
CutsceneAnimation.__index = CutsceneAnimation

function CutsceneAnimation.new(sequence : KeyframeSequence)
   local self = {}
   setmetatable(self, CutsceneAnimation)
   self.KeyframeSequence = sequence
   self.Keyframes = sequence:GetKeyframes()
   self.Frame = 1
   self.Motors = {}
   return self
end

function CutsceneAnimation:UpdatePose(frame, DT : number)
   for _, pose : Pose in ipairs(frame:GetDescendants()) do
      if pose:IsA("Pose") then
         local Motor = self.Motors[pose.Name]
         if Motor then
            local x,y,z = pose.CFrame:ToEulerAnglesXYZ()
            if x == 0 and y == 0 and z == 0 and pose.CFrame.Position.Magnitude == 0 then
               continue
            end
            Motor.Transform = Motor.Transform:Lerp(pose.CFrame, DT)
         end
      end
   end
end

function CutsceneAnimation:Play(Rig : Model, startCFrame : CFrame)
   local CutsceneRig = Rig
   self.CutsceneRig = CutsceneRig
   local accumulatedTime = self.AccumulatedTime or 0

   for _, motor in ipairs(self.CutsceneRig:GetDescendants()) do
      if motor:IsA("Motor6D") then
         self.Motors[motor.Name] = motor
      end
   end

   if not startCFrame then
      startCFrame = CutsceneRig.PrimaryPart.CFrame
   end

   CutsceneRig.PrimaryPart.Anchored = true
   CutsceneRig.PrimaryPart.CFrame = startCFrame

   CutsceneAnimation[Rig] = true

   table.sort(self.Keyframes, function(a, b)
      return a.Time < b.Time
   end)

   self:UpdatePose(self.Keyframes[self.Frame], 0)

   local Connection = nil

   Connection = RunService.Heartbeat:Connect(function(DT)
      if self.Paused then return end

      accumulatedTime += DT

      while self.Frame < #self.Keyframes and accumulatedTime >= self.Keyframes[self.Frame + 1].Time  do
         self.Frame += 1
         self:UpdatePose(self.Keyframes[self.Frame], DT * 7)
      end


      if accumulatedTime >= self.Keyframes[self.EndKeyframe or #self.Keyframes].Time then
         Connection:Disconnect()
         Connection = nil
         CutsceneAnimation[Rig] = false
      end
   end)
end

return CutsceneAnimation
1 Like

Fair enough. Hope it gets solved, but if you change your mind then lemme know, you can just strip off anything unnecessary if you don’t wish to share the model, assuming the bug persists with a stripped down version. Even if the animation itself isn’t the issue, I’d still need it to check issues with the model/script.

3 Likes

I guess it somewhat moves the door but it doesn’t really do much other than leave it like this…

Not to mention its movement is really laggy.

Could you please show a video?

External Media

I’m not sure why it does this

Try this, this will tell us how much frames there are in the sequence and also what frame it ended at

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local CutsceneAnimation = {}
CutsceneAnimation.__index = CutsceneAnimation

function CutsceneAnimation.new(sequence : KeyframeSequence)
   local self = {}
   setmetatable(self, CutsceneAnimation)
   self.KeyframeSequence = sequence
   self.Keyframes = sequence:GetKeyframes()
   self.Frame = 1
   self.Motors = {}
   print(#self.Keyframes.. "keyframes")
   return self
end

function CutsceneAnimation:UpdatePose(frame, DT : number)
   for _, pose : Pose in ipairs(frame:GetDescendants()) do
      if pose:IsA("Pose") then
         local Motor : Motor6D = self.Motors[pose.Name]
         if Motor then
            local x,y,z = pose.CFrame:ToEulerAnglesXYZ()
            if x == 0 and y == 0 and z == 0 and pose.CFrame.Position.Magnitude == 0 then
               continue
            end
            Motor.Transform = Motor.Transform:Lerp(pose.CFrame, DT)
         end
      end
   end
end

function CutsceneAnimation:Play(Rig : Model, startCFrame : CFrame)
   local CutsceneRig = Rig
   self.CutsceneRig = CutsceneRig
   local accumulatedTime = self.AccumulatedTime or 0

   for _, motor in ipairs(self.CutsceneRig:GetDescendants()) do
      if motor:IsA("Motor6D") then
         self.Motors[motor.Name] = motor
      end
   end

   if not startCFrame then
      startCFrame = CutsceneRig.PrimaryPart.CFrame
   end

   CutsceneRig.PrimaryPart.Anchored = true
   CutsceneRig.PrimaryPart.CFrame = startCFrame

   CutsceneAnimation[Rig] = true

   table.sort(self.Keyframes, function(a, b)
      return a.Time < b.Time
   end)

   self:UpdatePose(self.Keyframes[self.Frame], 0)

   local Connection = nil

   Connection = RunService.Heartbeat:Connect(function(DT)
      if self.Paused then return end

      accumulatedTime += DT

      while self.Frame < #self.Keyframes and accumulatedTime >= self.Keyframes[self.Frame + 1].Time do
         self.Frame += 1
         self:UpdatePose(self.Keyframes[self.Frame], DT * 7)
      end

      if accumulatedTime >= self.Keyframes[self.EndKeyframe or #self.Keyframes].Time then
         print("Stopped at"..self.Frame)
         Connection:Disconnect()
         Connection = nil
         CutsceneAnimation[Rig] = false
      end
   end)
end

return CutsceneAnimation

image
image

It says that there’s 5 keyframes in the animation.

1 Like

Am I missing something? To me, it seems like the speed is the same, it just has maybe a slight playing delay at the beginning, which is probably due to the fact that animations has to replicate to other clients.

You can run the animation locally for every player and see if that helps.

Hold up I’m going to do some testing on a rigged door I just got out of toolbox, just HOLD ON

Nothing was mentioned about the speed alone of the door. In the studio playback you can see it doesn’t fully go into the wall, but in the playtest it goes beyond the wall.

I wasn’t gonna give up on you that easily @kalet14 ,

Alright so get this awesome spring module and put it inside of ReplicatedStorage (I didn’t create)
spr (Spring Module).rbxm (9.6 KB)

It’ll allow super smooth movement with some nice spring action, also it’s safe so dont worry about that

And then use this updated module

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local spr = require(ReplicatedStorage.spr)
local RunService = game:GetService("RunService")
local CutsceneAnimation = {}
CutsceneAnimation.__index = CutsceneAnimation

function CutsceneAnimation.new(sequence : KeyframeSequence)
   local self = {}
   setmetatable(self, CutsceneAnimation)
   self.KeyframeSequence = sequence
   self.Keyframes = sequence:GetKeyframes()
   self.Frame = 1
   self.Motors = {}
   return self
end

function CutsceneAnimation:Play(Rig : Model, startCFrame : CFrame)
   local CutsceneRig = Rig
   self.CutsceneRig = CutsceneRig
   local accumulatedTime = self.AccumulatedTime or 0

   for _, motor in ipairs(self.CutsceneRig:GetDescendants()) do
      if motor:IsA("Motor6D") then
         self.Motors[motor.Name] = motor
      end
   end

   print(self.Motors)

   if not startCFrame then
      startCFrame = CutsceneRig.PrimaryPart.CFrame
   end

   CutsceneRig.PrimaryPart.Anchored = true
   CutsceneRig.PrimaryPart.CFrame = startCFrame

   CutsceneAnimation[Rig] = true

   table.sort(self.Keyframes, function(a, b)
      return a.Time < b.Time
   end)

   local Connection = nil

   local function updatePose()
      for _, pose : Pose in ipairs(self.Keyframes[self.Frame]:GetDescendants()) do
         if pose:IsA("Pose") then
            local Motor : Motor6D = self.Motors[pose.Name]
            if Motor then
               local x,y,z = pose.CFrame:ToEulerAnglesXYZ()
               if x == 0 and y == 0 and z == 0 and pose.CFrame.Position.Magnitude == 0 then
                  continue
               end
               spr.target(Motor, .4, 1,{
                  Transform = pose.CFrame
               })
            end
         end
      end
   end

   Connection = RunService.Heartbeat:Connect(function(DT)
      if self.Paused then return end

      accumulatedTime += DT

      while self.Frame < #self.Keyframes and accumulatedTime >= self.Keyframes[self.Frame + 1].Time do
         self.Frame += 1
         updatePose()
      end

      if accumulatedTime >= self.Keyframes[self.EndKeyframe or #self.Keyframes].Time then
         print("Animation ended")
         Connection:Disconnect()
         Connection = nil
         CutsceneAnimation[Rig] = false
      end
   end)
end

return CutsceneAnimation
1 Like

Unfortunately, I found a solution that isn’t really that well and limits my animating abilities for any future animations I make with the door model and that is using the animation editor that Studio has built in and I had to make a ton of keyframes since using any sort of easing at all will break the doors animation.

1 Like