Vector Rotation Problem

Started by
4 comments, last by haegarr 12 years, 1 month ago
So what I want to do is to have my main character holding a weapon that aims wherever the mouse is pointing.

My solution to this is to find the current position of the mouse, find the angle between that point and the character's current direction vector, and then finally rotate the character's direction vector by that angle to make it point toward the mouse.

I've never used vectors in my games before, and I'm running into a problem; namely, my code implementation isn't working tongue.png Here is my code (C++):

//set weapon's direction
float angle = m_vDirection.findAngleRadians(mouse);
//rotate
m_vDirection.rotate(angle);
//get angle between weapon direction and 0 degrees
Vector2D vectemp;
vectemp.x = m_vPosition.x - m_rCamera->x;
vectemp.y = m_vPosition.y - m_rCamera->y;
float angleFromZero = m_vDirection.findAngleDegrees(vectemp);
if(angleFromZero > 360)
angleFromZero /= 360;
//set image accordingly
if((angleFromZero >= 0 && angleFromZero <= 30) ||
(angleFromZero >= 330 && angleFromZero <= 0))
{
currentDirection = RIGHT;
}
else if(angleFromZero >= 31 && angleFromZero <= 59)
{
currentDirection = UPRIGHT;
}
else if(angleFromZero >= 60 && angleFromZero <= 120)
{
currentDirection = UP;
}
else if(angleFromZero >= 121 && angleFromZero <= 149)
{
currentDirection = LEFTUP;
}
else if(angleFromZero >= 150 && angleFromZero <= 210)
{
currentDirection = LEFT;
}
else if(angleFromZero >= 211 && angleFromZero <= 239)
{
currentDirection = LEFTDOWN;
}
else if(angleFromZero >= 240 && angleFromZero <= 300)
{
currentDirection = DOWN;
}
else if(angleFromZero >= 301 && angleFromZero <= 329)
{
currentDirection = RIGHTDOWN;
}
m_pSprite->setClip(clips[currentDirection]);


As you can see, I try to find the direction that the weapon is currently pointing by checking the angle between a vector (that I think is) pointing along 0 degrees, and the main character's direction vector. This is the part that I think is really not working. And in actuality, I expect it not to because when I think about it, I feel like there is definitely something wrong with my theory, because I don't know what the origin of these vectors are, which could throw off my whole assumption of the 0-360 degrees being the directions that I think they are.

If anyone can tell me what I'm doing wrong, or if I'm going about this problem in the completely wrong way, please help me out! Thanks in advance smile.png

Here are my implementations for Vector2D::findAngleRadians(), Vector2D::findAngleDegrees(), and Vector2D::rotate() just in case anyone wants to see them:

float Vector2D::findAngleRadians(Vector2D& rhs)
{
float dotProd,
lengthLHS,
lengthRHS,
angleCos;
//find dot product
dotProd = dot(rhs);
//find length of each vector
lengthLHS = getLength();
lengthRHS = rhs.getLength();
//find the cosine of the angle
angleCos = dotProd / (lengthLHS * lengthRHS);
//return angle between the two vectors in radians
return acosf(angleCos);
}
//*****************************************************
float Vector2D::findAngleDegrees(Vector2D& rhs)
{
const double PI = 3.1415926;
float dotProd,
lengthLHS,
lengthRHS,
angleCos,
angleInRads;
//find dot product
dotProd = dot(rhs);
//find length of each vector
lengthLHS = getLength();
lengthRHS = rhs.getLength();
//find the cosine of the angle
angleCos = dotProd / (lengthLHS * lengthRHS);
//find angle in radians
angleInRads = acosf(angleCos);
//return angle between the two vectors in degrees
return (angleInRads * (180 / PI));
}
//*****************************************************
Vector2D& Vector2D::rotate(float t)
{
x = x * cosf(t) - y * sinf(t);
y = y * cosf(t) + x * sinf(t);
return *this;
}
Advertisement

My solution to this is to find the current position of the mouse, find the angle between that point and the character's current direction vector, and then finally rotate the character's direction vector by that angle to make it point toward the mouse.

