## Convert vector to angle?

Oldtimer
Posts: 832
Joined: 2002.09
Post: #16
So why aren't you striving to get better, by doing it the right way? It's a little bit like learning to drive by constantly having someone drive the car to a hilltop, and then sit by the wheel as it rolls down the hill.

Instead of explaining it to you, I'm going to point you to this wonderful Java applet:
http://catcode.com/trig/trig05.html

Play around with it for a while to get a feel for what the sine and cosine actually are. What you're doing in your application (with regards to moving the player at an angle, not the atan2f stuff) is that you take the angle and ask for the X and Y sides of the triangle. Think of it like this: you have your angle, and you want to move in the direction of it. That's the same as moving in the direction of the hypotenuse. (Regardless of which direction you want to move in, you can always stick a right triangle to that vector, where the short sides make up the X and Y directions.)

Now, here comes the trick: you want a hypotenuse with a length of exactly 1. Why? Well, because it's easy to scale. If you want to move by 30pixels/sec, you do in fact want to move 1 * 30 pixels/sec, right? Might seem trivial, but it will come in handy, since that also means that the X and Y speeds you want to move in are the X and Y sides of that triangle, times 30. What you're doing is:
1) constructing a right triangle
2) with a hypotenuse of 1
3) and then scaling that entire triangle up to the speed you want to move with

It's dead simple! To figure out the short sides of the triangle, you use sin(angle) and cos(angle), which gives you the lengths of the two short sides. Now, just scale those sides up.

Therefore, the complete (and very, very standard) code you'll get is the following:

Code:
```float angle; float radians void move_player() {     NSPoint vector;     vector.x = new_world_dst.x - player.x;     vector.y = new_world_dst.y - player.y;     angle = atan2(vector.y, vector.x);    // The ONLY right way to get the angle     // Also, atan2 returns in radians already     position.x += cos(radians) * SPRITE_SPEED; // Add the X-side to the X pos, and scale it to SPRITE_SPEED     position.y += sin(radians) * SPRITE_SPEED; // Add the Y-side to the Y pos, and scale it to SPRITE_SPEED }```

I hope that clears things up for you. And a little morale of the story: whenever you don't understand code, it will bite you bad. If nothing else, you've skipped an opportunity for learning, which is a terrible thing to waste.
Member
Posts: 151
Joined: 2002.09
Post: #17
Things you are still doing wrong: converting to an angular coordinate system and back again when it could have been done faster.
And in the special case of new_world_dst == player you would probably want the position to remain the same.
Member
Posts: 105
Joined: 2007.03
Post: #18
Fenris Wrote:So why aren't you striving to get better, by doing it the right way? It's a little bit like learning to drive by constantly having someone drive the car to a hilltop, and then sit by the wheel as it rolls down the hill.

Instead of explaining it to you, I'm going to point you to this wonderful Java applet:
http://catcode.com/trig/trig05.html

Play around with it for a while to get a feel for what the sine and cosine actually are. What you're doing in your application (with regards to moving the player at an angle, not the atan2f stuff) is that you take the angle and ask for the X and Y sides of the triangle. Think of it like this: you have your angle, and you want to move in the direction of it. That's the same as moving in the direction of the hypotenuse. (Regardless of which direction you want to move in, you can always stick a right triangle to that vector, where the short sides make up the X and Y directions.)

Now, here comes the trick: you want a hypotenuse with a length of exactly 1. Why? Well, because it's easy to scale. If you want to move by 30pixels/sec, you do in fact want to move 1 * 30 pixels/sec, right? Might seem trivial, but it will come in handy, since that also means that the X and Y speeds you want to move in are the X and Y sides of that triangle, times 30. What you're doing is:
1) constructing a right triangle
2) with a hypotenuse of 1
3) and then scaling that entire triangle up to the speed you want to move with

It's dead simple! To figure out the short sides of the triangle, you use sin(angle) and cos(angle), which gives you the lengths of the two short sides. Now, just scale those sides up.

Therefore, the complete (and very, very standard) code you'll get is the following:

Code:
```float angle; float radians void move_player() {     NSPoint vector;     vector.x = new_world_dst.x - player.x;     vector.y = new_world_dst.y - player.y;     angle = atan2(vector.y, vector.x);    // The ONLY right way to get the angle     // Also, atan2 returns in radians already     position.x += cos(radians) * SPRITE_SPEED; // Add the X-side to the X pos, and scale it to SPRITE_SPEED     position.y += sin(radians) * SPRITE_SPEED; // Add the Y-side to the Y pos, and scale it to SPRITE_SPEED }```

