|
-
March 23rd, 2012, 05:30 PM
#1
Need help with physics for this engine. I will explain in thread.
Thanks for clicking this post, I'll get right down to business.
I'm creating a physics engine for class.
The overall idea is a 2d screen with a spaceship flying around and asteroids.
You can rotate the spaceship and thrust (thrusting gives a force in a certain direction of 1).
I'm having a lot of trouble with the physics.
What I'm doing:
The force is 1 in a certain direction. I'm attempting to compute that force into a force for x and a force for y, which I can later translate into a velocity for each x and y.
I have the game running correctly for what I've done, but I just realized that the spaceship always goes at nearly a 45 degree angle (albeit in the correct general direction). If it's straight up, it goes straight up, same with straight down, left, and right. But if it's inbetween, it goes at a 45 degree angle.
I'll show my code, it's pretty sloppy because I've been trying to throw it all together for days.
Note: This is just the engine.cpp part of the code. Also, the origin of (0,0) is in the top left instead of the bottom left.
Code:
#include <vector>
#include <string>
#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 = 0;
for(int i = 0; i <= pushCount; i++)
{
forceX[i] = 0;
forceY[i] = 0;
}
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 .. currently using this for stopping the ship to help test for bugs
velX[0] = 0;
velY[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)) * 1; //force of 1 per tick
forceY[0] = -cos(angle[0] * 5 * (PI / 180)) * 1; //force of 1 per tick
}
}
/*
//add gravity pulls to forces
for(int i = 0; i <= pushCount; i++) //add gravity pulls for each object
{
for(int u = 1; u <= pushCount; u++) //each object should add a force for every other object
{
switch(id[i])
{
case ASTEROID_ID:
switch(id[u])
{
case ASTEROID_ID:
break;
case SPACESHIP_ID:
break;
}
break;
case SPACESHIP_ID:
switch(id[u])
{
case ASTEROID_ID:
break;
case SPACESHIP_ID:
break;
}
break;
}//id[i]tempForce += GRAV_CONST *
}
}
*/
//compute force to velocity
velX[0] += (forceX[0] / SPACESHIP_MASS) * 0.1;
if(velX[0] > MAX_VELOCITY)
velX[0] = MAX_VELOCITY;
else
if(velX[0] < MIN_VELOCITY)
velX[0] = MIN_VELOCITY;
velY[0] += (forceY[0] / SPACESHIP_MASS) * 0.1;
if(velY[0] > MAX_VELOCITY)
velY[0] = MAX_VELOCITY;
else
if(velY[0] < MIN_VELOCITY)
velY[0] = MIN_VELOCITY;
for(int i = 1; i <= pushCount; i++)
{
velX[i] += (forceX[i] / ASTEROID_MASS) * 0.1;
velY[i] += (forceY[i] / ASTEROID_MASS) * 0.1;
}
//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];
}
}
I know the including of string isn't necessary, I just haven't changed it. I also know a lot of the code is redundant, but I'll clean it once it's working.
Any help will be greatly appreciated. I have almost no hope at this point.
(I do have a general idea on how to get the gravity working for each object, I've just yet to implement it.. I'd rather fix the 45 degree bug first)
-
March 24th, 2012, 03:48 AM
#2
Re: Need help with physics for this engine. I will explain in thread.
there are many things wrong here ... anyway, speaking of the "45 degree bug" it's probably caused by your velocity truncation code: you're truncating the x and y components of the velocity vectors to a positive interval. You should truncate the norm of the velocity vector instead ( take the length l of the vector V, if l is < Vmin ( > Vmax ) then reset V = Vmin*V/l ( = Vmax*V/l ); clearly, you'll need to take special action when l ~= 0 ).
-
March 24th, 2012, 09:03 AM
#3
Re: Need help with physics for this engine. I will explain in thread.
The 45 degree bug looks like it is caused by what superbonzo said, i.e. the velocity normalization is wrong.
So, with that covered, a few more tips .
Why are you using weird units for the angles? Your angle units are such that angle=72 means 360 degrees. Why not just use degrees instead? Everyone knows what these are.
The bit where you update the position:
Code:
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];
}
is wrong. Why are you subtracting x[i] in the bit I've highlighted in red? You should be adding it. The same goes for the y[i] update. You can also optimize this bit by doing the addition first, then checking that it is within the screen bounds after.
Finally, it would be better to not use strings to indicate the command. An enum is much more appropriate for this. It prevents bugs with misspelling, and allows you to 'switch' on the command rather than using a lot of if/else statements. It is also faster, as comparing one enum to another is a lot faster than checking whether two strings are equal.
I would also change the names of the commands if I was doing this, as left, right and up could cause confusion. After all, when you send the 'up' command the ship doesn't go 'up', it thrusts forwards. And the 'left' command doesn't make the ship go left on screen, but turn left.
Maybe call them turnLeft/turnRight/thrust instead? This is entirely up to you, of course...
-
March 24th, 2012, 08:17 PM
#4
Re: Need help with physics for this engine. I will explain in thread.
Thanks Superbonzo. You seem to clearly grasp what I'm doing wrong. However I'm still a little confused.
Actually I'm very confused.
How do I find the length of the vector V?
And what special action will I need to take when the length is 0?
Sorry, I'm really not understanding the physics part of this program. (Which is the main part).
And to Peter, thanks to you both for your replies. My professor built the GUI, and he used 72 angles for displaying the spaceship sprite in 72 different directions. I'm just going along with what he originally coded, so as to avoid confusing myself. (Changing the value would probably conflict with his GUI in some way)
I think the updating position part was correct, however, as it wraps correctly in my program.. Let me see..
If the velocity was 300, and the maxX was 500, and I was at 300 currently, then I would need to do 300 - (500 - 300) or V - (maxX - currX)
I suppose I should put (SCREEN_WIDTH - x[i]) in parens to avoid further confusion.
The part about using strings is also true, and I should've mentioned that my professor wrote the GUI.
I might later delve into changing his variable names as I think we will work on this project in different ways until May.
As I'm going to be stuck dealing with this thing for so long, I'd appreciate any further explanations! Treat me like I didn't take Physics! (since I took it in highschool x.x)
Thanks for everything
-
March 24th, 2012, 08:20 PM
#5
Re: Need help with physics for this engine. I will explain in thread.
Also, this part of the assignment (with gravity built in) is due Monday. o.o
-
March 26th, 2012, 08:55 AM
#6
Re: Need help with physics for this engine. I will explain in thread.
Thanks for the help. I got that part working.
Code:
//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;
}
}
=)
-
March 26th, 2012, 02:08 PM
#7
Re: Need help with physics for this engine. I will explain in thread.
 Originally Posted by Filthy_Utter
