Sign in to follow this  

Projoectile along an angle

Recommended Posts

Hey, i cant help but think this should be really simple, but i havn't seen a trigonometry book in like 3 years and clearly whatever i'm doing isn't right. After that guy posted something about an AI controlled gun turret in a game, and I wanted to take a break from my run/gun project and just try to build something simple to get some physics and collisions practice down, I started my own turret project. At first, I would rotate the matrix of the shot before translation, but this would cause strange effects like appearing far away from the actual origin of the matrix ( which baffled me because the matrix should have been centered, but anyway) so I moved on to trig maths to push it along an angled trajectory instead. Knowing the shot angle, (the angle of the turret that was passed to the Shoot function when the space bar is pressed), i thought i could calculate the Y position of the bullet with this: bullet->Y = (speed_x or, time, tried both) * sin(bullet->shot_angle); and a constant increment for x, because it seems like this would keep extending a right triangle to me unless i'm imagining this wrong. Please refresh my math memory :l

Share this post

Link to post
Share on other sites
If you only want to follow the path of a half sine curve, you can do something like this pseudo code snippet

for(phase = 0; phase < PI; phase += PI/64) {
bullet->x = xStart + (xStart - xEnd)/PI*phase;
bullet->y = yStart + magnitude * sin(phase);

Here the bullet's x co-ordinate advances from xStart up to xEnd, during the bullet's y is starting from yStart, reaching its apex at yStart+magnitude, and falls back to yStart.

(Of course, this simple solution only _follows_ the sine curve. It is not suitable for considering wind, gravity, and other forces.)

EDIT: Forgotten: You have to look-up a suitable xEnd in dependence of the shot angle to use the above method.

[Edited by - haegarr on November 28, 2005 9:36:00 AM]

Share this post

Link to post
Share on other sites
On the other hand, you have to integrate a changing velocity, e.g. so (this is not working code but a hint only):

float speed = 5.0f; // scalar speed value, e.g. miles per second or such
float xVelocity = speed * cos(angle); // initial velocity vector x component
float yVelocity = speed * sin(angle); // initial velocity vector y component
float xPos = xStart; // initial position vector x component
float yPos = yStart; // initial position vector y component
float time = currentTimeInSeconds();
while(not_exploded()) {
float now = currentTimeInSeconds();
float ticks = now - time;
xPos += xVelocity * ticks; // integrate velocity x component
yPos += yVelocity * ticks; // integrate velocity y component
yVelocity += -gravity * ticks; // integrate gravity to velocity y component
time = now; // remember current time for next simulation step

Here the angle must be given to 0 radian if shooting straight horizontal (to the right), and half Pi if shooting straight up.

The above steps does a simple physics by integrating the velocity to yield in the way the bullet goes. It adapts the y velocity by gravity.

Share this post

Link to post
Share on other sites
Start by looking at some Newtonian mechanics.

The most important formula you need is -

x=s + ut + 1/2 at^2

x = Position
s = Start position
u = Initial velocity
a = Initial acceleration
t = Time

We can treat x,s,u and a as vectors, or we can treat them as components (x and y)

So if we were to fire a bullet from our origin with an initial velocity of 10m/s in a vacuum (no resistance) in space (no gravity) we can plug the numbers into the formula. e.g.


So, after one second, the bullet has travelled 10m. After 2 seconds, 20m, etc.

Next step, lets go to two dimensions.

We fire a bullet at 30 degrees (from North say) at 10m/s, again, no gravity or air resistance.

First, work out the initial x and y velocities.

ux=u * cos(a)
uy=u * sin(a)

where u is the initial velocity, ux and uy are our initial velocity components, and a is the angle.

Using our figures from above,
ux=10 * cos(30) = 5.25m/s
uy=10 * sin(30) = 5.25m/s

You can then put these into the simple formula we worked out above.

Share this post

Link to post
Share on other sites
glTranslatef(bullet->X + (cos(bullet->shot_angle) * bullet->t),
bullet->Y + (sin(bullet->shot_angle) * bullet->t), 0);

this is how I applied your suggestion, OldDev, but it still behaves weirdly. (I ommitted the stuff involving acceleration, mind you, because i'm not applying acceleration to these physics for simplicities sake and the outcome would always be 0).

Did i misunderstand it/ apply it incorrectly?

Share this post

Link to post
Share on other sites
The sine and cosine of the shot angle are just _starting conditions_ for the velocity vector of the projectile. After start, the velocity changes due to gravity (and, if liked to be, wind and air resistance and such). Then the angle is something that happened in the past. Your code instead applies it constantly over time as factor to the linear term.

Look at my second post or OldDev's post above: the shot angle is used only once, and since then a time based simulation is done without furthur regarding the angle.

The bullet->X and bullet->Y should show the integrated values (again: see posts above), so that
is all that should be visible by OpenGL.

The simulation loop looks like this:
(1) initialize parameters
(2) compute time duration elapsed since latest run through the loop
(3) compute new position by doing a single integration step of the current velocity by time product
(4) update current velocity by e.g. gravity (and other forces) effect
(5) continue with (2) as long as simulation runs

Share this post

Link to post
Share on other sites
ok, heres what i have:

this is the constructor for Bullet, which sets the initial velocity and starting position, and time.

Bullet(float x, float y, float a){ X = x ; Y = y + 64; life = 500; vx = cos(a); vy = sin(a); timer = GetTickCount(); }

here, like you said, the positions on x and y are incremented by velocity * delta time, so i did that. However, it's still behaving all wrong. My question is why didnt just rotating the matrix before translating work, because the matrix was centered, so it should not have looked weird the way it did. (the way it looks when you rotate something at its corner instead of in its center, though the origin was in it's center)

bullet->delta = GetTickCount();
int t = bullet->delta - bullet->timer;
glBindTexture(GL_TEXTURE_2D, image[4]);

bullet->rotation_angle+=t; <--- just a little effect, doesnt move the matrix or anything that would mess this up

bullet->X += (bullet->vx * t);
bullet->Y += (bullet->vy * t);
glTranslatef(bullet->X, bullet->Y, 0);

glRotatef(bullet->rotation_angle, 0, 0, 1);
glTexCoord2f(0,0); glVertex3f(-16, -16, 0);
glTexCoord2f(1,0); glVertex3f(16, -16, 0);
glTexCoord2f(0,1); glVertex3f(-16, 16, 0);
glTexCoord2f(1,1); glVertex3f(16, 16, 0);

bullet->timer = bullet->delta;

Share this post

Link to post
Share on other sites
_Rendering_ is another thing. Your bullet class tracks itself the state (say position, velocity, and so on) of the bullet without regarding OpenGL. That is principally a good solution.

You first supply the translation, and then the rotation. In OpenGL, the transformation _supplied_ last is _applied_ first. So you do a local rotation, and do a translation on the rotated object. That seems me ok. (However, I don't know the matrix active before the rendering loop.) First try to switch off the rotation, so that the flight curve could be tested alone.

From the code, I expect the bullet rotate constantly (say not aligned to the flight curve) around its center, and it moves on a straight line by the initial angle. The latter is due to the missing correction of the vertical velocity by gravity.

Next source of problem may be the t, and possibly also Bullet::timer and Bullet::delta. At least the former one is an int typed value. Is this suitable for holding the return value of GetTickCount()? And if so, it would not be suitable for driving the animation directly!

If all this don't help, please try to describe what happens in more detail.

Share this post

Link to post
Share on other sites
Well, the bullet is intended to move on a straight line until deletion at the end of it's life cycle, it's not intended to be realistic, so I don't believe there should be a need to implement acceleration/deceleration because the value of velocity shouldn't change, it's linear.

Anyway, bullets will fly in directions which aren't being pointed in. This might have something to do with opengl's peculiar angle system, but even when dealing with normal angles ( like above 0, below 90) the results are unexpected. It seems like often the bullets velocity increases perpendicular to the angle of the turret, but other times just slightly off, and other times in the reverse direction, and still other times, just right. the results are unexpected, and I've done a table of the values that should return from the equation in my graphing calculator, and it looks ok, so i'm at a loss as to whats causing the weirdness.


ok, heres whats really going on (i told it to wait before rotating the turret again when an arrow is pressed).

it basically goes through a sine wave of velocities. at 0, it the bullet travels correctly, at 1, it is like 45 degrees to the left, at 2 it's an additional 45, by the 4th degree, the bullet shoots in the reverse direction of the turret, another and it shoots at 225 degrees, etc etc, until the pattern is complete.

so.. im gettin some coffee i think. --;

Share this post

Link to post
Share on other sites
Maybe a silly question, but you have said "between 0 and 90": Have you converted the angle to radians before overhanding to sin/cos? The fact that the direction is more or less arbitrary lets me think so, since overhanding degrees lets the actual angle rotate 57.3 times faster as expected.

EDIT: glRotate uses degree.

Share this post

Link to post
Share on other sites

you can see it for yourself, I'm really baffled heh. I just read the article about motion in 2D/3D space, which basically boiled down to the same concepts youve been talking about and what I've got down in code.

Share this post

Link to post
Share on other sites
As I've said: You're using degree where radians were appropriate. Look here:

You compute the turret angle by increasing/decreasing Tank::Turret_Angle. This variable is defined in degrees. You correctly overhand this to glRotate inside Tank::Draw().

_But_ you also create new bullets by overhanding the degree value:
bullet.insert(bullet.end(), 1, Bullet(X + 24, Y - 111, Turret_Angle));
Then, in the constructor, you compute
vx = cos(a);
vy = sin(a);
directly from it, so that in fact
vx = cos(Turret_Angle);
vy = sin(Turret_Angle);
stands there.

However, the argument of sin and cos are to be measured in _radians_. So it must be

a *= 3.14159f/180.0f;
vx = cos(a);
vy = sin(a);


Share this post

Link to post
Share on other sites
yep, you're right. but where does it say that those functions use radians? I was reading the header front to back looking for clues, it didn't even say that in a textbook i have ABOUT the standard libraries in the math section.

but the important thing is it works, and that kicks are. next stop.. collisions :<

Share this post

Link to post
Share on other sites
Don't know. I'm using linux, and in such cases I type a "man cos" manual page command in the shell. That says: "The cos() function returns the cosine of x, where x is given in radians."

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