So recently I have been researching and trying to script a planet which revolves around the sun, using the gravity formula: F = G(m1m2)/R2
Everything has been scripted as I thought it should be, however it shows no evidence that it’s orbiting, but rather the planet crashing into it.
I tried numerous google searches with no answers and I tried setting the initial velocity, which I don’t know If I did it right, but I can’t get it to work. So I really appreciate some help.
Update: As this discussion was going, I tried playing around and it all seems to either go linear (due to planets gravitational force) or right in the sun due to low intiialvelocity and no other planets involved.
Now the main problem I’m facing is figuring out how I should set the initial velocity.
Video, Code, Explorer tab below:
Main script:
local universe = require(game.ServerScriptService.Universe)
game:GetService("RunService").Stepped:Connect(function()
for i,Body in pairs(workspace.Objects:GetChildren()) do
local surfaceGravity = Body.SurfaceGravity.Value
local radius = Body.Radius.Value
local mass = surfaceGravity * radius * radius / universe.grav
Body.mass.Value = mass
end
end)
local run = 0
game:GetService("RunService").Stepped:Connect(function()
for i,thisBody in pairs(workspace.Objects:GetChildren()) do
for i,otherBody in pairs(workspace.Objects:GetChildren()) do
if otherBody~=thisBody then
local sqrdist = math.sqrt((otherBody.Position - thisBody.Position).Magnitude)
local forceDir = (otherBody.Position - thisBody.Position)
local NormalizedVector = forceDir.Unit
local force = NormalizedVector * universe.grav *
thisBody.mass.Value * otherBody.mass.Value / sqrdist;
local acceleration = force/thisBody.mass.Value
local currentvelocity = acceleration * universe.dt
if thisBody.Name == "Planet" then --and run==0 then
currentvelocity += thisBody.InitialVelocity.Value
print(currentvelocity)
end
--thisBody.LinearVelocity.VectorVelocity += currentvelocity * constants.dt
thisBody.Position += currentvelocity * universe.dt
end
end
end
run += 1
end)
What’s the planet’s initial velocity? If it’s 0 relative to it’s orbiting body, then yeah it’s going to just fall it. It needs some velocity in the plane perpendicular to the direction to the orbiting body to “miss” the orbiting body.
I started to realize that -1000 is too small to notice since the size of the sun is ten times bigger, so just now I tried setting it to -10000, but instead of orbiting. It slowly goes in a straight line, escaping the orbit completely.
I know that it’s because of this specific code, and all I did was adding the same starting velocity in every loop…
if thisBody.Name == "Planet" then --and run==0 then
currentvelocity += thisBody.InitialVelocity.Value
print(currentvelocity)
end
The main problem is that I don’t know how to set the initialvelocity the right way.
Seems your code might be working. If the initial velocity is high, the object would escape. If it is too low, it would crash.
It you are just having fun, why not try 10 moons at the same time, with different velocity.
If you want to have an orbit that can go on forever, maybe you will be better of with a hinge constraint with motor enabled, although as a gravity simulator that would be cheating.
Just play around with it until you find a stable orbit. Try moving the planet closer (so the “high” initial velocity is closer to an orbital velocity at that distance), or try increasing the gravitational constant, or increase the mass of one or both bodies.
EDIT: Or you could compute the escape velocity and just pick any velocity less than that (but not 0)
Never use division like this, instead create a constant for it.
local UniverseConstant = 1 / universe.grav
for i,Body in pairs(workspace.Objects:GetChildren()) do
local surfaceGravity = Body.SurfaceGravity.Value
local radius = Body.Radius.Value
local mass = surfaceGravity * radius * radius * UniverseConstant
Body.mass.Value = mass
end
Remember that division sucks and you should avoid it.
Second thing is that you are using body movers, you don’t need to.
Instead create your own “objects” aka tables in modules which will represent planets and you will describe their properties in those tables.
Example:
local function createObject()
local object = {}
object.Position = Vector3.new()
object.Radius = 5 --It's Size divided by 2
object.ReferenceInWorkspace = nil
return object
end
--[[Remember that tables don't work like Vector3 or any roblox's special
datatypes since you have not added any metamethods in, so whenever you
change something inside of this table, you don't get them to duplicate.
So when you do something like this:
local tab = {}
local tab2 = tab
tab.a = 5
print(tab.a) -- 5
print(tab2.a) -- 5
You can see that those tables are the same references.
]]--
Instead of calculating sqrdist you could calculate it’s inverse since you are not using it in any other way anyways.
Here’s he formula: InverseSqrdDist = ((otherBody.Position - thisBody.Position).Magnitude)^(-(0.5))
0.5 used in power operator is a squareroot
minus near the power operator creates the inverse
if we combine those two things you get inverse of a square root which is the thing you want.
So instead of dividing by the square root you multiply by it’s inverse making your script much faster.
It’s getting weird now because a couple of results happen when I played around with it:
When lowering the initialvelocity, no matter how far or near it gets, it will always goes straight (due to initialvelocity) then bending its orbit curved to the sun. Thus not even a single orbit was made.
Adding multiple planets like four or ten of them, only goes in a straight line (or slightly bended to the sun as well) because of the surrounding planets
Also it has nothing to do with mass I suppose. Mass is set by script.
Increasing the gravitational constant leaves no effect whatsoever, same result.
I still have the feeling however that the code I had shown above is the problem.
Since I said what I wanted, now I can get to the problem solving. The solution is pretty simple, you calculate the gravity velocity, and then you switch the velocity axis, thank you for the attention.
Example → input x,y,z : output z * orbitspeed,x * orbitspeed,y*orbitspeed.
Or you basically switch the values so the biggest influence is swapped with the smallest once etc…
You basically swap x,y,z values.
It could potential create some funny orbits, but the idea behind this is you know that objects are attracted by the gravity so they collide, so what you do if you want them to orbit around themselves, you swap those axis values, so x is now z, y turns into x, and z becomes x and you get a potential desired orbit velocity.
Here is my script that i used a few months ago to achieve what you’re trying to do:
local G = 2.396 * 10^-10
for _, object1 in pairs(game.Workspace:GetChildren()) do
for _, object2 in pairs(game.Workspace:GetChildren()) do
if object1.ClassName == "Part" and object2.ClassName == "Part" then
if object2.Name == "Sun" then
if object1 == object2 then
continue
end
local distance = (object1.Position - object2.Position).Magnitude
local magnitude = G * object1.Mass * object2.Mass / distance
local line_force = Instance.new("LineForce")
local attachment1 = Instance.new("Attachment")
attachment1.Parent = object1
local attachment2 = Instance.new("Attachment")
attachment2.Parent = object2
line_force.Name = object1.Name.." To "..object2.Name
line_force.ApplyAtCenterOfMass = true
line_force.InverseSquareLaw = true
line_force.ReactionForceEnabled = true
line_force.Magnitude = magnitude * 950000000000
line_force.Attachment0 = attachment1
line_force.Attachment1 = attachment2
line_force.Parent = game.Workspace
local v = math.sqrt(G * object2.Mass / distance) * 60000
object1.AssemblyLinearVelocity = Vector3.new(v, 0, 0)
end
end
end
end
It doesn’t look to me like you’re tracking velocity between steps? That’s pretty critical. That’s why your objects are moving linearly instead of accelerating.
If you give an object velocity, it should constantly maintain that velocity every frame. When a force acts on the object, change the velocity rather than the position.
And when you set the initial velocity, only set it for the first frame.
But it doesn’t look like you maintain velocity between frames. Gravity needs to be added to velocity rather than position, and you need to manually save the previous velocity in a table or Attribute.
It should look like this pseudo-code.
set initial velocity into a table or Attribute
loop or event
get velocity from table or Attribute
add gravity to velocity
add other forces to velocity
add velocity to part position in Workspace
save velocity to a table or Attribute so it can be used next loop
end
Funny, right this instant I’m working on a gravitation game too. I don’t use this method though, I use LineForces. It’s way simpler to let Roblox handle the physics, and it’s also less expensive, more efficient and easier to manage. Just a suggestion.
Too, you should know that earth, the moon, and the sun are EXTREMELY far away from each other. More than we think, so when trying to simulate it, yes it may look more boring, but we will get way better results if you put the objects farther away from each other. The farther away they are, the more stable the orbits are.
Also, you should know about the Three Body Problem.