'How do I calculate a 2D Vector from a dot product or a signed angle?
I have the following scenario:
I am working on a top-down 2-dimensional (XZ plane) game and i need to calculate the difference of the characters movement direction (moveDir) to the look direction (lookDir).
I would like to calculate a 2D Vector (xy) that holds the following information:
The X value should range from -1 (character facing backwards) to 1 (facing forwards)
The Y value should also range from -1 (character facing left) to 1 (facing right).
To calculate the X value I can use the dot product of moveDir and lookDir. However, I dont understand how to correctly calculate the Y value. I assume that I have to use the signedAngle between moveDir and lookDir, as the signedAngle returns a value of -90 if the character is facing left and 90 if its facing right.
I could probably even use the signedAngle between the vectors for calculating both X and Y values, as a signedAngle of 0 has the same meaning as a dot product of 1 (and also the same applies to a signedAngle of 180 and the dot product of -1).
How do I calculate the missing part?
Solution 1:[1]
I figured out the following solution (pseudocode):
y = 1 - absoluteValue(dotProduct(lookDir, moveDir))
if (signedAngle(lookDir, moveDir) <= 0
y *= -1
Solution 2:[2]
As said assuming both moveDir
and lookDir
are normalized vectors I think you can simply use Vector2.Dot
for the first one:
var x = Vector2.Dot(moveDir, lookDir);
this will return a value between 1
(lookDir == moveDir
=> looking "forward") and -1
(lookDir == -moveDir
=> looking "back") and 0
would mean it is perpendicular.
Then for "left" and "right" you can cheat a little bit and basically do the same but using Vector3.Cross
(note that even though you only want 2D vectors Unity is a 3D engine after all) in order to first obtain a vector that supposedly is "right" like e.g.
var y = Vector2.Dot(lookDir, Vector3.Cross(moveDir, Vector3.forward).normalized);
to explain this a bit
we use
Vector3.forward
which is basically(0, 0, 1)
(a vector pointing into the screen away from you) since you are dealing withVector2
vectors which move on theXY
plane. So in order to get a perpendicular vector to aVector2
we first need a vector that is perpendicular to all of them on the third axisVector3.Cross
uses left hand ruleso
Vector3.Cross(moveDir, Vector3.forward)
returns a Vector pointing 90° to the "right" from the
moveDir
Vector3
andVector2
are implicitly convertible into each other which will simply ignore theZ
component or use0
OR as Fredy pointed out you can also simply use
var y = Mathf.Sin(Vector2.SignedAngle(lookDir, moveDir) * Mathf.Deg2Rad);
which basically does the same and is probably less complicated ;)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | ceso |
Solution 2 |