views:

1874

answers:

10

I'm trying to make a triangle (isosceles triangle) to move around the screen and at the same time slightly rotate it when a user presses a directional key (like right or left).

I would like the nose (top point) of the triangle to lead the triangle at all times. (Like that old asteroids game).

My problem is with the maths behind this. At every X time interval, I want the triangle to move in "some direction", I need help finding this direction (x and y increments/decrements).

I can find the center point (Centroid) of the triangle, and I have the top most x an y points, so I have a line vector to work with, but not a clue as to "how" to work with it.

I think it has something to do with the old Sin and Cos methods and the amount (angle) that the triangle has been rotated, but Im a bit rusty on that stuff.

Any help is greatly appreciated.

Thanks.

+5  A: 

The arctangent (inverse tangent) of vy/vx, where vx and vy are the components of your (centroid->tip) vector, gives you the angle the vector is facing.

The classical arctangent gives you an angle normalized to -90° < r < +90° degrees, however, so you have to add or subtract 90 degrees from the result depending on the sign of the result and the sign of vx.

Luckily, your standard library should proive an atan2() function that takes vx and vy seperately as parameters, and returns you an angle between 0° and 360°, or -180° and +180° degrees. It will also deal with the special case where vx=0, which would result in a division by zero if you were not careful.

See http://www.arctangent.net/atan.html or just search for "arctangent".

Edit: I've used degrees in my post for clarity, but Java and many other languages/libraries work in radians where 180° = π.

You can also just add vx and vy to the triangle's points to make it move in the "forward" direction, but make sure that the vector is normalized (vx² + vy² = 1), else the speed will depend on your triangle's size.

aib
So once I have this angle, how can I apply it so that I know how to increment/decrement the x and y values of each point of the triangle?
Mark
Also, that website seems to state that the arctangent is for right triangles only, whereas mine is an isosceles triangle
Mark
You can normalize and use vx and vy (just add them to the x/y coordinates of the points). Note that vx=sin(r) and vy=cos(r), this is just the opposite of the arctan operation.
aib
The right triangle mentioned on the site has nothing to do with your isoceles triangle, sorry if it caused confusion.
aib
sorry if Im asking a dumb question, but the other posts on this question state that the x values use cos() and the y values use sin(), but your comment has them the otherway around, was this intended?
Mark
It doesn't really matter in your case. You can interchange sin and cos. They basically give you the same curve, with a PI/2 phase difference. All it will affect is where your triangle will initially be heading when your angle starts at 0.
Ates Goral
ok thanks Ates Goral.
Mark
But yes, I meant to have sin() and cos() the other way around in the comments. The point is, it's very easy to go back and forth between vector components, the vector angle, and your x/y displacement.
aib
+4  A: 

It seems to me that you need to store the rotation angle of the triangle and possibly it's current speed.

x' = x + speed * cos(angle)
y' = y + speed * sin(angle)

Note that angle is in radians, not degrees!

Radians = Degrees * RadiansInACircle / DegreesInACircle

RadiansInACircle = 2 * Pi

DegressInACircle = 360

For the locations of the vertices, each is located at a certain distance and angle from the center. Add the current rotation angle before doing this calculation. It's the same math as for figuring the movement.

Loren Pechtel
So if I was to use degrees, the formula would be:x' = x + speed * cos( myAngleInDegrees * ((2 * PI) / 360) )y' = y + speed * sin( myAngleInDegrees * ((2 * PI) / 360) )??
Mark
sorry about the formatting on that last comment
Mark
Yes, and in a more concise form: myAngleInDegrees * PI / 180
Ates Goral
hehe, even easier thanks Ates.
Mark
Yes, 2 Pi / 360 reduces to Pi / 180. I was trying to show the why.
Loren Pechtel
A: 
double v; // velocity
double theta; // direction of travel (angle)
double dt; // time elapsed

// To compute increments
double dx = v*dt*cos(theta);
double dy = v*dt*sin(theta);

// To compute position of the top of the triangle
double size; // distance between centroid and top
double top_x = x + size*cos(theta);
double top_y = y + size*sin(theta);
jakber
Does the logic behind computing the new top_x and top_y apply to the other 2 points as well in exactly the same manor?
Mark
+2  A: 

keep the centroid at the origin. use the vector from the centroid to the nose as the direction vector. http://en.wikipedia.org/wiki/Coordinate_rotation#Two_dimensions will rotate this vector. construct the other two points from this vector. translate the three points to where they are on the screen and draw.

