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?

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

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?

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.

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.

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.