I hope that clears things up for you. And a little morale of the story: whenever you don't understand code, it will bite you bad. If nothing else, you've skipped an opportunity for learning, which is a terrible thing to waste.

Actually atan2 returns the angle value in radians so you wouldn't do position.x += cos(radians) * SPRITE_SPEED you'd use position.x += cos(angle) * SPRITE_SPEED instead. And I was only kidding around earlier when about the inversion thing
Moderator
Posts: 869
Joined: 2003.01
Post: #19
Leroy Wrote:Actually atan2 returns the angle value in radians so you wouldn't do position.x += cos(radians) * SPRITE_SPEED you'd use position.x += cos(angle) * SPRITE_SPEED instead. And I was only kidding around earlier when about the inversion thing

Actually using atan2() for this is quite stupid

You can save yourself the whole ordeal and just use the normalized vector in the first place.
Member
Posts: 100
Joined: 2006.05
Post: #20
DoG Wrote:Actually using atan2() for this is quite stupid

You can save yourself the whole ordeal and just use the normalized vector in the first place.

Just divide the components by the length of the vector:

Code:
```vector.x = new_world_dst.x - player.x;     vector.y = new_world_dst.y - player.y;          float scale = SPRITE_SPEED/sqrt(vector.x^2 + vector.y^2)     position.x += vector.x*scale;     position.y += vector.y*scale;```
Member
Posts: 151
Joined: 2002.09
Post: #21
Code:
```vector.x = new_world_dst.x - player.x;     vector.y = new_world_dst.y - player.y;          float sqd = vector.x * vector.x + vector.y * vector.y;     if(sqd > 0.00001) {         float scale = SPRITE_SPEED/sqrt(sqd);         position.x += vector.x*scale;         position.y += vector.y*scale;     }```
Moderator
Posts: 767
Joined: 2003.04
Post: #22
Code:
```#define SPRITE_SPEED2 SPRITE_SPEED*SPRITE_SPEED ...     vector.x = new_world_dst.x - player.x;     vector.y = new_world_dst.y - player.y;          float sqd = vector.x * vector.x + vector.y * vector.y;     if(sqd > 0.00001f) {         float scale = SPRITE_SPEED2/sqd;         position.x += vector.x*scale;         position.y += vector.y*scale;     }```
Member
Posts: 105
Joined: 2007.03
Post: #23
DoG Wrote:Actually using atan2() for this is quite stupid
You can save yourself the whole ordeal and just use the normalized vector in the first place.

What exactly is is that makes the latter mentioned method superior?
Sage
Posts: 1,403
Joined: 2005.07
Post: #24
Code:
```#define SPRITE_SPEED2 SPRITE_SPEED*SPRITE_SPEED ...     vector.x = new_world_dst.x - player.x;     vector.y = new_world_dst.y - player.y;          float sqd = vector.x * vector.x + vector.y * vector.y;     if(sqd > 0.00001f) {         float scale = SPRITE_SPEED2/sqd;         position.x += vector.x*vector.x*scale;         position.y += vector.y*vector.y*scale;     }```

Sir, e^iÏ€ + 1 = 0, hence God exists; reply!
Member
Posts: 100
Joined: 2006.05
Post: #25
Whoa there. Why are we squaring everything? The square of a ratio is not identical to the ratio itself. I realize we're trying to avoid the overhead of the expensive sqrt call, but if you square the ratio, you'll have to take the square root anyway. Hog had it right...

Oh yeah. Sin, cos, and atan2 are all very expensive (performance-wise) function calls and are very prone to rounding errors. So if we can avoid all that with one call to sqrt, the routine should perform better.
Moderator
Posts: 767
Joined: 2003.04
Post: #26
edit: nvm - 1:24am
Member
Posts: 105
Joined: 2007.03
Post: #27
Nevada Wrote:Oh yeah. Sin, cos, and atan2 are all very expensive (performance-wise) function calls and are very prone to rounding errors. So if we can avoid all that with one call to sqrt, the routine should perform better.

Correct me if I'm wrong but can't you just use sin and cos tables to eliminate the expense?
Sage
Posts: 1,482
Joined: 2002.09
Post: #28
Leroy Wrote:Correct me if I'm wrong but can't you just use sin and cos tables to eliminate the expense?

Yes, but at the cost of more rounding errors. Making a lookup table entry for every possible 32bit float is not an option.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Moderator
Posts: 1,140
Joined: 2005.07
Post: #29
Why are you trying to get around using a much easier, faster, and all round better method anyway?
Luminary
Posts: 5,139
Joined: 2002.04
Post: #30
On a modern processor, a sin/cos lookup table with any accuracy is almost certainly more expensive than just calculating the sin or cosine directly.