It is usually not necessary to compute an angle and from that to compute an orientation. Often it is suitable to build the orientation directly from the direction.

E.g. if t denotes the target point and a the anchor point of the character, then
d := t - a
denotes the difference vector from the character to the target, and
d' := d / |d|
denotes the belonging normalized direction vector. Using the perp operator you can get a perpendicular vector to that. E.g.
p := perp( d' ) = [ d'[sub]y[/sub] -d'[sub]x[/sub] ][sup]t[/sup]
is a solution if the positive y is 90° counterclockwise to the positive x axis.

With this, the orientation matrix is simply
[ d' p ]
(assuming that the "forward" vector is located at the first column). Much easier than using angles, isn't it?

However, throwing a look at your code:


...

//set weapon's direction
float angle = m_vDirection.findAngleRadians(mouse);



So, how is "mouse" defined? Is it already given in the same space as m_vDirection?



//rotate
m_vDirection.rotate(angle);
//get angle between weapon direction and 0 degrees
Vector2D vectemp;
vectemp.x = m_vPosition.x - m_rCamera->x;
vectemp.y = m_vPosition.y - m_rCamera->y;
float angleFromZero = m_vDirection.findAngleDegrees(vectemp);
if(angleFromZero > 360)
angleFromZero /= 360;



You want to use "angleFromZero -= 360;" here.



//set image accordingly
if((angleFromZero >= 0 && angleFromZero <= 30) ||
(angleFromZero >= 330 && angleFromZero <= 0))
{
currentDirection = RIGHT;
}
else if(angleFromZero >= 31 && angleFromZero <= 59)
{
currentDirection = UPRIGHT;
}
else if(angleFromZero >= 60 && angleFromZero <= 120)
{
currentDirection = UP;
}
else if(angleFromZero >= 121 && angleFromZero <= 149)
{
currentDirection = LEFTUP;
}
else if(angleFromZero >= 150 && angleFromZero <= 210)
{
currentDirection = LEFT;
}
else if(angleFromZero >= 211 && angleFromZero <= 239)
{
currentDirection = LEFTDOWN;
}
else if(angleFromZero >= 240 && angleFromZero <= 300)
{
currentDirection = DOWN;
}
else if(angleFromZero >= 301 && angleFromZero <= 329)
{
currentDirection = RIGHTDOWN;
}
m_pSprite->setClip(clips[currentDirection]);


This is an insufficient solution, because you have gaps between the particular branches. E.g. what happens if angleFromZero is 59.5?


As you can see, I try to find the direction that the weapon is currently pointing by checking the angle between a vector (that I think is) pointing along 0 degrees, and the main character's direction vector. This is the part that I think is really not working. And in actuality, I expect it not to because when I think about it, I feel like there is definitely something wrong with my theory, because I don't know what the origin of these vectors are, which could throw off my whole assumption of the 0-360 degrees being the directions that I think they are.

m_vDirection's name hints that the vector is a direction vector. vectemp is definitely a direction vector. Opposed to position vectors (a.k.a. points), direction vectors lack the concept of "origin". They are just directions.



If anyone can tell me what I'm doing wrong, or if I'm going about this problem in the completely wrong way, please help me out! Thanks in advance smile.png

Here are my implementations for Vector2D::findAngleRadians(), Vector2D::findAngleDegrees(), and Vector2D::rotate() just in case anyone wants to see them:

float Vector2D::findAngleRadians(Vector2D& rhs)

{
float dotProd,
lengthLHS,
lengthRHS,
angleCos;
//find dot product
dotProd = dot(rhs);
//find length of each vector
lengthLHS = getLength();
lengthRHS = rhs.getLength();
//find the cosine of the angle
angleCos = dotProd / (lengthLHS * lengthRHS);
//return angle between the two vectors in radians
return acosf(angleCos);
}
//*****************************************************
float Vector2D::findAngleDegrees(Vector2D& rhs)
{
const double PI = 3.1415926;
float dotProd,
lengthLHS,
lengthRHS,
angleCos,
angleInRads;
//find dot product
dotProd = dot(rhs);
//find length of each vector
lengthLHS = getLength();
lengthRHS = rhs.getLength();
//find the cosine of the angle
angleCos = dotProd / (lengthLHS * lengthRHS);
//find angle in radians
angleInRads = acosf(angleCos);
//return angle between the two vectors in degrees
return (angleInRads * (180 / PI));
}
//*****************************************************
Vector2D& Vector2D::rotate(float t)
{
x = x * cosf(t) - y * sinf(t);
y = y * cosf(t) + x * sinf(t);
return *this;
}


IMHO:
1. You should use "const&" for the parameters named "rhs" above.
2. You should rewrite findAngleDegrees to be as simple as "return findAngleInRadians(rhs) * 180 / PI;", perhaps even inlined.


EDIT: Unfortunately I had written 'perpDot' instead of 'perp' in the original version of this post.
Thanks for your reply! I'll look through all of this tomorrow after work :)

[quote name='Ziel' timestamp='1331290547' post='4920628']
My solution to this is to find the current position of the mouse, find the angle between that point and the character's current direction vector, and then finally rotate the character's direction vector by that angle to make it point toward the mouse.

It is usually not necessary to compute an angle and from that to compute an orientation. Often it is suitable to build the orientation directly from the direction.

E.g. if t denotes the target point and a the anchor point of the character, then
d := t - a
denotes the difference vector from the character to the target, and
d' := d / |d|
denotes the belonging normalized direction vector. Using the perpDot operator you can get a perpendicular vector to that. E.g.
p := perpDot( d' ) = [ d'[sub]y[/sub] -d'[sub]x[/sub] ][sup]t[/sup]
is a solution if the positive y is 90° counterclockwise to the positive x axis.

With this, the orientation matrix is simply
[ d' p ]
(assuming that the "forward" vector is located at the first column). Much easier than using angles, isn't it?
[/quote]

I hate to ask, but would you mind giving a code example of this? Also, I don't understand what the perpendicular dot operator is. >_<
Any help guys? I don't understand the orientation matrix. I looked up the perpdot product and apparently it returns a scalar. How do you stick a vector d' and a scalar p into a matrix? sad.png!

[quote name='haegarr' timestamp='1331293732' post='4920638']
...


I hate to ask, but would you mind giving a code example of this? Also, I don't understand what the perpendicular dot operator is. >_<
[/quote]
Form the OP's code snippets its not clear to me whether you have a Matrix2D class, whether Vector2D (and perhaps Matrix2D) are affine or homogeneous, and whether non-scalar operators plus, minus, ... exist. So I'll try to give some code that seems me suiting the OP's code, although I would not implement it that way.

// the position vector denoting the target
Vector2D t = ...;
// the position vector denoting the anchor point of the character, given in same space as t
Vector2D a = ...;

// difference vector from a to t
Vector2D d;
d.x = t.x - a.x;
d.y = t.y - a.y;

// normalizing difference vector gives a standard direction vector (d')
float norm = sqrt( d.x*d.x + d.y*d.y );
d.x /= norm;
d.y /= norm;

// making a perpendicular vector
Vector2D p;
p.x = d.y;
p.y = -d.x;

// building 2D orientation matrix; it is given in the same space as t and a
Matrix2D m;
m.x.x = d.x;
m.x.y = d.y;
m.y.x = p.x;
m.y.y = p.y;

Now, the problems with showing some code are further:
1. I don't know whether you deal with column or row vectors.
2. I don't know whether my definition of "forward" vector (e.g. d') is suitable for our definition of the model and world.
Hence it may be that an offset of e.g. 90° is needed, and / or that the distribution of d's and p's scalars when building m must be done in another way.


...I looked up the perpdot product and apparently it returns a scalar. How do you stick a vector d' and a scalar p into a matrix?

Sorry for that, my mistake. The perpDot operator is just a dot operator but uses a variation of one of its arguments. That variation is in fact a simple method of building a perpendicular vector from a given vector. Its just that method that I wanted to hint at, but not the perpDot in its entirety. I've corrected my posts above, now using a "perp" instead of perpDot now.

This topic is closed to new replies.

Advertisement