Angle of rotation formula depending on sprite position

Started by
23 comments, last by ElyasMachera 12 years, 10 months ago
Hi, I'm new to the gamedev.net and hope to know you guys :)
I'm just going over game basics to get the hang of it.
I have a 2d spaceship please see attached file.
I was using the one the right initially, but then I was messing with the rotation when I decided to use the one on the left.
To calculate the direction (velocity) vector based on that right sprite position I used this formula,

playerVel.X = Math.Sin(rotAngle) ;
playerVel.Y = -Math.Cos(rotAngle) ;

That worked fine, until I let the sprite's initial position look like that of the left. To calculate the direction I was guessing the formula..until I tried the original formula of finding direction based on angle of rotation. The one that makes sense.

playerVel.X = Math.Cos(rotAngle);
playerVel.Y = Math.Sin(rotAngle) ;

now this makes sense! Cos is used to find the X value and Sin to find the Y value. My question is, how does switching how the sprite's initial direction in a 2d image change the formula to find the new direction vector?
If I knew how to plot this on a graph paper I'd be able to derive the formula instead of guessing..I was never good at trigonometry so can someone please make this clear using some pictures of a graph or something..hopefully? :P
Thanks
Advertisement
It's all based on how you're defining your rotation angle. Your initial orientations differ by 90 degrees, so your definition of the where angle = 0 is differs, which means the formulas are going to differ slightly.

Incidentally, rotating by 90 degrees in 2D can be achieved by swapping the X & Y coordinates, and then negating one of the coordinates. If you look at the difference between the two formulas you've come up with you'll notice you've done exactly that.

