• 11
• 27
• 9
• 20
• 31

# Converting Mouse clicks to angles

This topic is 4555 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

What I am trying to do is determine the angle difference between a player character on the screen and where the mouse was last clicked. The reason I am trying to figure this out is so that my 2d character can be facing the right direction when he walks. I have it working for 4 of the 8 directions (NE, NW, SW, SE are working) but N, W, S, and E do not work. What am I doing wrong? I tried converting to polar coordinates to find the theta between the two lines, but it doesn't seem to work for angles near 90 degree. Here's the source.
	float fPointX = static_cast<float>( this->m_ptMovePosition.x ) - this->m_fPositionX;
float fPointY = static_cast<float>( this->m_ptMovePosition.y ) - this->m_fPositionY;
float fThetaOff = 0.0f;

//need to translate to
if( static_cast<float>( this->m_ptMovePosition.x ) >= this->m_fPositionX &&
static_cast<float>( this->m_ptMovePosition.y ) <= this->m_fPositionY )
{
fPointX = fabsf( fPointX );
fPointY = fabsf( fPointY );
}
else if( static_cast<float>( this->m_ptMovePosition.x ) <= this->m_fPositionX &&
static_cast<float>( this->m_ptMovePosition.y ) <= this->m_fPositionY )
{
//convert the Y to positive
fPointY *= -1;
//set the offset to 180 so that theta will be correct in the end
fThetaOff = 180.0f;
}
else if( static_cast<float>( this->m_ptMovePosition.x ) <= this->m_fPositionX &&
static_cast<float>( this->m_ptMovePosition.y ) >= this->m_fPositionY )
{
//fPointX *= -1;
fPointY *= -1;
fThetaOff = 180.0f;
}
else if( static_cast<float>( this->m_ptMovePosition.x ) >= this->m_fPositionX &&
static_cast<float>( this->m_ptMovePosition.y ) >= this->m_fPositionY )
{
fPointY *= -1;
fThetaOff = 360.0f;
}

//Visual Studio 6.0 has a weird error where atanf isn't
//included in the std namespace
#if _MSC_VER > 1200
float theta = std::atanf( static_cast<float>( fPointX ) / fPointY  );
#else
float theta = atanf( static_cast<float>( fPointX ) / fPointY  );
#endif

//convert to degrees
theta *= ( 180 / PI );

//this line below should be plus equals but for some reason html
//won't show it as plus equals.
theta += fThetaOff;

//now set the animation direction
if( LOOKING_N( theta ) )
{
this->SetAnimationSet( UP_ANIMATION );
}
else if( LOOKING_NE( theta ) )
{
this->SetAnimationSet( UP_RIGHT_ANIMATION );
}
else if( LOOKING_E( theta ) )
{
this->SetAnimationSet( RIGHT_ANIMATION );
}
else if( LOOKING_SE( theta ) )
{
this->SetAnimationSet( DOWN_RIGHT_ANIMATION );
}
else if( LOOKING_S( theta ) )
{
this->SetAnimationSet( DOWN_ANIMATION );
}
else if( LOOKING_SW( theta ) )
{
this->SetAnimationSet( DOWN_LEFT_ANIMATION );
}
else if( LOOKING_W( theta ) )
{
this->SetAnimationSet( LEFT_ANIMATION );
}
else if( LOOKING_NW( theta ) )
{
this->SetAnimationSet( UP_LEFT_ANIMATION );
}



##### Share on other sites
I'm not sure if I've understood you but do you want that the character go to the place where the player clicked?!?

Well, to do it(in 2D) you must have the character position and the mouse cursor position when the player clicked. Then, its just you subtract the cursor y position from the character y position and divide by the subtraction between the cursor x position and the character x position.This calculation will give you the tangent of the angle formed by the cursor-character vector.To get the angle just use atan(). Then to move the character use sin() and cos().

