I watched a youtube video on some gravity simulation, and they let you see the source code, so I had this idea to recreate it in Roblox, but it was created with C# in Unity. Now I was sort of able to figure out what the code does but I wasn't sure so I did a few google searches if I didn't understand something. Now the thing is SOMETHING isn't right with it because the planets just follow each other and speed up over time until you experience floating-point precision errors, so I want to know, how good is my code? Here's the source: https://github.com/SebLague/Solar-System/tree/Episode_01/Assets/Scripts/Planets Here's my code: (I didn't do gravity object because it appeared to do nothing) Universe: (ModuleScript)
local Universe = { gravitationalConstant = 0.0001; physicsTimeStep = 0.01; }; Universe.updateProperties = function(G, T) Universe.gravitationalConstant = G Universe.physicsTimeStep = T end return Universe
CelestialBody: (ModuleScript)
local Universe = require(script.Parent.Universe) _G.CelestialBody = {} newCelestialBody = function() local this = {} this.radius = 0 this.surfaceGravity = 0 this.initialVelocity = Vector3.new(0, 0, 0) this.bodyName = "Unnamed" this.velocity = Vector3.new(0, 0, 0) this.mass = 0 this.rb = game.ServerStorage.MeshPart:Clone() this.rb.Parent = workspace local mv = Instance.new("IntValue", this.rb) mv.Name = "mass" this.Awake = function() this.rb.mass.Value = this.mass velocity = this.initialVelocity end this.UpdateVelocity = function(allBodies, timeStep) for i,otherBody in pairs(allBodies) do if otherBody ~= this then local sqrDst = (otherBody.rb.Position - this.rb.Position).Magnitude local forceDir = (otherBody.rb.Position - this.rb.Position).Unit local acceleration = forceDir * Universe.gravitationalConstant * otherBody.mass / sqrDst velocity += acceleration * timeStep end end end this.UpdateVelocity = function(acceleration, timeStep) velocity += acceleration * timeStep end this.UpdatePosition = function(timeStep) this.rb.Position += (velocity * timeStep) end this.OnValidate = function() this.mass = this.surfaceGravity * this.radius * this.radius / Universe.gravitationalConstant this.rb.Size = Vector3.new(1, 1, 1)* this.radius this.rb.Name = this.bodyName end this.rb.Changed:Connect(this.OnValidate) this.RigidBody = function() return this.rb end this.Position = function() return this.rb.Position end table.insert(_G.CelestialBody, this) return this end return newCelestialBody
NBodySimulation: (ModuleScript)
local Universe = require(script.Parent.Universe) local Time = {fixedDeltaTime = 0} function newNBodySimulation() local this = {} this.bodies = _G.CelestialBody this.NBodySimulation = Instance.new("Folder", workspace) this.Awake = function() this.bodies = _G.CelestialBody Time.fixedDeltaTime = Universe.physicsTimeStep print("Setting fixedDeltaTime to: "..Universe.physicsTimeStep) end this.FixedUpdate = function() for i = 1, #this.bodies do local acceleration = this.CalculateAcceleration(this.bodies[i].Position(), this.bodies[i]) this.bodies[i].UpdateVelocity(acceleration, Universe.physicsTimeStep) end for i = 1, #this.bodies do this.bodies[i].UpdatePosition(Universe.physicsTimeStep) end end this.CalculateAcceleration = function(point, ignoreBody) local acceleration = Vector3.new(0, 0, 0) for i,body in pairs(this.bodies) do if body ~= ignoreBody then local sqrDst = (body.Position() - point).Magnitude local forceDir = (body.Position() - point).Unit acceleration += forceDir * Universe.gravitationalConstant * body.mass / sqrDst print(acceleration) end end return acceleration end this.Bodies = function() return this.bodies end this.NBodySimulation = function(instance) if instance == nil then instance = this.NBodySimulation end return instance end return this end return newNBodySimulation
Heres an example script to demonstrate usage:
local CelestialBody = require(script.Parent.CelestialBody) local NBodySimulation = require(script.Parent.NBodySimulation) local planet = CelestialBody() planet.radius = 2.5 planet.surfaceGravity = 10 planet.bodyName = "New planet" planet.initialVelocity = Vector3.new(0, 0, 0) planet.OnValidate() planet.Awake() local sim = NBodySimulation() sim.Awake() wait(10) while true do sim.FixedUpdate() wait() end