Hopefully that makes sense.
[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler
There are 2 ways:

1. An offset of the angle by -90° (in this case) compared to the original


playerVel.X = Math.Sin(rotAngle-90) ;
playerVel.Y = -Math.Cos(rotAngle-90);

(ignoring that sin and cos usually need radian instead of degree) and using the correspondences


sin( a-90° ) == cos( a ), sin( a+90° ) == -cos( a ), cos( a-90° ) == -sin( a ), cos( a+90° ) == sin( a )

because the sine and cosine curves are the same but just 90° shifted.

2. Rotating the original vector as Postie has already mentioned above:


[ cos( 90° ) -sin( 90° ) ] * [ sin( a ) ] = [ 0 -1 ] * [ sin( a ) ] = [ cos( a ) ]
[ sin( 90° ) cos( 90° ) ] [ -cos( a ) ] [ 1 0 ] [ -cos( a ) ] [ sin( a ) ]
thanks guys..sorry for late reply, I didn't know I got a reply. The second answer was very difficult to follow, I am not good at maths like that...but I get it now thanks :)
By the way I was also wondering why when I am trying to get the direction vector of the enemy to look at the player..
I use atan2(y2-y1,x2-x1)
the code works well if the angle of the player is at 0 degrees pointing to the right..it will point directly at the player..
however if the sprites heading is upwards at 90 degrees..the atan2 doesn't give me the correct results.
so I am wondering for the enemy sprite to rotate at the player correctly does the ship sprite need to have an initial angle of 0 degrees (must it be facing right on the spritesheet)?
Because even if I subtracted 90 from the atan2 results the ship still doesn't look directly at the player, if its initial angle was at 90 degrees on the spritesheet..
any insights on this?
Thanks..

... The second answer was very difficult to follow, I am not good at maths like that...but I get it now thanks

Sorry for that, but unfortunately things are inherently math. And so is your next question, too:


By the way I was also wondering why when I am trying to get the direction vector of the enemy to look at the player..
I use atan2(y2-y1,x2-x1)
the code works well if the angle of the player is at 0 degrees pointing to the right..it will point directly at the player..

The atan2 is a improved function of the atan (i.e. "arc tangent" or "inverse tangent") function. To understand atan2, you need to understand the tangent function.

The tangent function of an angle is defined as the ratio of the opposite to the adjacent leg. With atan2(y,x) the corresponding arc tangent function is atan(y/x). Because the arc tangent is the inverse of the tangent, y plays the role of the opposite and x the role of the adjacent leg.

Hence the result of atan2(y,x) will be
* angle==0 where y==0 and x>0 (i.e. straight to the right),
* angle==90° where y>0 and x==0 (i.e. straight up),
* angle==180° where y==0 and x<0 (i.e. straight to the left),
* angle==-90° where y<0 and x==0 (i.e. straight down).

If this is not what you want, you have to adapt the values. E.g. by exchanging the values, i.e. using atan2(x,y) instead, you'll get
* angle==0 where x==0 and y>0 (i.e. straight up),
* angle==90° where x>0 and y==0 (i.e. straight to the right),
* angle==180° where x==0 and y<0 (i.e. straight down),
* angle==-90° where x<0 and y==0 (i.e. straight to the left).

You can also alter the sign of one or both values. E.g. atan2(-y,x) yields in
* angle==0 where y==0 and x>0 (i.e. straight to the right),
* angle==90° where y<0 and x==0 (i.e. straight down),
* angle==180° where y==0 and x<0 (i.e. straight to the left),
* angle==-90° where y>0 and x==0 (i.e. straight up).

...

So you can rotate the axes by 90° when swapping y and x, and you can mirror up/down and/or left/right by negating one or both arguments. If you need further help, please tell us what angles you desire at what combination of x and y (like I've done above).
Hi Haegar thanks for reply..I know maths is but I'm sure you've met people like myself where sin and cos puts them off..but I'd really like to understand it so I can make cool games ha ha you might have heard that a lot..
The angle of the sprite in the sprite sheet is at 90 degrees...but I can't tell where the x and y positions of the player or enemy will be as it is random.

To make things simple..we know that the sprite both enemy and player looking up at 90 degrees (12 o'clock)..and to calculate the angle of rotation for the enemy to face the player I would need the
atan function...since the x and y coordinates are random...
how do I decide which formula to use
atan2(x,y) atan2(y,x) atan2(-y,x)
Maybe if we start from there...I'd slowly but surely come to understand why it is happening..I hope you're patient enough to help me as I am very slow.
Thanks
Just a general recommendation: stick with '0 degrees/radians points along the +x axis' for all your game objects and game object visuals (e.g. sprites), and things will be much simpler. (Following this convention, you would use 'atan2(y, x)'.)

The angle of the sprite in the sprite sheet is at 90 degrees...but I can't tell where the x and y positions of the player or enemy will be as it is random.

Well, although the positions are arbitrary w.r.t. the definition range, the correspondence between the delta of the positions and the angle is not arbitrary; and that is what we're looking for.


To make things simple..we know that the sprite both enemy and player looking up at 90 degrees (12 o'clock)..and to calculate the angle of rotation for the enemy to face the player I would need the
atan function...since the x and y coordinates are random...
how do I decide which formula to use
atan2(x,y) atan2(y,x) atan2(-y,x)

The 3 functions I've listed are just 3 examples out of a set of 8 possibilities. However ... let's go into the details:

You want to know the angle of rotation with which the sprite of ship A has to be transformed to let its forward vector point to the position of target ship B. The sprite has a default forward vector (i.e. the forward vector when the sprite is unrotated) of f[sub]x[/sub]=0 and f[sub]y[/sub]=1. Please notice that these values denote a direction, not a position! I.e. it is irrelevant where the sprite is placed; its default forward direction is ever the same.

The default forward direction can be written in vector notation as:
[ f[sub]x[/sub] f[sub]y[/sub] ] = [ 0 1 ]
If you apply the atan2(y,x) function to these values, you'll get that the default forward direction is at
atan2( f[sub]y[/sub] , f[sub]x[/sub] ) = atan2( 1, 0 ) = 90° =: a[sub]f[/sub]
what we'll define as the angle a[sub]f[/sub].
(Attention: The atan2 function, when used in computer programs, deals with radian values (i.e. 2 pi means 360°), while I use degree here for simplicity!)

If you check out some values, you'll find that the angle of 0° is returned by atan2( y,x ) when y==0 and x>0. Hence, the reference angle 0° is to the right (for the constellation (y,x) of arguments). Because we've found above that +90° is straight up, atan2(y,x) gives us increasing angles when rotating in counter clockwise (CCW) direction.

The function atan(y/x) is working inside atan2(y,x). As you can see, the argument to atan is a quotient. One consequence is that if both y and x are scaled by the same factor (unequal to 0), the quotient and hence the resulting angle from atan is the same. E.g. atan( 3/5 ) gives the same angle as atan( (2*3)/(2*5) ). The same is true for atan2 in principle, but remember that atan2 is able to distinguish which signs each of y and x has. That means that for atan2 the factor must be >0 (and not only !=0).

That said, what would scaling of [ x y ] mean? It would mean that the distance of the both ships is irrelevant when computing the angle; only the direction is relevant.

So we can compute the difference between the positions from ship A to ship B as
[ x[sub]B[/sub] y[sub]B[/sub] ] - [ x[sub]A[/sub] y[sub]A[/sub] ] = [ x[sub]B[/sub]-x[sub]A [/sub]y[sub]B[/sub]-y[sub]A[/sub] ]
as you already know, an put this into atan2 without bothering the absolute distance, and compute the angle of this direction as
a[sub]d[/sub] := atan2( y[sub]B[/sub]-y[sub]A[/sub] , x[sub]B[/sub]-x[sub]A [/sub])
which denotes the angle to the targeted ship.

When looking at the difference of the default angle a[sub]f[/sub] and this target angle a[sub]d[/sub], we see that
* for y[sub]B[/sub]-y[sub]A[/sub] == 0, x[sub]B[/sub]-x[sub]A [/sub]> 0, i.e. ship B is straight to the right of ship A, we get a[sub]d[/sub]-a[sub]f[/sub] = 0°-90° == -90°, i.e. rotate A by 90° in CW direction to target B,
* for y[sub]B[/sub]-y[sub]A[/sub] == 0, x[sub]B[/sub]-x[sub]A [/sub]< 0, i.e. ship B is straight to the left of ship A, we get a[sub]d[/sub]-a[sub]f[/sub] = 180°-90° == +90°, i.e. rotate A by 90° in CCW direction to target B,
* for y[sub]B[/sub]-y[sub]A[/sub] > 0, x[sub]B[/sub]-x[sub]A [/sub]== 0, i.e. ship B is straight above ship A, we get a[sub]d[/sub]-a[sub]f[/sub] = 90°-90° == 0°, i.e. don't rotate A to target B,
* for y[sub]B[/sub]-y[sub]A[/sub] < 0, x[sub]B[/sub]-x[sub]A [/sub]== 0, i.e. ship B is straight below ship A, we get a[sub]d[/sub]-a[sub]f[/sub] = -90°-90° == -180°, i.e. rotate A by 180° to target B.

All of these 4 (straight forward and therefore chosen) cases work fine. The receipt you're looking for is hence:
1. compute the difference angle from the both ship positions (B - A) using the atan2(y,x),
2. subtract the default forward angle of 90° from it,
3. use the resulting angle for rotation.
[sub][/sub]
hello, @jyk I get what you mean..but it wouldn't hurt to have this knowledge
@haegar I think I get what you mean

if the ship is facing right, then its original look vector irrespective of it its position is (1,0) and atan2(0) is always 90
if it is up at 90 (0,-1) in reference to your first post should it not be x==0, y<0 for the ship looking up?

if the ship is facing right, then its original look vector irrespective of it its position is (1,0) and atan2(0) is always 90

It would be better to say that the original (or default, i.e. unrotated) look vector is [ 0 1 ] (but see below), and that the current look vector is [ 1 0 ] when facing to the right, and all this regardless of the location of the ship. This distinction is necessary because we need the default (or original) vector to be constant. One can say that it is the look direction in the model's local space but expressed in global co-ordinates, and as such it is fixed.

atan2(0) is not defined, because atan2 requires 2 parameters. But atan2(y,0) for any y>0 is always 90°, correct.


if it is up at 90 (0,-1) in reference to your first post should it not be x==0, y<0 for the ship looking up?

Err, does this mean that y increases from top to bottom rather than from bottom to top? Until now I assumed here and in any post above that y increases from the bottom of the screen to its top, because AFAIK it is the way D3D handles this! Please clarify.

If that assumption is wrong, then the vector [ 0 1 ] and its belonging angle +90° will point down, while the vector [ 0 -1 ] and its belonging angle -90° will point up. Moreover, positive angles mean to rotate in CW direction, while negative angles mean to rotate in CCW direction. This can be overcome simply by negating the angle after its computation by atan2, where necessary.

This topic is closed to new replies.

Advertisement