Why is Roblox's physics so unpredictable and how can you get around this?

Using this equation I can solve for the predicted position at time (t)–given the initial position (x₀), initial velocity (v₀), and a constant acceleration (a).

x = x₀ + v₀t + (1/2)at²

My issue is that, although this equation should give me a result that is very close to the real position of the projectile, it doesn’t. Even on the axis of which there is no acceleration it rarely gets a percise-enough result. It is especially worse on the Y-axis for some reason too.

Is your projectile network owned by either the server or client at all times? If it switches from client while near the player to server when farther away that could lead to some inconsistency. Also, what are you using to accelerate the projectile and what value are you using for the acceleration constant?

roblox physics use euler integration, which is what most games use for their physics, it is less accurate than your equation, but faster and accurate enough to give believable results. the accuracy directly depends on the time difference between physics steps (delta time), a smaller delta time gives more accurate results but you need to run the simulation for more iterations

1 Like

The projectile is owned by the client at all times. When the projectile touches something, that data is put into a table, giving the new velocity and initial position and the hit position. The server will then take these values and verify that the trajectory seems correct.

Is this “euler integration” some sort of formula similar to the kinematic equation I already have? I have heard of it before in this post.

I have tried implementing the fix that this post suggests but it does not work, albeit the post is very old.

euler integration is just adding velocity * delta_time to the position every frame, you cant really figure out where the projectile will be with 1 single calculation, you will have to do it a bunch of times, roblox doesnt have to pre-calculate the entire trajectory but just where the part will be the next frame

in pseudocode, eulers method looks like this:

Heartbeat(dt)
    part.Velocity += (forces / part.Mass) * dt
    part.Position += part.Velocity * dt

Do you think that this error can be quantified like @tyzone says? When I follow his solution, it appears that the issue persists–even after using his provided test code.

The post is 3 years old which means a Roblox update must have broken his solution.

an update wouldnt really affect this unless they changed the physics solution from euler to something else. tyzones correction is specific to euler, it should still work but it will never be 100% accurate in the real world because of micro lag like fps varying from as little as 60 to 59.98 to 60.04 will accumulate over time, tyzones correction assumes a constant time step.
but i believe roblox did change the physics stepping method from fixed to adaptive by default, which means the delta time varies to improve performance. if you havent already, try setting Workspace.PhysicsSteppingMethod to fixed and try again

you can also simply not use roblox physics at all and use the same equation on both the client to launch the projectile, and on the server to verify its trajectory

u cant bro, u need roblox to update their physics themselves. i suggest making ur own physics system using lerps/tweens.

ROBLOX has not changed their integration method as of recent so the fix mentioned in that old post is still valid. However, the post is about an inaccuracy due to forces and accelerations (such as gravity), so in the case of a ball shot in a parabolic trajectory, this should only cause an inaccuracy on the Y axis (and not as large as the one depicted in your video; it’s only 0.4 studs per second with normal gravity settings), so the issue lies elsewhere.

Could you provide us with the .rbxl file used in that video? Here’s a test place I’ve got where results are pretty close (there’s a discrepancy of roughly 2 studs between predicted and measured positions on the Y axis after 5 seconds, which is due to the inaccuracy explained in the quoted post)

Note I’ve set physics stepping to “Fixed” in the workspace’s properties, though I don’t think this should have any impact in this scenario

I also used this line in my code dt = wait(dt) which ensures that the value of dt more accurately represents how long the ball has been flying (for example wait(5) will return a value like 5.008), however I don’t think this discrepancy would be large enough to explain the results in your video either.

testfallingobject.rbxl (54.5 KB)