Game Development Community

Gravitational Pull - Math done, need help with coding

by Tyler Slabinski · in Torque Game Builder · 07/28/2010 (3:20 am) · 11 replies

For the past 2 or so hours (not counting the minor bugs I ran into when starting), I've been working on a script that gives a gravitational force between a "planet" (object effected by gravity), and a "star" (object emitting the pull). Here is my quick script:

Gravity.cs
function starClass::onLevelLoaded(%this, %scenegraph)
{
	$Star = %this;
}

function planetClass::onLevelLoaded(%this, %scenegraph)
{
	$Planet = %this;
	$Planet.enableUpdateCallBack();
}

function planetClass::onUpdate(%this)
{
	%starX = $Star.getPositionX();
	%starY = $Star.getPositionY();
	%starPos = $Star.getPosition();
	
	%planetX = $Planet.getPositionX();
	%planetY = $Planet.getPositionY();
	%planetPos = $Planet.getPosition();
	
	%distance = t2dVectorDistance(%starPos, %planetPos);
	
	%pastX = $Planet.getLinearVelocityX();
	%pastY = $Planet.getLinearVelocityY();

	%x = (%starX - %planetX) * 1 / (%distance);
	%y = (%starY - %planetY) * 1 / (%distance);
	
	%this.setLinearVelocity(%x + %pastX, %y + %pastY);
}

Now this script works perfectly when there is a single star and a single planet in the level, but what fun would that be? This script completely breaks when you add a second star or planet. It treats all the planets as a single entity, and they can only be effected by one star.

I am not very good at editing the engine source code, so I was wondering if anyone could help me walk through this, since I know it would be crazy having 20+ planets doing all that math at once.

#2
07/28/2010 (5:38 pm)
If you want to use the code you provided, you need to get rid of those globals.
function starClass::onLevelLoaded(%this, %scenegraph)
{
	$Star = %this;
}

function planetClass::onLevelLoaded(%this, %scenegraph)
{
	//$Planet = %this;
	//$Planet.enableUpdateCallBack();
        %this.enableUpdateCallBack();
}

function planetClass::onUpdate(%this)
{
	%starX = $Star.getPositionX();
	%starY = $Star.getPositionY();
	%starPos = $Star.getPosition();
	
	%planetX = %this.getPositionX();
	%planetY = %this.getPositionY();
	%planetPos = %this.getPosition();
	
	%distance = t2dVectorDistance(%starPos, %planetPos);
	
	%pastX = %this.getLinearVelocityX();
	%pastY = %this.getLinearVelocityY();

	%x = (%starX - %planetX) * 1 / (%distance);
	%y = (%starY - %planetY) * 1 / (%distance);
	
	%this.setLinearVelocity(%x + %pastX, %y + %pastY);
}
That should work if you only have one star and many planets.
#3
07/30/2010 (12:08 am)
Okay, I just finished (at least for a prototype) a script that will give an object gravity towards another object:

function starClass::onLevelLoaded(%this, %scenegraph)
{
	$star = %this;
}

//Update a callback every frame for the planet (%this)

function planetClass::onLevelLoaded(%this, %scenegraph)
{
	%this.enableUpdateCallBack();
}

function planetClass::onUpdate(%this)
{
	%pastX = %this.getLinearVelocityX();
	%pastY = %this.getLinearVelocityY();
	
	%distance = t2dVectorDistance($star.getPosition(), %this.getPosition());
	%x = $star.getPositionX() - %this.getPositionX();
	%y = $star.getPositionY() - %this.getPositionY();
	%sum = mAbs(%x) + mAbs(%y);
	
	%powerX = castGravityX(%sum, %x, %distance);
	%powerY = castGravityY(%sum, %y, %distance);
	
	%this.setLinearVelocity(%powerX + %pastX, %powerY + %pastY);
}

function castGravityX(%sum, %x, %distance)
{
	%x = %x / %sum;
	return (%x / %distance) * 300;
}

function castGravityY(%sum, %y, %distance)
{
	%y = %y / %sum;
	return (%y / %distance) * 300;
}

This works using multiple planets, but only one star can be on the scene at a time. I have an idea for adding more stars, but it requires making separate classes and functions for each.

Does anyone know how I could use this on multiple stars?
#4
07/30/2010 (1:56 am)
There's a couple of options I can think of.

I'd *HIGHLY* recommend that you process all of the objects in one loop.

The other option is to make a SimSet of the Stars (instead of using a global variable). Then each planet can iterate over the SimSet of Stars in order to calculate their pull. You can write something like this:

new SimSet(StarList);

function starClass::onLevelLoaded( %this, %scenegraph )
{
  StarList.add( %this );
}

function planetClass::onUpdate( %this )
{
  %cStars = StarList.getCount();
  for( %i = 0; %i < %cStars; %i++ )
  {
    %star = StarList.getObject( %i );
    ... and so on ...
  }
}
#5
07/30/2010 (1:56 am)
P.S. If you do the latter method, don't forget to either clean up the SimSet between levels!
#6
07/30/2010 (2:52 am)
I never should have skipped the chapter of simsets in that old Torque book.

EDIT: It's starting to work now! Thanks for the help. I wish I knew enough of the engine to turn the math into code (instead of script), but I am just working on a prototype right now, so I guess it doesn't matter.

Here is the finished script:

Gravity.cs
new SimSet(StarList);

function starClass::onLevelLoaded(%this, %scenegraph)
{
	StarList.add(%this);
}

//Update a callback every frame for the planet (%this)

function planetClass::onLevelLoaded(%this, %scenegraph)
{
	%this.enableUpdateCallBack();
}

function planetClass::onUpdate(%this)
{
	%cStars = StarList.getCount();
	for( %i = 0; %i < %cStars; %i++ )
	{
		%star = StarList.getObject(%i);
		%pastX = %this.getLinearVelocityX();
		%pastY = %this.getLinearVelocityY();
	
		%distance = t2dVectorDistance(%star.getPosition(), %this.getPosition());
		%x = %star.getPositionX() - %this.getPositionX();
		%y = %star.getPositionY() - %this.getPositionY();
		%sum = mAbs(%x) + mAbs(%y);
	
		%powerX = castGravityX(%sum, %x, %distance);
		%powerY = castGravityY(%sum, %y, %distance);
	
		%this.setLinearVelocity(%powerX + %pastX, %powerY + %pastY);
	}
}

function castGravityX(%sum, %x, %distance)
{
	%x = %x / %sum;
	
	return (%x / %distance) * 300;
}

function castGravityY(%sum, %y, %distance)
{
	%y = %y / %sum;

	return (%y / %distance) * 300;
}
#7
09/09/2010 (3:40 pm)
I' trying implement the above code but get the following console errors:

Error: cannot change namespace parent linkage of Star from t2dStaticSprite to Star.
Error: cannot change namespace parent linkage of planet from t2dStaticSprite to planet.

Please help.
#8
09/09/2010 (3:54 pm)
Ok, I've fixed that error on my own; it had nothing to do with your code was a fragment of an old function that i forgot to completely comment out. Now the console says that it compiled your script. However nothing seems to happen. I assigned the "planet" and star classes each to an object.
#9
09/09/2010 (4:00 pm)
I'm wondering where exactly you put the command to execute the script to get it working.
#10
09/09/2010 (4:09 pm)
Ok, I got it working. But when an object hits the ground it moves back an forth along the ground. Is there a fix for this?
#11
09/09/2010 (7:38 pm)
You are going to need to make some sort of code for friction. I may be able to find time in a few hours to try something, but I am not sure if it will work.