//globalsVECTOR2 Character;VECTOR2 Cursor;...//do it on each loopfloat angle = float(atan((Cursor.y-Character.y)/(Cursor.x-Character.x));//now move the characterCharacter.x += CharacterSpeed*cos(angle)*dt;//dt is the timestep between each loopCahracter.y += CharacterSpeed*sin(angle)*dt;...

I hope I helped you...
Cya..

##### Share on other sites
the player already moves, its a matter of getting him/her to face the correct direction. I have 8 animations which are the 8 major directions of a compas, North, North East, East...etc. I am trying to figure out how to make sure he is facing the direction that was just clicked in respect to his current location.

~guyaton

##### Share on other sites
Couple things:
Quote:
 //this line below should be plus equals but for some reason html won't show it as plus equals.
You've probably already figured this out, but although gdnet filters +'s in preview mode, they do show up in the post.

The problem with both your and xissburg's methods is the use of atan(), which requires workarounds to deal with the quadrants, and angles near +/-90 (pi/2). C++ is kind enough to provide an alternate function, atan2(), which handles these details internally. So you might have something like:
Vector2 diff = target.pos-player.pos;float angle = atan2(diff.y, diff.x);player.direction.x = cos(angle);player.direction.y = sin(angle);
Note that this is the same as normalizing diff to get direction, but more expensive. However, you also get the angle, which may be useful for other purposes.

The only failure case is when the player is right on top of the target, which may or may not be possible depending on your circumstances.

##### Share on other sites
hi there

xissburg, I think there's a problem with your angle calculation using atan().
If player.x and cursor.x are the same you get a div. by zero.

EDIT: Oh, what I suggested does not work... go with jyk's method.

##### Share on other sites
Quote:
 the player already moves, its a matter of getting him/her to face the correct direction. I have 8 animations which are the 8 major directions of a compas, North, North East, East...etc. I am trying to figure out how to make sure he is facing the direction that was just clicked in respect to his current location.
For this problem it seems you could snap the angle returned in my previous example to the nearest multiple of pi/4. You could then use this result to choose an animation.

##### Share on other sites
Just use atan2().

##### Share on other sites
Quote:
 Just use atan2().
Quote:
 The problem with both your and xissburg's methods is the use of atan(), which requires workarounds to deal with the quadrants, and angles near +/-90 (pi/2). C++ is kind enough to provide an alternate function, atan2(), which handles these details internally.

##### Share on other sites
Wow... :P

I didn't see it ,hell...i hate tangents!!lol

Instead using tangents, you could also find the distance between the cursor and the character and then take Cursor.x-Character.x. Divinding Cursor.x-Character.x by the distance you get the cosine of the angle. the sine of the angle will be sqrt(1.0f - cosine*cosine).It will use two sqrt() but not acos(). Since sqrt is faster than acos()(I'm not sure :P) it can be a good idea :P ...

//globalsVECTOR2 Character;VECTOR2 Cursor;...//do it on each loopfloat distance = sqrt((Cursor.x-Character.x)*(Cursor.x-Character.x)+(Cursor.y-Character.y)*(Cursor.y-Character.y));float cosine = (Cursor.x-Character.x)/distance;//now move the characterCharacter.x += CharacterSpeed*cosine*dt;//dt is the timestep between each loopCharacter.y += CharacterSpeed*sqrt(1.0f - cosine*cosine)*dt;...

hmm....If there's something wrong in my code please say me...I'm not a good writer :P

Thanks

##### Share on other sites
Quote:
 If there's something wrong in my code please say me...
Not 'wrong' per se, but perhaps unnecessarily inefficient and unstable. First, sqrt(1.0f - cosine*cosine) may fail in practice if cosine comes out to be just a little over 1. This can be guarded against by taking the absolute value of the argument.

However, this sqrt is unnecessary. Consider that sqrt(1.0f - cosine*cosine) can be re-arranged into (Cursor.y-Character.y)/distance. 'distance' has already been calculated, so only one sqrt is required. At this point you have:
float cosine = (Cursor.x-Character.x)/distance;float sine   = (Cursor.y-Character.y)/distance;
Which you'll recognize as a simple vector normalization.