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?