Hi, I have a script that utilizes CFrames a lot, I’m multiplying a CFrame by many small CFrames incrementally. For some reason it keeps exploding into big numbers, inf, and then NAN. Why is it getting so big? Here’s the script:
repeat
if not self.IsPlaying then return end
if self.IsPaused then coroutine.yield() end
self.CurrentIncrement += RS.RenderStepped:Wait()
local incrementCFrame = self.RealCFrame:ToObjectSpace(keyframe.Keyframe:GetCFrame(self.CurrentIncrement / keyframe.Length))
self.RealCFrame *= incrementCFrame -- incremented cframe (small)
print(self.RealCFrame)
self.Character:PivotTo(
(self.LocksPosition and self.RealCFrame) or
self.Character:GetPivot() * incrementCFrame)
until self.CurrentIncrement >= keyframe.Length end
You could be accumulating errors due to numerical precision when you repeatedly multiply small CFrames. This can lead to exponentially growing values, eventually resulting in large numbers, inf, or NaN (not a number).
One approach to fix this issue is to periodically “normalize” your CFrame, essentially resetting its position and orientation to prevent the build up of numerical errors. Try converting your CFrame to a rotation matrix, then back to a CFrame.
repeat
if not self.IsPlaying then return end
if self.IsPaused then coroutine.yield() end
self.CurrentIncrement += RS.RenderStepped:Wait()
local incrementCFrame = self.RealCFrame:ToObjectSpace(keyframe.Keyframe:GetCFrame(self.CurrentIncrement / keyframe.Length))
self.RealCFrame *= incrementCFrame -- incremented cframe (small)
-- Periodically normalize RealCFrame to prevent accumulation of errors
if self.CurrentIncrement % normalizeInterval == 0 then
local _, _, _, _, _, _, x, y, z = self.RealCFrame:GetComponents()
self.RealCFrame = CFrame.new(x, y, z)
end
print(self.RealCFrame)
self.Character:PivotTo(
(self.LocksPosition and self.RealCFrame) or
self.Character:GetPivot() * incrementCFrame)
until self
I tried to do this, I found a person with the same problem and shared a “normalizing” script. Thanks, I’ll see if it helps, but aren’t you leaving out the rotation?
What library are you using that provides that GetCFrame method for animation keyframes? I think it might be important to see its source code to determine if it’s giving invalid results that poison your CFrame math into oblivion.
It’s not really a library I would say it’s just a resource, I happened to be using my own resource, but it just gives arbritrary CFrames. I can show you what it prints, if you want?
Could you add a print statement specifically for incrementCFrame? Please add a label to both the increment and real CFrames so they’re distinguished in the console.
Could you run the code long enough that INF and NaN values appear and send a screenshot of the log around the point that happens?
You say that GetCFrame is from a resource of your own. Can I ask if this method does any clamping for its argument before fetching the keyframe CFrame?
Yes, it starts to happen when I run animations that last a while, probably because the error increases.
And yes it’s a resource of my own. The script printing is apart of the same resource, it’s just using a separate part of the resource. And no, it doesn’t clamp anything.
Ignore the “Attack failed: ERR 6”, that’s intended.
I can provide more code, if you want. I think the issue is just because I’m multiply REALLY small cframes and angles by the same cframe, causes floating point and calculation inaccuracy, which leads to exploding and inf, then nan. But how do I make it not do that? That’s my question.
I probably should’ve asked this earlier but what are you trying to do in your script? Adjusting the realCFrame with the object space of a keyframe CFrame based off the realCFrame seems a bit strange.
When testing this logic, do you visually see the animation working as you’d expect?
It’s a bit janky, let me send you a video. Here’s the backstory.
I’m working on a battlegrounds game, and I want consistent movement for the player. I designed a module to animate the CFrame of PVInstances, so I could get consistent movements. Like a slight movement forward before a punch.
It’s customizable, so I can change it to lock CFrames, or it can be moved while in the animation, but to achieve this effect I need to make it incremental, where as of before it assigned CFrames, now it increments CFrames, and now I’m having this problem. It does work a little as intended but it’s a bit janky. It glitches around, and it wasn’t doing that before. It has to be because of floating point error.
The reason I have to do this specific setup is because I made it the way I explained earlier. It’s toggleable between LOCKING CFrames (cannot change the position the animation occurs at once started) and free (animation animates off of the instance, can be moved while doing animation).
I have ran into issues with NaN before, very, very annoying. Also very hard to debug because it happened so rarely. But I was able to debug it
I noticed that DeltaTime returned by RenderStepped can sometimes be 0 (I couldn’t find it in my scripts, I am pretty sure I noted that with a comment. So this statement is what I recall from my memory, and might be wrong)
In the case dt is 0, you are sending 0 to keyframe.Keyframe:GetCFrame() (misread the script, not true). Maybe the issue comes from there, idk
Another useful thing to know is that NaN is not equal to itself. This means that to verify if a number, or a CFrame, or whatever, is NaN you can do this
if Number ~= Number then
-- Number is NaN
end
In my case, I use this to stop NaN from breaking my scripts, as I cannot avoid NaN, it just happens from time to time, seemingly at random? idk… It was happening more often with a high fps (unlocked)
Okay, so now I know how to check it, but I still need to know how to prevent floating point errors. I’m not completely sure why it’s getting extremely big or small.