Sign in to follow this  
Echilon

Untitled

Recommended Posts

Echilon    122
I have two bodies and I'm trying to calculate gravity between them. This is for a game, and there are actually three bodies currently. Each frame, I check the distance each one moves due to gravity and store it in a cache (to simulate gravity acting on all objects simultaneously), then apply each vector to the body. This is the code I have:
public void calculateGravity(GravitationalBody planet) {
	if(isFixed || gravityIndex.contains(planet.hashCode()) || planet.getGravityIndex().contains(this.hashCode())) {
	    return;
	}
	double radiusGravity = this.getCenter().distance(planet.getCenter());
	double force = (Constants.G * this.mass * planet.mass)/(radiusGravity*radiusGravity); // F=GMm/r^2
	double frameRateMs = (Constants.FrameRate/1000.0);
	double gravityAngle = Math.atan2(Math.max(location.y,planet.location.y) - Math.min(location.y,planet.location.y),
	                                 Math.max(location.x,planet.location.x) - Math.min(location.x,planet.location.x)) + (Math.PI/2);
	double gravityDistance = ((force*frameRateMs)/this.mass)*Constants.SpriteGravityMultiplier;
	if(gravityAngle < 0){ // keep angle positive
	    gravityAngle += MaxAngle;
	}
	//        System.out.println("--"+name+"<->"+planet.getName()+"-"+gravityDistance+"px @ "+Math.round(gravityAngle)+"rad");
	if(planet.IsFixed()) { // gravity acts only on this body, pulling it towards the planet
	    gravityCache.add(new Vector2D(gravityAngle, gravityDistance));
	    gravityIndex.add(planet.hashCode());
	} else { // gravity acts on both, pulling them toward each other
	    double resultantGravAngle = (gravityAngle/2),
	           resultantGravDistance = (gravityDistance /2);
	    gravityCache.add(new Vector2D(resultantGravAngle, resultantGravDistance));
	    gravityIndex.add(planet.hashCode());
	    planet.getGravityCache().add(new Vector2D(resultantGravAngle, resultantGravDistance));
	    planet.getGravityIndex().add(planet.hashCode());
	}
}
Assuming Constants.Framerate = 30, Constants.G = 6.667, Constants.SpriteGravityMultiplier = 1e1
The angles are off though, and I'm convinced it has something to do with the coordinate system Java uses for drawing but I can't get it to work properly. I'm pulling my hair out with this problem, is there anything obvious I've been overlooking?

Share this post


Link to post
Share on other sites
h4tt3n    1974
Hi Echilon,

I'd drop the atan2 method and use vector math instead, since you don't need to know the explicit angle value. Remember that the normalized distance vector implicitly tells you the angle:

Normalized distance.x = (planet1.location.x - planet2.location.x) / distance = cos(angle)
Normalized Distance.y = (planet1.location.y - planet2.location.y) / distance = sin(angle)

In order to get the appropriate force vector to move the bodies around, simply multiply the scalar gravitational force value (which you've got right) with the normalized distance vector.

Hope this helps.

Cheers,
Mike

Share this post


Link to post
Share on other sites
Echilon    122
Thanks, but I don't follow. At the moment I apply the vectors in another method using the angle. If I don't need the angle, why is it in your calculation?

Share this post


Link to post
Share on other sites
h4tt3n    1974
You don't need the *explicit* angle, ie. the actual angle value in degrees or radians. All you need is sine and cosine to the angle, which can be easily found using vector math. Actually, in 2d finding sine and cosine to the angle between two points is the same thing as finding the normalised distance vector.

Here are two very simple commented 2d code samples illustrating my point. I don't blame you if you won't run the .exe files, but at least take a look at the source, which is written in an easily understandable basic dialect (FreeBasic). Both files are about 150 - 200 lines and with plenty of comments.

http://www.jernmager.dk/stuff/gravity_code_examples.zip

Cheers,
Mike

[Edited by - h4tt3n on December 17, 2008 12:49:52 PM]

Share this post


Link to post
Share on other sites
h4tt3n    1974
Well, no matter what I strongly suggest you use vector math to retrieve force directions and save the angle based stuff for whatever you need that for.

Trying a different approach... I'm quite sure that at least one error hides here:
Quote:

double gravityAngle = Math.atan2(Math.max(location.y,planet.location.y) - Math.min(location.y,planet.location.y), Math.max(location.x,planet.location.x) - Math.min(location.x,planet.location.x)) + (Math.PI/2);

atan2 takes sine and cosine of the angle as arguments. I think it would work if you did:
Quote:

double gravityAngle = Math.atan2((location.y - planet.location.y)/radiusGravity, (location.x - planet.location.x)/radiusGravity));

But you're still walking over the bridge to get water here - atan2 is a cpu expensive function and you don't need it in this context. And why do you halve the distance and angle when two bodies are interacting?
Quote:

double resultantGravAngle = (gravityAngle/2),
resultantGravDistance = (gravityDistance /2);

cheers,
Mike

Share this post


Link to post
Share on other sites
Echilon    122
Ok I've simplified the source a bit, but left some comments in. If you want to take a look at what's happening, I've uploaded the game to http://mi6.nu/ml.zip and the two methods are at http://pastebin.com/m5e53fe34. Maybe you'll see something when you see it in action.

Thanks again. :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this