Ray Tayek
A: 

I can see that I need to apply the common 2d rotation formulas to my triangle to get my result, Im just having a little bit of trouble with the relationships between the different components here.

aib, stated that:

The arctangent (inverse tangent) of vy/vx, where vx and vy are the components of your (centroid->tip) vector, gives you the angle the vector is facing.

Is vx and vy the x and y coords of the centriod or the tip? I think Im getting confused as to the terminology of a "vector" here. I was under the impression that a Vector was just a point in 2d (in this case) space that represented direction.

So in this case, how is the vector of the centroid->tip calculated? Is it just the centriod?

meyahoocomlorenpechtel stated:

It seems to me that you need to store the rotation angle of the triangle and possibly it's current speed.

What is the rotation angle relative to? The origin of the triangle, or the game window itself? Also, for future rotations, is the angle the angle from the last rotation or the original position of the triangle?

Thanks all for the help so far, I really appreciate it!

Mark
A: 

you will want the topmost vertex to be the centroid in order to achieve the desired effect.

vmarquez
You mean as the rotation anchor point?
Mark
Sure of that? Games like Asteroids put the center of rotation in the center of the ship, not on the nose. The formulas remain the same no matter where you put it, though.
Loren Pechtel
+3  A: 

@Mark:

I've tried writing a primer on vectors, coordinates, points and angles in this answer box twice, but changed my mind on both occasions because it would take too long and I'm sure there are many tutorials out there explaining stuff better than I ever can.

Your centroid and "tip" coordinates are not vectors; that is to say, there is nothing to be gained from thinking of them as vectors.

The vector you want, vForward = pTip - pCentroid, can be calculated by subtracting the coordinates of the "tip" corner from the centroid point. The atan2() of this vector, i.e. atan2(tipY-centY, tipX-centX), gives you the angle your triangle is "facing".

