Projoectile along an angle

Started by
12 comments, last by haegarr 18 years, 5 months ago
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
|aaap.penopticon.com| My website, including game projects. Collaboration/comments are welcome, please visit :)
Advertisement
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]
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 suchfloat xVelocity = speed * cos(angle); // initial velocity vector x componentfloat yVelocity = speed * sin(angle); // initial velocity vector y componentfloat xPos = xStart; // initial position vector x componentfloat yPos = yStart; // initial position vector y componentfloat 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.
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.

x=10t

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.
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?
|aaap.penopticon.com| My website, including game projects. Collaboration/comments are welcome, please visit :)
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
glTranslate3f(bullet->X,bullet->Y,0);
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
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]);glPushMatrix();                 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);               bullet->life-=1;       glTranslatef(bullet->X, bullet->Y, 0);        glRotatef(bullet->rotation_angle, 0, 0, 1);          glBegin(GL_TRIANGLE_STRIP);          glColor4f(1,1,1,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);          glEnd();     glPopMatrix();bullet->timer = bullet->delta;
|aaap.penopticon.com| My website, including game projects. Collaboration/comments are welcome, please visit :)
_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.
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.

EDIT:

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. --;
|aaap.penopticon.com| My website, including game projects. Collaboration/comments are welcome, please visit :)
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.

This topic is closed to new replies.

Advertisement