-
March 27th, 2012, 12:20 PM
#1
Still Some Trouble Creating Gravity
Hi, I've been having trouble working on this physics engine of mine. Right now I'm having trouble adding gravity.
The game is a spaceship--which you control--flying around in space with asteroids and eventually the ability to shoot bullets. There should be a wrap on the edges of the screen and gravity for each object depending on their mass.
I'm creating a forceX and forceY for each force put onto each object, and then computing that force into a velX and velY which will determine the direction of each object and at which speed.
Where my problem arises:
Code:
//add gravity pulls to forces
for(int i = 0; i <= pushCount; i++) //add gravity pulls for each object
{
for(int u = 0 ; u <= pushCount; u++) //each object should add a force for every other object
{
if(i != u)
{
switch(id[i])
{
case ASTEROID_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = ASTEROID_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case SPACESHIP_ID: //m1 = ASTEROID_MASS, m2 = SPACESHIP_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * SPACESHIP_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = ASTEROID_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
case SPACESHIP_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = SPACESHIP_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * SPACESHIP_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = SPACESHIP_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * SPACESHIP_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
case BULLET_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = BULLET_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case SPACESHIP_ID: //m1 = BULLET_MASS, m2 = SPACESHIP_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * SPACESHIP_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = BULLET_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
}
tempAngle = atan2( ( (x[i]-x[u]) / tempForce ), ( (y[i]-y[u]) / tempForce ) );
if( (tempAngle * 180 / PI) > 0 && 90 > (tempAngle * 180 / PI) ) //sin +, cos +
{
forceX[i] += cos(tempAngle);
forceY[i] += sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 90 && 180 > (tempAngle * 180 / PI) ) //sin +, cos -
{
forceX[i] += -cos(tempAngle);
forceY[i] += sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 180 && 270 > (tempAngle * 180 / PI) ) //sin -, cos -
{
forceX[i] += -cos(tempAngle);
forceY[i] += -sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 270 && 360 > (tempAngle * 180 / PI) ) //sin -, cos +
{
forceX[i] += cos(tempAngle);
forceY[i] += -sin(tempAngle);
}
}
}
}
And then my entire engine.cpp code, if necessary:
Code:
#include <vector>
#include <string>
#include <math.h>
#include <valarray>
#include "constants.h"
using namespace std;
void crunchCommand(string command, int pushCount, vector<int> id, vector<float> & x, vector<float> & y, vector<int> & angle, vector<float> & velX, vector<float> & velY, vector<float> & forceX, vector<float> & forceY)
{
float
tempForce,
tempAngle,
ratio;
if(command == "right")
{
if(angle.front() + 1 <= 71) //if a turn right doesn't overflow the 72 limit, turn right one.
angle.front() = angle.front() + 1;
else //else it does overflow, so wrap back to the first angle.
angle.front() = 0;
}
else
if(command == "left")
{
if(angle.front() - 1 >= 0) //if a turn left doesn't go below 0 (the first angle), turn left one.
angle.front() = angle.front() - 1;
else //else it does go below 1, so wrap back to the last angle (72)
angle.front() = 71;
}
else
if(command == "space")
{
//shoot a bullet.. pause for now
velX[0] = 0;
velY[0] = 0;
forceX[0] = 0;
forceY[0] = 0;
}
else
if(command == "up")
{
if(angle[0] == 0)
forceY[0] = -1;
else
if(angle[0] == 36)
forceY[0] = 1;
else
if(angle[0] == 18)
forceX[0] = 1;
else
if(angle[0] == 54)
forceX[0] = -1;
else
{
forceX[0] = sin(angle[0] * 5 * (PI / 180)); //force of 1 per tick
forceY[0] = -cos(angle[0] * 5 * (PI / 180)); //force of 1 per tick.. negative cosine to account for the reversed y-axis
}
}
//add gravity pulls to forces
for(int i = 0; i <= pushCount; i++) //add gravity pulls for each object
{
for(int u = 0 ; u <= pushCount; u++) //each object should add a force for every other object
{
if(i != u)
{
switch(id[i])
{
case ASTEROID_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = ASTEROID_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case SPACESHIP_ID: //m1 = ASTEROID_MASS, m2 = SPACESHIP_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * SPACESHIP_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = ASTEROID_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
case SPACESHIP_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = SPACESHIP_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * SPACESHIP_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = SPACESHIP_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * SPACESHIP_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
case BULLET_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = BULLET_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case SPACESHIP_ID: //m1 = BULLET_MASS, m2 = SPACESHIP_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * SPACESHIP_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = BULLET_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
}
tempAngle = atan2( ( (x[i]-x[u]) / tempForce ), ( (y[i]-y[u]) / tempForce ) );
if( (tempAngle * 180 / PI) > 0 && 90 > (tempAngle * 180 / PI) ) //sin +, cos +
{
forceX[i] += cos(tempAngle);
forceY[i] += sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 90 && 180 > (tempAngle * 180 / PI) ) //sin +, cos -
{
forceX[i] += -cos(tempAngle);
forceY[i] += sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 180 && 270 > (tempAngle * 180 / PI) ) //sin -, cos -
{
forceX[i] += -cos(tempAngle);
forceY[i] += -sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 270 && 360 > (tempAngle * 180 / PI) ) //sin -, cos +
{
forceX[i] += cos(tempAngle);
forceY[i] += -sin(tempAngle);
}
}
}
}
//compute force to velocity
velX[0] += (forceX[0] / SPACESHIP_MASS) * ACCEL; //scaler of ACCEL .. makes objects obtain force slower
velY[0] += (forceY[0] / SPACESHIP_MASS) * ACCEL; //scaler of ACCEL
for(int i = 1; i <= pushCount; i++)
{
velX[i] += (forceX[i] / ASTEROID_MASS);
velY[i] += (forceY[i] / ASTEROID_MASS);
}
//limit the speed of every object pushed into the game. (will need to make special case for bullets)
for(int i = 0; i <= pushCount; i++)
{
if(sqrt(velX[i]*velX[i] + velY[i]*velY[i]) > MAX_VELOCITY)
{
ratio = MAX_VELOCITY / sqrt(velX[i]*velX[i] + velY[i]*velY[i]);
velX[i] = velX[i] * ratio;
velY[i] = velY[i] * ratio;
}
}
//change position of x and y
for(int i = 0; i <= pushCount; i++)
{
if((x[i] + velX[i]) > SCREEN_WIDTH) //if x gets bigger than maxX, wrap
x[i] = velX[i] - SCREEN_WIDTH - x[i];
else
if(x[i] + velX[i] < 0)
x[i] = SCREEN_WIDTH + velX[i] + x[i]; //if x gets smaller than minX, wrap
else
x[i] += velX[i];
if((y[i] + velY[i]) > SCREEN_HEIGHT) //if y gets bigger than maxY, wrap
y[i] = velY[i] - SCREEN_HEIGHT - y[i];
else
if(y[i] + velY[i] < 0)
y[i] = SCREEN_HEIGHT + velY[i] + y[i]; //if y gets smaller than minY, wrap
else
y[i] += velY[i];
}
}
Any help would be very much appreciated. This has cost me countless hours of headache, and is due Wednesday (extended from Monday).
-
March 27th, 2012, 12:47 PM
#2
Re: Still Some Trouble Creating Gravity
-
March 27th, 2012, 02:22 PM
#3
Re: Still Some Trouble Creating Gravity
Hello again!
Firstly, a tip on making your code neater (I do like neat code ). You have a lot of code duplication in this switch statement:
Code:
switch(id[i])
{
case ASTEROID_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = ASTEROID_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case SPACESHIP_ID: //m1 = ASTEROID_MASS, m2 = SPACESHIP_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * SPACESHIP_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = ASTEROID_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * ASTEROID_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
case SPACESHIP_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = SPACESHIP_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * SPACESHIP_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = SPACESHIP_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * SPACESHIP_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
case BULLET_ID:
switch(id[u])
{
case ASTEROID_ID: //m1 = BULLET_MASS, m2 = ASTEROID_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case SPACESHIP_ID: //m1 = BULLET_MASS, m2 = SPACESHIP_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * SPACESHIP_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
case BULLET_ID: //m1 = BULLET_MASS, m2 = BULLET_MASS
tempForce = ( (GRAV_CONST * BULLET_MASS * BULLET_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
break;
}
break;
}
The end cases in this double switch all have the same form, the only difference between them being the two masses used in the calculation.
Now, if you liked that bit of refactoring I suggested on your other thread (http://forums.codeguru.com/showthrea...40#post2061740) then you'll love this bit!
Write a simple helper function, called e.g. "mass", which returns the appropriate mass for a given object id (i.e. ASTEROID_ID/SPACESHIP_ID/BULLET_ID) by switching on the object id. Then you can replace all the above switch statement with one line of code. Pretty neat eh?
Now, for the bit which is causing problems:
Code:
tempAngle = atan2( ( (x[i]-x[u]) / tempForce ), ( (y[i]-y[u]) / tempForce ) );
if( (tempAngle * 180 / PI) > 0 && 90 > (tempAngle * 180 / PI) ) //sin +, cos +
{
forceX[i] += cos(tempAngle);
forceY[i] += sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 90 && 180 > (tempAngle * 180 / PI) ) //sin +, cos -
{
forceX[i] += -cos(tempAngle);
forceY[i] += sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 180 && 270 > (tempAngle * 180 / PI) ) //sin -, cos -
{
forceX[i] += -cos(tempAngle);
forceY[i] += -sin(tempAngle);
}
else
if( (tempAngle * 180 / PI) > 270 && 360 > (tempAngle * 180 / PI) ) //sin -, cos +
{
forceX[i] += cos(tempAngle);
forceY[i] += -sin(tempAngle);
}
You are overcomplicating things here. The equation for the gravitational attraction between two masses (in vector form) is:
F_12 = -G*M1*M2/R^2 * V
where F_12 is the force applied on object 2 due to object 1,
G is the gravitational constant
M1/M2 are the masses
R^2 is the square of the distance between them
and V is a unit vector from object 1 to object 2.
You have already calculated the first part (G*M1*M2/R^2). So all you need is to calculate the unit vector. You get this by normalising the vector between the two objects, i.e. normalise the vector ( (x[i]-x[u]), (y[i]-y[u]) ). No need to mess around with angles at all
-
March 27th, 2012, 06:21 PM
#4
Re: Still Some Trouble Creating Gravity
I'm glad it's Peter_B here to save the day yet again.
As for the complicated switch.. I know it's horrible x.x
I was really trying to get things working correctly before going to clean up (for some reason--making it hard on myself).
I planned on creating classes and doing simply class.mass()
But I might do a quick implementation of a function call to simplify things for me for now!
As for the next part, I'm not sure how to multiply the G*M1*M2/R^2 by vector V.
I did a quick Google to find that normalizing is simply dividing each of the components by the length--so dividing each one by r would do it I believe, or would it be dividing by tempForce?
I think it would be r, as you said the distance from object 1 to object 2.
But how would I go about multiplying by the vector? Sorry for the utter ignorance on the subject of vectors, but thanks so much for your help again!
Also, did you mean to put the - in front of the equation G*M1*M2/R^2 * V ? It's meant to be negative?
Last edited by Filthy_Utter; March 27th, 2012 at 06:51 PM.
Reason: Forgot one thing
-
March 27th, 2012, 06:57 PM
#5
Re: Still Some Trouble Creating Gravity
Wait, so would I simply be able to say:
forceX = (-G*M1*M2/R^2) / (y2-y1)
and
forceY = (-G*M1*M2/R^2) / (x2-x1)
?
-
March 28th, 2012, 04:04 AM
#6
Re: Still Some Trouble Creating Gravity
Originally Posted by Filthy_Utter
I'm glad it's Peter_B here to save the day yet again.
As for the complicated switch.. I know it's horrible x.x
I was really trying to get things working correctly before going to clean up (for some reason--making it hard on myself).
I planned on creating classes and doing simply class.mass()
But I might do a quick implementation of a function call to simplify things for me for now!
Adding classes would definitely be a good idea. I didn't suggest that as I wasn't sure whether you had been taught them yet. It is best to add them sooner rather than later, as they help keep the code simple.
Originally Posted by Filthy_Utter
As for the next part, I'm not sure how to multiply the G*M1*M2/R^2 by vector V.
I did a quick Google to find that normalizing is simply dividing each of the components by the length--so dividing each one by r would do it I believe, or would it be dividing by tempForce?
I think it would be r, as you said the distance from object 1 to object 2.
But how would I go about multiplying by the vector? Sorry for the utter ignorance on the subject of vectors, but thanks so much for your help again!
You are correct about normalizing a vector - you divide each component by the length, which in this case is R.
To multiply a scalar (i.e. a plain number) by a vector you just multiply each component of the vector by the scalar in turn. So e.g.
Originally Posted by Filthy_Utter
Also, did you mean to put the - in front of the equation G*M1*M2/R^2 * V ? It's meant to be negative?
Don't worry about the minus sign - that way is just the conventional way of writing it. If you reverse the direction of the vector V the minus sign disappears.
I've just noticed an error in the gravity calculation, by the way. In this line:
Code:
tempForce = ( (GRAV_CONST * ASTEROID_MASS * ASTEROID_MASS) / ( (float)sqrt( (x[i]-x[u])*(x[i]-x[u]) + (y[i]-y[u])*(y[i]-y[u]) ) ) );
you are dividing by the distance rather than the square of the distance
Originally Posted by Filthy_Utter
Wait, so would I simply be able to say:
forceX = (-G*M1*M2/R^2) / (y2-y1)
and
forceY = (-G*M1*M2/R^2) / (x2-x1)
?
Not quite. If you had y1=y2 or x1=x2 these would give infinite forces
The X component of the force will be (G*M1*M2/R^2) * X component of normalised V.
Then the X component of normalised V will be (x2-x1)/R. Or maybe (x1-x2)/R, depending upon which objects force you are calculating - if things start repelling each other instead of attracting, just change the sign.
-
March 28th, 2012, 12:58 PM
#7
Re: Still Some Trouble Creating Gravity
I don't know how to thank you enough. Thank you so much
My program is working correctly now. I have to make a video of it, so I'll go ahead and post it later so you can see!
You have saved me!
-
March 28th, 2012, 04:34 PM
#8
Re: Still Some Trouble Creating Gravity
Originally Posted by Filthy_Utter
My program is working correctly now. I have to make a video of it, so I'll go ahead and post it later so you can see!
Excellent - I'd like to see it working. Asteroids in the arcades used to be one of my favourites
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|