As for what it's relative to, it doesn't matter. Your library will probably use the convention that the increasing X axis (---> the right/east direction on presumably all the 2D graphs you've seen) is 0° or 0π. The increasing Y (top, north) direction will correspond to 90° or (1/2)π.

aib
Thank you aib, that is very clear. I appreciate the help greatly!
Mark
+3  A: 

Here's some more:

Vectors represent displacement. Displacement, translation, movement or whatever you want to call it, is meaningless without a starting point, that's why I referred to the "forward" vector above as "from the centroid," and that's why the "centroid vector," the vector with the x/y components of the centroid point doesn't make sense. Those components give you the displacement of the centroid point from the origin. In other words, pOrigin + vCentroid = pCentroid. If you start from the 0 point, then add a vector representing the centroid point's displacement, you get the centroid point.

Note that:

vector + vector = vector
(addition of two displacements gives you a third, different displacement)

point + vector = point
(moving/displacing a point gives you another point)

point + point = ???
(adding two points doesn't make sense; however:)

point - point = vector
(the difference of two points is the displacement between them)

Now, these displacements can be thought of in (at least) two different ways. The one you're already familiar with is the rectangular (x, y) system, where the two components of a vector represent the displacement in the x and y directions, respectively. However, you can also use polar coordinates, (r, Θ). Here, Θ represents the direction of the displacement (in angles relative to an arbitary zero angle) and r, the distance.

Take the (1, 1) vector, for example. It represents a movement one unit to the right and one unit upwards in the coordinate system we're all used to seeing. The polar equivalent of this vector would be (1.414, 45°); the same movement, but represented as a "displacement of 1.414 units in the 45°-angle direction. (Again, using a convenient polar coordinate system where the East direction is 0° and angles increase counter-clockwise.)

The relationship between polar and rectangular coordinates are:

Θ = atan2(y, x)
r = sqrt(x²+y²) (now do you see where the right triangle comes in?)

and conversely,

x = r * cos(Θ)
y = r * sin(Θ)

Now, since a line segment drawn from your triangle's centroid to the "tip" corner would represent the direction your triangle is "facing," if we were to obtain a vector parallel to that line (e.g. vForward = pTip - pCentroid), that vector's Θ-coordinate would correspond to the angle that your triangle is facing.

Take the (1, 1) vector again. If this was vForward, then that would have meant that your "tip" point's x and y coordinates were both 1 more than those of your centroid. Let's say the centroid is on (10, 10). That puts the "tip" corner over at (11, 11). (Remember, pTip = pCentroid + vForward by adding "+ pCentroid" to both sides of the previous equation.) Now in which direction is this triangle facing? 45°, right? That's the Θ-coordinate of our (1, 1) vector!

aib
A: 

Ok, so I have a lot of information here to go with, and Im trying to digest it all.

Its funny, I read all of your posts, and I understand at least 90% of it fine, 10% is a bit un-clear, but I still dont know quite how to apply it correctly.

I would like to run through and example situation, if i could, to help me out with the calculations and to help piece it all together.

the example below is in Java

First, I need to define the starting point of the triangle:

    //starting point
    double tip_x = 10;
    double tip_y = 10;

Then define some of the details of the triangle:

    //triangle details
    int width = 6; //base
    int height = 9;

    //direction vector init
    double heading_vec_x = 0;
    double heading_vec_y = 0;

And then from this get the initial centroid, considering that I want the triangle facing left of screen in the positive x-axis. (just the arithmetic average of the points)

    //calculate initial centroid x and y
    double centroid_x = (tip_y + (tip_y - (width/2)) + (tip_y + (width/2))) / 3;
    double centroid_y = (tip_x + (tip_x - height) + (tip_x - height)) / 3;

this give me a centriod_x at 10.0, and centroid_y at 4.0

After that, I need to calc the "heading vector" that the triangle is facing: (for the info you guys gave me)

    //calculate heading of triangle
    heading_vec_x = tip_x - centroid_x;
    heading_vec_y = tip_y - centroid_y;

which gives heading_vec_x: 0.0 and heading_vec_y: 6.0;

then I need the inverse tangent of that:

double direction_angle = Math.atan2(heading_vec_y, heading_vec_x);

which gives: direction_angle of 1.5707963267948966 I then want to rotate the triangle by itself, with NO forwarf displacement 45 degrees:

    int rotation_angle = 45;
    double radians = Math.toRadians(rotation_angle);

    tip_x = tip_x + Math.cos(radians);
    tip_y = tip_y + Math.sin(radians);

Which gives: tip x of 10.70 and tip y of 10.70

which is wrong...obviously if I rotate 45 degrees, I want a lower X value and a higher Y value.

Please let me know whats going on! Its killing me..

Thanks for all your patience too so far.

Mark
A: 

First, I would start with the centroid rather than calculate it. You know the position of the centroid and the angle of rotation of the triangle, I would use this to calculate the locations of the verticies. (I apologize in advance for any syntax errors, I have just started to dabble in Java.)

//starting point

double tip_x = 10;
double tip_y = 10;

should be

double center_x = 10;
double center_y = 10;

//triangle details

int width = 6; //base
int height = 9;

should be an array of 3 angle, distance pairs.

angle = rotation_angle + vertex[1].angle;
dist = vertex[1].distance;    
p1_x = center_x + math.cos(angle) * dist;
p1_y = center_y - math.sin(angle) * dist;
// and the same for the other two points

Note that I am subtracting the Y distance. You're being tripped up by the fact that screen space is inverted. In our minds Y increases as you go up--but screen coordinates don't work that way.

The math is a lot simpler if you track things as position and rotation angle rather than deriving the rotation angle.

Also, in your final piece of code you're modifying the location by the rotation angle. The result will be that your ship turns by the rotation angle every update cycle. I think the objective is something like Asteroids, not a cat chasing it's tail!

Loren Pechtel
Im sorry but I dont understand the 2 lines:angle = rotation_angle + vertex[1].angle;dist = vertex[1].distance; it may just be a syntax thing, but I just dont get what your doing here... what is vertex[1]? Sorry if its simple, Im just having more trouble with this that I thought I would...
Mark
Is vertex[1], supposed to represent the tip point of the triangle and the "angle" is its rotation from the center? what is the "distance" part of it?
Mark
I mean that your triangle info is three points, not just the tip. I'm specifying point 1 of 3--an array. (Note: This permits shapes other than a triangle, also.)
Loren Pechtel
Loren Pechtel
I see, thanks for the info, I appreciate the help. Although it seems that without meaning too, I turned this question from displacement to rotation which I didnt really mean to do!
Mark
I think I'm the one who turned it to rotation but that was because I saw that as a weakness in the approach you were proposing.
Loren Pechtel