Jump to content
  • Advertisement
Sign in to follow this  
guyaton

Converting Mouse clicks to angles

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

If you intended to correct an error in the post then please contact us.

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 
	//Quad1
	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 );
	}
	//Quad2
	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;
	}
	//Quad3
	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;
	}
	//Quad4
	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 );
	}

thanks in advance, guyaton

Share this post


Link to post
Share on other sites
Advertisement
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().


//globals
VECTOR2 Character;
VECTOR2 Cursor;
.
.
.
//do it on each loop
float angle = float(atan((Cursor.y-Character.y)/(Cursor.x-Character.x));
//now move the character
Character.x += CharacterSpeed*cos(angle)*dt;//dt is the timestep between each loop
Cahracter.y += CharacterSpeed*sin(angle)*dt;
.
.
.



I hope I helped you...
Cya..

Share this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Just use atan2().
It's already been suggested. From earlier in the thread:
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 this post


Link to post
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 ...


//globals
VECTOR2 Character;
VECTOR2 Cursor;
.
.
.
//do it on each loop
float 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 character
Character.x += CharacterSpeed*cosine*dt;//dt is the timestep between each loop
Character.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 this post


Link to post
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!