And to Peter, thanks to you both for your replies. My professor built the GUI, and he used 72 angles for displaying the spaceship sprite in 72 different directions. I'm just going along with what he originally coded, so as to avoid confusing myself. (Changing the value would probably conflict with his GUI in some way)
...
The part about using strings is also true, and I should've mentioned that my professor wrote the GUI.
Oh well, give him/her a smack from me 
 Originally Posted by Filthy_Utter
I think the updating position part was correct, however, as it wraps correctly in my program.. Let me see..
If the velocity was 300, and the maxX was 500, and I was at 300 currently, then I would need to do 300 - (500 - 300) or V - (maxX - currX)
I suppose I should put (SCREEN_WIDTH - x[i]) in parens to avoid further confusion.
Putting the (SCREEN_WIDTH -x[i]) in parens changes the expression, and is equivalent to my suggestion of changing the "- x[i]" to "+ x[i]" 
A neater way to write this, by the way, is do the addition first then check whether it is out of bounds:
Code:
x[i] += velX[i];
if (x[i] > SCREEN_WIDTH)
x[i] -= SCREEN_WIDTH;
else if (x[i] < 0)
x[i] += SCREEN_WIDTH;
This means you reduce the number of additions needed. You were adding x[i] + velX[i] in the if condition and then again in whichever if branch you end up in. Doing it first means you only do it once.
Remember that for this to work properly, the velocity must be small enough that the 'raw' value of x[i]+velX[i] must not be greater than 2*SCREEN_WIDTH or less than -SCREEN_WIDTH. If it isn't you will need to add or subtract further multiples of SCREEN_WIDTH.
-
March 26th, 2012, 05:53 PM
#8
Re: Need help with physics for this engine. I will explain in thread.
Thanks for another great reply.
As for the neater code: it is much neater--I don't know what else to say.
I will definitely implement it in this manner when I get done with the gravity part. (I will also include more classes later, then I will rename the horribly named variables!)
And I hadn't thought about it reaching more than 2*theWidth, so I will try to think of a way to include that scenario! Thanks!
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
|