Gravity
by Daniel Waterworth · in Torque Game Builder · 11/26/2006 (4:11 am) · 10 replies
In this game I'm making, there are planets and spaceships. I want to add gravity to the planets without using triggers or blank scene objects on either the planets of the spaceships, because I want every planet to have an affect on every spaceship. I want the each planet to hav less of an affect on each spaceship as it gets further away (which I know is easy, its jus pythag.). Is there a way of doing this without slowing the performance of the game down 2 much. ie I can imagine using 2 while loops, one inside the other for every cycle would be processor intensive.
Any help would be much appreciated.
Dan
Any help would be much appreciated.
Dan
#2
Dan
11/27/2006 (6:39 am)
Thanks, I probably never would hav thought of that. I'll try to put that into my game asap and tell u if it works.Dan
#3
Also in the same thread Thomas posted a way to do it script side using a trigger.
www.garagegames.com/mg/forums/result.thread.php?qt=28261
11/27/2006 (8:52 am)
If you don't mind getting your hands a little dirty, Melv implemented something similar but engine side. If you're interested I'll have a dig through my emails and see if I can find it.Also in the same thread Thomas posted a way to do it script side using a trigger.
www.garagegames.com/mg/forums/result.thread.php?qt=28261
#4
Dan
11/28/2006 (1:23 am)
Unfortunately I dont hav the source code for TGB and so the only way I could do it is through scripting, and as I said above, I dont want to use triggers because I want the force to affect all the objects and not jus ones inside a zoned area. but thanks anyway.Dan
#5
11/28/2006 (8:16 am)
The bottom line is you'll have to start out with doing N-squared calculations at first. Once you get that working you can start to think about optimizations if you have problems, but if your goal is to have every planet "realistically" affect every object, you need an N-squared algorithm. Whatever your tick rate is going to be, every frame, every 30ms, etc. you'll have to just add up the forces on every object. Build a nested for loop with spaceships in the outer loop and planets in the inner loop. The inner loop will get the vector from planet to spaceship, perform some calculation to invert its scale (because longer vectors should result in less force) and add it together with the next iteration of the loop. When you're done, you'll be left with a vector that represents the aggregate force on the ship.
#6
12/01/2006 (2:14 pm)
I'm actually a little curious about this as well. I'm a bit rusty on my physics, but has anyone written some script to simulate planetary gravity, such that a ship could use its gravity to swing around the planet and gain speed, ala some space probes do? I think 'Star Control Melee' did this.... any ideas?
#7
function ship::setgravity(%this)
{
%num = $planets.getcount();
while(%i<%num)
{
%obj = $planets.getobject(%i);
%force = 5000/t2dVectorDistance(%obj.getposition(), %this.getposition());
%angle = mAtan(%obj.getpositiony()-%this.getpositiony(),%obj.getpositionx()-%this.getpositionx());
%i = %i + 1;
%x = %x + mcos(%angle) * %force;
%y = %y + msin(%angle) * %force;
}
%this.setconstantforce(%x, %y);
}
function gravity()
{
if($ships.getcount()>0)
{
if($i>=$ship.maxcount)
{
$i = 0;
}
else
{
if($i<$ships.getcount())
{
%obj = $ships.getobject($i);
%obj.setgravity();
}
$i = $i + 1;
}
}
schedule(1, 0, gravity);
}
If anyone needs any of it explaining, jus ask and equally, if u can find any way to optimize it, however small, I'd love to hear from u.
Dan
12/07/2006 (1:03 pm)
I'v started and finished the code for gravity today. if anyones interested I used the following:-function ship::setgravity(%this)
{
%num = $planets.getcount();
while(%i<%num)
{
%obj = $planets.getobject(%i);
%force = 5000/t2dVectorDistance(%obj.getposition(), %this.getposition());
%angle = mAtan(%obj.getpositiony()-%this.getpositiony(),%obj.getpositionx()-%this.getpositionx());
%i = %i + 1;
%x = %x + mcos(%angle) * %force;
%y = %y + msin(%angle) * %force;
}
%this.setconstantforce(%x, %y);
}
function gravity()
{
if($ships.getcount()>0)
{
if($i>=$ship.maxcount)
{
$i = 0;
}
else
{
if($i<$ships.getcount())
{
%obj = $ships.getobject($i);
%obj.setgravity();
}
$i = $i + 1;
}
}
schedule(1, 0, gravity);
}
If anyone needs any of it explaining, jus ask and equally, if u can find any way to optimize it, however small, I'd love to hear from u.
Dan
#8
I have tried out this code unsuccesfully... would you be able to comment it? Thanks!
01/31/2007 (8:11 am)
Hi Daniel, I have tried out this code unsuccesfully... would you be able to comment it? Thanks!
#9
function ship::setgravity(%this)
{
%shipPos = %this.getposition();
%totalForce = "0 0";
%num = $planets.getcount();
for (%i = 0; %i < %num; %i++)
{
%diff = t2dVectorSub($planets.getobject(%i).getposition(), %shipPos);
%diffMag = t2dVectorLength(%diff);
%force = t2dVectorScale(%diff, 5000 / (%diffMag * %diffMag));
/* the line above is a simplification from
%forceMag = 5000 / %diffMag;
%diff = t2dVectorNormalise(%diff);
%force = t2dVectorScale(%diff, %forceMag);*/
%totalForce = t2dVectorAdd(%totalForce, %force);
}
%this.setconstantforce(getWord(%totalForce, 0), getWord(%totalForce, 1));
}
01/31/2007 (6:26 pm)
I haven't been following this thread too closely, but I guess you can get rid of the trigonometry functions to gain an extra boost. The code would look something like this, I haven't actually tested it so it might be wrong, but I'm sure you get the idea.function ship::setgravity(%this)
{
%shipPos = %this.getposition();
%totalForce = "0 0";
%num = $planets.getcount();
for (%i = 0; %i < %num; %i++)
{
%diff = t2dVectorSub($planets.getobject(%i).getposition(), %shipPos);
%diffMag = t2dVectorLength(%diff);
%force = t2dVectorScale(%diff, 5000 / (%diffMag * %diffMag));
/* the line above is a simplification from
%forceMag = 5000 / %diffMag;
%diff = t2dVectorNormalise(%diff);
%force = t2dVectorScale(%diff, %forceMag);*/
%totalForce = t2dVectorAdd(%totalForce, %force);
}
%this.setconstantforce(getWord(%totalForce, 0), getWord(%totalForce, 1));
}
#10
%diff = t2dVectorSub($planets.getobject(%i).getposition(), %shipPos);
with...
%obj = $planets.getobject(%i);
%diff = t2dVectorSub(%obj.getposition(), %shipPos);
and for some reason the gravity isn't as strong so I replaced...
%force = t2dVectorScale(%diff, 5000 / (%diffMag * %diffMag));
with...
%force = t2dVectorScale(%diff, 10000 / (%diffMag * %diffMag));
and then it worked fine. which leaves me with this, plus comments...
02/12/2007 (6:01 am)
I'v replaced the old trigonometry code with the your new code and it seems to work, except I replaced...%diff = t2dVectorSub($planets.getobject(%i).getposition(), %shipPos);
with...
%obj = $planets.getobject(%i);
%diff = t2dVectorSub(%obj.getposition(), %shipPos);
and for some reason the gravity isn't as strong so I replaced...
%force = t2dVectorScale(%diff, 5000 / (%diffMag * %diffMag));
with...
%force = t2dVectorScale(%diff, 10000 / (%diffMag * %diffMag));
and then it worked fine. which leaves me with this, plus comments...
function gravity() //function to cause gravity to start (I'v called it in the onlevelloaded callback)
{
if($ships.getcount()>0) //$ships is a simset containing all the ships u want gravity to affect
{
if($i>=$ships.maxcount) //$ships.maxcount is a variable containing the max amount of ships
{
$i = 0; //once the max number of ships has been affected it loops
}
else
{
if($i<$ships.getcount()) //if $ships.getobject($i) exists
{
%obj = $ships.getobject($i);
%obj.setgravity(); //apply gravity to it
}
$i = $i + 1; //next ship
}
}
schedule(1, 0, gravity); //loop. this could be changed to, "$gravity = schedule(1, 0, gravity);"
} //and then "cancel($gravity);" would cause gravity to stop
function ship::setgravity(%this) //this function applies the affect of gravity to a ship once
{
%shipPos = %this.getposition(); //the variable containing the current coordinate of the ship
%totalForce = "0 0"; //the variable that will contain the gravity vector specific to a ship
%num = $planets.getcount(); // $planets is a simset containing all the planet objects
for (%i = 0; %i < %num; %i++) // loop through all the planets
{
%obj = $planets.getobject(%i); // asign planet %i to object %obj
%diff = t2dVectorSub(%obj.getposition(), %shipPos); //create a vector from the ship to the planet
%diffMag = t2dVectorLength(%diff); //get the magnitude of the vector
%force = t2dVectorScale(%diff, 10000 / (%diffMag * %diffMag));
//multiply this vector by 10000 / the magnitude squared
%totalForce = t2dVectorAdd(%totalForce, %force);
//add the forces created by all the planets together
}
%this.setconstantforce(getWord(%totalForce, 0), getWord(%totalForce, 1)); //apply the force
}
Associate Tom Eastman (Eastbeast314)
Then again, it would probably be a good idea to do only, say, a couple of the objects in the set at a time - spread out the calculations over a few frames so that you don't have a noticable hitch when all the gravity checks are done. Might not be need - it would be a nice feature anyhow.
Hope that made some sense ;)