Slope and speed of a projectile

Started by
8 comments, last by mjfara 13 years, 9 months ago
Hello everyone,

I've been making some pretty good progress with my tile based action game.
Just finished a map editor and collision detector.

As of right now, my character can fire a projectile in one direction.

A "bullet" class is created with a travel speed of 10.
The bullet's "x" is simply incremented by the travel speed.
This bullet is then drawn in the main loop.

Because this game is for the iPhone, the fire button is a touch circle.
I would like the direction of the touch to be where the bullet is fired.

I just did a test run to get the slope if I pressed the top right corner of the circle. The slope I got was:
-40
------
38

How can I increment the bullet's x and y with these values at the same speed?
No matter which direction it is going, I want it to have one speed.

Any help is greatly appreciated, thank you.
Advertisement
Hi,

You don't even need the slope to do that. If you have a point on the circle to determine the direction, you can divide it by the radius to obtain a point (vx, vy). Then, you just have to do this:

x += vx * speed;
y += vy * speed;

I don't have more time to explain it better, but I hope it can help you.
Can you clarify on the values you retrieve from the iPhone? If you press top/bottom right/left, what values for x and y you get? Which value should point the bullet upward, and which value should point it horizontally?

If the travel speed is 10, this means the total speed of the bullet I assume;

v = 10 at all times
vx2 + vy2 = v2

This holds for:
vx = v * cos(angle);
vy = v * sin(angle);

Because:
cos2(angle) + sin2(angle) = 1

Thus:
vx2 + vy2 = (v2 * cos2(angle)) + (v2 * sin2(angle) = v2 * (cos2(angle) + sin2(angle)) = v2

With:
angle = tan(y / x)-1 (use http://cplusplus.com/reference/clibrary/cmath/atan2/ if you're using C(++))

double x, y; // get from iPhonedouble angle = atan2(y, x);double bullet_velocity = 10.0;bullet.velocity.x = bullet_velocity * cos(angle);bullet.velocity.y = bullet_velocity * sin(angle);.........while (run){    bullet.position.x = bullet.velocity.x * time_passed;    bullet.position.y = bullet.velocity.y * time_passed;}


EDIT: if you already get the position from a circle, you don't have to calculate the angle, but you can normalize (set the minimal value to 0.0, and the maximal value to 1.0, _all_ values are between 0.0 and 1.0) the x/y values and use them directly instead of the cos/sin.
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
You don't want to use slopes for this. Instead, you just need some basic vector math.

First you'll need a basic 2-d vector struct/class/whatever with x and y member variables, and with support for basic arithmetical operations such as addition and subtraction.

Your code might then look something like this (pseudocode, untested):
// When the projectile is fired:projectile.direction = mouse_position - object_position;projectile.direction.normalize(); // Look up 'vector normalization'// To move the projectile:projectile.position += projectile.direction * projectile.speed * time_step;
(I'm assuming here that you can use floating-point variables for the simulation and then convert to integers only when needed.)
Thanks for the response guys!

Faelenor,
I don't quite understand =(

====================

Decrius,
I knew I should have paid more attention in math class!
Your solution looks like it will work, I haven't tried it yet, but am going to.
Here's the clarification you asked for:

In the bottom right corner of the screen I have a touch box.
(It's actually a square, but the image is a circle, dont think it matters)
Anyway,
It is not relative to the box, but relative to the screen
These are in pixels (100x100)

X starts at 380, half way is 430, and it ends at 480
Y starts at 220, half way is 270, and it ends at 320

220
--------------
|^ |
|| |
380|y <--x--> |480
|| |
|v |
--------------
320


Lets say I hit a perfect horizontal shot(right).

The y from the touch would be 270 (midway on y)
The x would be anywhere from 380 to 480
The bullet would then increment like so:
x += 10;
y += 0;


Lets say I hit a perfect diagonal shot (top right).

The x from the touch would be 480
The y would be 220
The bullet would then increment like so:
x += 10;
y += 10;

Also any touch along the same slope would reproduce the same result
So even if:
x was 455 && y was 245
It would still increment the same

Sorry if this is confusing, I'm not the neatest programmer.
^_^

====================

jyk,

What kind of data would "direction" hold?
An x and y of the point?
Decrius,

"EDIT: if you already get the position from a circle, you don't have to calculate the angle, but you can normalize (set the minimal value to 0.0, and the maximal value to 1.0, _all_ values are between 0.0 and 1.0) the x/y values and use them directly instead of the cos/sin."

Ok I think I get it, but I dont think it will work.

I normalize my x input to
-1, 0, 1
instead of 380,430,480

and y to
-1, 0, 1
instead of 220,270,320

Then I multiply the value pressed by the speed.

So lets say x = 1 and y = 0
Multiply by the speed(10) and you get 10.

But what if x = 0.5 and y = 0
Wouldn't it travel at 5?
Quote:What kind of data would "direction" hold?
An x value and a y value, as you said. In C++, for example, a simple 2-d vector struct might look like this:
struct Vector2{    float x;    float y;};
Quote:Original post by mjfara
But what if x = 0.5 and y = 0
Wouldn't it travel at 5?


Yes, that's why you want to normalize the touch point. (0.5, 0) will be normalized to (1.0, 0.0), so you'll end up with a speed of 10. If the point is, say, (0.5, 0.5), it will be normalized to (0.707, 0.707) and the speed will still be 10: sqrt(0.707^2 + 0.707^2) * 10 = 10. If you normalize the touch point, it will always have a length of 1.0 and you'll be sure to always have the same speed.

Actually, what I said in the first message I posted was the same as Decrius, because the coordinates of a point on a unit circle are defined by the cos and sin of the angle. That's why you better used them instead of a slope, because with a slope, you get a singularity when the speed is only in y (10 / 0 = infinity).

So, what you want is just to normalize the touch point and used it to compute your speed in x and y.
That's quite simple to do... And interesting.

A vector can be defined as:
struct Vector{    float x, y;}


We want to keep (430, 270) as the origin, so simply subtract 430 and 270 from the coordinates of the point which you touch.
We want the vector's tail to be our origin, which we define as (430, 270)
So:
Vector direction;void Touch(float x, float y){    direction.x = x - 430;    direction.y = y - 270;}


Next we turn it into a unit vector, this way when we multiply the unit vector with the speed, we get a vector with that speed in the direction of the vector.
so:
A^ = A/|A|
void Unit(){    float x, y;    x = direction.x;    y = direction.y;    direction.x = x/sqrt(direction.x*direction.x + direction.y*direction.y);    direction.y = y/sqrt(direction.x*direction.x + direction.y*direction.y);}


Now let's turn it into speed:
Scalar(x) * Vector = Vector in the same direction with x times the magnitude.
float ModOfSpeed;Vector speed;speed.x = direction.x * ModOfSpeed;speed.y = direction.y * ModOfSpeed;


There you go.
Wow!
Thank you for all the informative posts, I finally got it working!
And best of all I finally understand how it works.
Much appreciated, I'm grateful for all your help.
It won't be long before I'm back with another question so be prepared :D

This topic is closed to new replies.

Advertisement