Simulated newtonian orbit is anomalously growing

I created a simple script that can simulate gravity for multiple bodies (more than 2). It doesn’t use BodyForces, but instead uses TweenService to smoothly move between calculated positions. However, when I attempt to simulate a light body orbiting massive object, the orbit slowly grows in size. How do I fix this?

orbitgainen.wmv

Code used to calculate velocity and position:

local AugendVelocity = Vector3.new(0, 0, 0)
	
--Get individual velocities
for _, Object in pairs(workspace.Space:GetChildren()) do
	--Check if object isn't itself
	if Object ~= self then
		--Get mass, difference, and distances
		local Mass1 = self.Mass.Value
		local Mass2 = Object.MassVal.Value
		local Difference = Object.Position - self.Position
		local Distance = Difference.Magnitude
		
		--Calculate force in newtons and acceleration in studs/meters
		local Force = G*Mass1*Mass2/(Distance^2)
		local AddendVelocity = Difference.Unit*Force/Mass1 --F = ma -> F/m = a
		
		--Add velocity after accounting for time
		AugendVelocity = AugendVelocity + AddendVelocity*Time
	end
end

--Set positions and velocity
Velocity = AugendVelocity + Velocity
Position = Position + Velocity
3 Likes

Apparently switching to a more OOP based approach fixed the issue, which is strange because I didn’t really change how gravity is simulated.

Hey there, I’m having the same issue. The orbit slowly grows until the orbiting body basically escapes. I’m not familiar with OOP, what exactly do you mean by switching to a more OOP based apprach?

Old Approach:

function newBody(mass)
    local body = {mass = mass}
    --more code
    return body
end

function simulateGravity(body)
    --code
end

Newer Approach:

local body = {}; body.__index = body

function body:simulateGravity()
    --code
end

function body.new(mass)
    local inst = setmetatable({mass = mass}, body}
    --more code
    return inst
end

Hi there. I’ve done a thing or two with orbits on Roblox

Mind sharing more of the OOP implementation? I have a hypothesis as to the underlying cause of this issue. I only ask because someone reached out to me on Discord with a similar problem and referenced this post.

Thanks!

Sorry, this post is old and I don’t have the exact copy of the code anymore, but I should have a more recent implementation of this somewhere. I’ll DM you when I find it.

1 Like

Ah, no worries. Didn’t realize the post was two years old, haha

If you are curious, what likely solved the problem was not OOP itself, but moving to raw Lua numbers.

Some background: computers can only represent binary values. So if we want to represent something like a decimal value, we can only store an approximation of that value encoded in binary. There will always be some error.

In orbital mechanics, we work with very large (mass of planets) and very small (G) values. The Roblox physics engine uses 32-bit floating point numbers for their calculations. These numbers are fast, but only have about 7 decimal places of accuracy. In other words, they can only accurately represent position values about 9 kilostuds away from the origin with millistud precision (9999.999 is seven decimal places). So doing math on very small and large values can cause the rapid loss of accuracy, leading to the “ghost forces” which you describe.

Raw Lua numbers, on the other hand, are 64 bit numbers. These numbers are slower, but can represent a HUGE range of values. About 14-17 decimal places of accuracy! This can fit the entire solar system in centimeter precision.

So by moving your calculations to an object, which is represented by a table with Lua number values, you moved from 32 bit numbers to 64 bit numbers. Thus, the math worked out; there was enough accuracy to represent values from G to the masses of planets without incurring large amounts of error.

If you are interested, you can read more about floating point numbers here. You can also check out my orbital mechanics library here if you like space stuff.