- Home /
Objects acting under each other's gravity
I'm trying to create a planet simulation in Unity, so planets are attracted towards each other by gravity. So I'm having to write all the movement myself. Anyway, here is what I have. I'm trying to make them move towards each other based on their mass.
var planet : Transform;
var numberOfPlanets = 10;
var minimumSize = 1;
var maximumSize = 10;
var position = Vector3.zero;
var planets = new Array ();
var masses = new Array ();
var total = Vector3.zero;
var speed = Vector3.zero;
function Start () {
for(i=0; i<numberOfPlanets; i++){
position = Vector3(Random.Range(-15,16), Random.Range(-15,16), Random.Range(-15,16));
var newPlanet = Instantiate (planet, position, Quaternion.identity);
planets.Push(newPlanet);
var scaleAmount = Random.Range (0,6);
newPlanet.localScale += Vector3(scaleAmount, scaleAmount, scaleAmount);
masses.Push(scaleAmount);
}
calculate();
}
function calculate (){
for (k=0;k<numberOfPlanets;k++){
var indiv = planets [k];
for(j=0;j<numberOfPlanets;j++){
var planetRef = planets[j];
total += ((planetRef.position-indiv.position) * masses[j]);
speed = total;
indiv.transform.Translate (speed);
}
}
}
However, they just fly away (more than 1,000,000 units travelled in one frame). So what am I doing wrong?
Basically, your maths are totally out. Look up acceleration under gravity on wikipedia- what you're doing here doesn't look right at all.
Also, look up the 3-body problem for an explanation for why this is extremely difficult to simulate accurately.
These are two brilliant answers. I really don't know which one to mark correct, so I went for Bunny83's as it has fewer votes. But these are incredible, thanks.
Answer by Bunny83 · Dec 19, 2011 at 04:32 PM
moved from the duplicated question
Your calculation doesn't have much in common with gravity. Your speed / acceleration will get smaller when the objects come closer to each other... That doesn't make much sense. You have to divide the mass by the distance squared. You also need to reset your "total" variable for each planet. Also you calculate the acceleration, not the speed so you have to store the current speed of each planet and add the acceleration each frame. Also you should do such calculations in FixedUpdate to be frame rate independent. Ohh and don't forget to scale your acceleration properly. In the real world the gravitational constant is a very very small number (10^-11) but it depends on the mass and distance proportion.
function calculate ()
{
for (k=0;k<numberOfPlanets;k++)
{
var indiv = planets [k];
total = Vector3.zero;
for(j=0;j<numberOfPlanets;j++)
{
var planetRef = planets[j];
var direction = (planetRef.position-indiv.position);
total += (direction.normalized * masses[j]) / direction.sqrMagnitude;
speed[k] += total;
indiv.transform.Translate (speed[k]);
}
}
}
Your custom approach could be done easier with Unity's rigidbody component. It has a velocity and a mass. Just turn off the gravity. Then use this script on each planet:
import System.Collections.Generic;
static var G = 0.01f; // adjust with try & error
static var planets = List.<Rigidbody>(); private var myRigidbody : Rigidbody;
//for testing. Set the z value to give the planet an initial speed along it's z-axis public var initialForwardSpeed : Vector3;
function Awake() { myRigidbody = rigidbody; myRigidbody.velocity = transform.TransformDirection(initialForwardSpeed); }
function OnEnable() { planets.Add(rigidbody); }
function OnDisable() { planets.Remove(rigidbody); }
function FixedUpdate() { var pos = myRigidbody.position; var acc = Vector3.zero; for(var planet in planets) { if (planet == myRigidbody) continue; var direction = (planet.position - pos); acc += G (direction.normalized planet.mass) / direction.sqrMagnitude; } myRigidbody.velocity+= acc * Time.fixedDeltaTime;
}
edit
I tested my script and i had two typos: One Vector3 was written with a small "v" and a comment had only one slash ;)
I've also tested some values. Had 3 planets:
1. Mass: 1000; Pos: 0,0,0; InitialSpeed: 0,0,0; Scale:3
2. Mass: 1; Pos: 4,0,0; InitialSpeed: 0,0,2; Scale:1
3. Mass: 1; Pos: 0,4,0; InitialSpeed: 0,0,1.8; Scale:1
All planets are just spheres. The two smaller spheres move on an elliptical orbit around the big one as expected.
I've found another very confusing fact:
The for-(each)-loop works great with the generic List, but if i use #pragma strict it complains that the planet variable (of type Object) doesn't have a position / or mass. Sure, so i changed it to:
for(var planet : Rigidbody in planets)
but now it complains that he can't cast an Object to a Rigidbody. "planets" is a strongly typed collection but UnityScript seems to ignore the type in for-each-loops
It works if you do it that way:
for(var planet : Rigidbody in planets.ToArray())
But that's not the point of using Lists :D. Does one of the UnityScript user have a good explanation for this?
Nice solution! Ins$$anonymous$$d of calculating forces, you go directly to the point and evaluate the acceleration, accumulating the velocity variation in rigidbody.velocity. Saved a lot of operations: no need to multiply by rigidbody.mass, since acc = force/rigidbody.mass, no need to accumulate forces in a separate variable and no AddForce at all! Very smart!
Really nice answer, upvote. I'm getting some errors using List. (in JS), I seem to remember this stopped working in 3.4 ? Should I just use an array and findGameobjectsWithTag ?
@$$anonymous$$uzz5: Did you miss the import System.Collections.Generic;
line? I don't use UnityScript myself ;) but it should work that way. Generics support has been added to UnityScript long time ago. They wouldn't remove it.
I will test it myself if i have some time ;)
@Bunny83, the browser ate the <Rigidbody> type in the List declaration (it always thinks it's a tag), thus I edited the answer and replaced the left angle bracket by the html equivalent (had to do that in this comment too). Hope this had not changed anything else.
Answer by aldonaletto · Dec 19, 2011 at 12:26 PM
You should use rigidbodies in the planets, and forces to simulate gravity (ironically, you should also set useGravity to false!) For each planet, you should calculate the gravity forces of all other planets and sum them together to get the resulting force, then apply it with AddForce in FixedUpdate - something like this (planet script):
var g = 6.674E−11; // universal gravity constant function FixedUpdate(){ if (planets[i] != transform){ // calculate only other planets gravity! var resForce = Vector3.zero; for (var i = 0; i < planets.length; i++){ var dir = planets[i].position - transform.position; // get the force direction var dist2 = dir.sqrMagnitude; // get the squared distance // calculate the force intensity using Newton's law var gForce = g * rigidbody.mass * planets[i].rigidbody.mass / dist2; resForce += gForce * dir.normalized; // accumulate in the resulting force variable } } rigidbody.AddForce(resForce); // apply the resulting gravity force }NOTE: The gravity constant applies to planet scale distances and masses; maybe you should use a larger value to have a barely noticeable effect in the small distances and masses you will actually use in your planet system. Just to have an idea, earth mass is about 6E24 kg, moon mass is about 7E22, and the distance earth-moon is 3.8E8 m. If you used a distance equal to 38 units in your system, the earth mass should be set to 6E20, or 600000000000000000000! The moon mass, on the other hand, should be only 7E18, or 7000000000000000000. Obviously, these numbers are waaaay too big. You could set earth mass to 600, for instance, and moon mass to 7, which is 1E18 times smaller. Compensate such scale change is a complicated thing to calculate, thus I suggest you to just try a g constant in the range 0.06 to 6 and watch what happens.
Answer by unison · Feb 13, 2012 at 10:07 AM
This is a very interesting and intuitive thread, I have implemented all that was written here to create a small solar system... I have big ideas on what I want specifically in my game but I need help on ways it can be done.
I am a total beginner when it comes to Scripting but am willing to learn it eventually through understanding and experiment in these early stages, I have lots of questions to ask here so I hope that you good people can help me out. I want to incorporate a spaceship into the game so here are my questions, I will start with the simplest;
how do I create both first person and third person spaceship controls that don't interfere with the pull of gravity but incorporate them into the velocity of the ship, and switch between the two (third and first person)modes in game.
how do I create the camera smooth follow control to follow the ship?
I have tried using the packaged scripts but they do not look very realistic in the context I want to use them in and they use the rigid bodies gravity even if it is unchecked!
any help would be much appreciated, I have many more questions but I would like to solve these ones first so I can get an in game view representation of what's going on and how I can improve the feel of the game.
Thanks in advance
Chris :),This is a very interesting and intuitive thread, I have implemented all that was written here to create a small solar system... I have big ideas on what I want specifically in my game but I need help on ways it can be done.
I am a total beginner when it comes to Scripting but am willing to learn it eventually through understanding and experiment in these early stages, I have lots of questions to ask here so I hope that you good people can help me out. I want to incorporate a spaceship into the game so here are my questions, I will start with the simplest;
how do I create both first person and third person spaceship controls that don't interfere with the pull of gravity but incorporate them into the velocity of the ship, and switch between the two (third and first person)modes in game.
how do I create the camera smooth follow control to follow the ship?
I have tried using the packaged scripts but they do not look very realistic in the context I want to use them in and they use the rigid bodies gravity even if it is unchecked!
any help would be much appreciated, I have many more questions but I would like to solve these ones first so I can get an in game view representation of what's going on and how I can improve the feel of the game.
Chris :)
You are willing to learn? That's good, here's a really good page to start with
Answer by kaedmon · Jan 01, 2013 at 12:53 AM
For any developers out there who would like to implement this really easily, try out:
World Physics System ~ http://nimbusgarden.com/worldphysicssystem
The World Physics System is a celestial body & point gravity scripting interface for Unity, intended as a replacement for the stock downward gravity. WPS can be used to simulate planetary orbits, body-body attraction, or "snowballing" effects. You may use it to create spherical worlds "out-of-the-box," but World Physics System is implemented robustly and is lightweight, providing you complete freedom in expressing your point gravitation creativity, complex and repulsive forces, allowing you to use the system as a subcomponent for other effects, such as spells, powerups, or goal-based Artificial Intelligences for NPC's. With the WPS, the sky is truly the limit!
Your answer
Follow this Question
Related Questions
Rigidbody gravity between planets 1 Answer
Unity3D PlanetGravity system? C# 1 Answer
Placing objects help needed 1 Answer
Faux Gravity, spinning at bottom of sphere 0 Answers
I Need help with gravity 1 Answer