Search Unity

Left/Right test function

Discussion in 'Scripting' started by HigherScriptingAuthority, Oct 2, 2009.

  1. It is easy to get the angle between two vectors using Vector3.Angle, but this only gives an absolute value for the angle. How do you tell if one direction is to the left or to the right of the other?

    It seems as though it should be easy, but in fact it's a little bit subtle. I've attached a function (in both JS and C# versions) that illustrates how to go about it. You need to supply a forward direction, the direction that you want to check for left/right of forward and an up direction. The functions return -1 when the target direction is left, +1 when it is right and 0 if the direction is straight ahead or behind.

    As is so often the case, the magic ingredient in the function is the cross product.
     

    Attached Files:

    Tarrag, Lu_Atar, Oyedoyin1 and 7 others like this.
  2. Muckel

    Muckel

    Joined:
    Mar 26, 2009
    Posts:
    429
    many many thanxxx
    ... how long was i searching for this solution...
    Now my Direction Display works !!!
    I really miss this in the Doc's !!!
    Great Community !!!
    :oops: kerstin

    P.S. Need#s to be on the Wiki !
     
  3. Robotron18

    Robotron18

    Joined:
    Aug 15, 2010
    Posts:
    12
    Thank you very much.
    You can get also the final vector, comfortable to transform own collisions.

    Code (csharp):
    1.  
    2. Vector3 VectorResult;
    3. float DotResult = Vector3.Dot(transform.forward, target.forward);
    4.         if (DotResult > 0)
    5.         {
    6.             VectorResult = transform.forward + target.forward;
    7.         }
    8.         else
    9.         {
    10.             VectorResult = transform.forward - target.forward;
    11.         }
    12.         Debug.DrawRay(transform.position, VectorResult * 100, Color.green);
     
  4. AkilaeTribe

    AkilaeTribe

    Joined:
    Jul 4, 2010
    Posts:
    1,149
    Simple and clean. Good job :wink:
     
  5. cerebrate

    cerebrate

    Joined:
    Jan 8, 2010
    Posts:
    261
    static version?

    Code (csharp):
    1. //returns -1 when to the left, 1 to the right, and 0 for forward/backward
    2. public static function AngleDir(fwd: Vector3, targetDir: Vector3, up: Vector3) : float {
    3.     var perp: Vector3 = Vector3.Cross(fwd, targetDir);
    4.     var dir: float = Vector3.Dot(perp, up);
    5.    
    6.     if (dir > 0.0) {
    7.         return 1.0;
    8.     } else if (dir < 0.0) {
    9.         return -1.0;
    10.     } else {
    11.         return 0.0;
    12.     }
    13. }
     
    kev000 likes this.
  6. elveatles

    elveatles

    Joined:
    May 2, 2009
    Posts:
    147
    Thank you so much HigherScriptingAuthority! This is exactly what I was looking for!
     
  7. samim23

    samim23

    Joined:
    Sep 11, 2012
    Posts:
    60
    Cool script, thanks for this. Here is the C# version:

    Code (csharp):
    1.  
    2.         //returns -1 when to the left, 1 to the right, and 0 for forward/backward
    3.     public float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up)
    4.     {
    5.         Vector3 perp = Vector3.Cross(fwd, targetDir);
    6.         float dir = Vector3.Dot(perp, up);
    7.  
    8.         if (dir > 0.0f) {
    9.             return 1.0f;
    10.         } else if (dir < 0.0f) {
    11.             return -1.0f;
    12.         } else {
    13.             return 0.0f;
    14.         }
    15.     }  
    16.  
     
    Asifno13 and Pozonu like this.
  8. yoyo

    yoyo

    Joined:
    Apr 16, 2010
    Posts:
    112
    In 2D there is a much simpler way, as explained in this stack overflow question.

    Code (csharp):
    1. public static float AngleDir(Vector2 A, Vector2 B)
    2. {
    3.     return -A.x * B.y + A.y * B.x;
    4. }
    This returns a negative number if B is left of A, positive if right of A, or 0 if they are perfectly aligned.

    It works by rotating B 90 degrees counter-clockwise (which is simply {-B.y, B.x}) and then taking the dot product to see if the rotated vector is ahead or behind A. (Make some vector combinations with your fingers and wiggle them around until you convince yourself this works! ;))
     
  9. NickP_2

    NickP_2

    Joined:
    Jul 9, 2013
    Posts:
    61

    You saved me a whole night and a gallon of coffee :)
     
    Last edited: Mar 4, 2014
  10. nsbigmotive

    nsbigmotive

    Joined:
    Aug 2, 2016
    Posts:
    1
    Thank you very much HigherScriptingAuthority! Perfect!
     
  11. andyblem

    andyblem

    Joined:
    Nov 11, 2014
    Posts:
    20
    great piece of code
     
  12. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    336
    If you have a Transform, you can also just take the dot product of its .right vector, and the direction vector.

    Also, OP, I think this version of your code would be marginally easier to understand :)
    Code (CSharp):
    1. float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up) {
    2.     Vector3 right = Vector3.Cross(up, fwd);        // right vector
    3.     float dir = Vector3.Dot(right, targetDir);
    4.    
    5.     if (dir > 0f) {
    6.         return 1f;
    7.     } else if (dir < 0f) {
    8.         return -1f;
    9.     } else {
    10.         return 0f;
    11.     }
    12. }
     
    DrWittenborg likes this.
  13. Mohamad-al-labban

    Mohamad-al-labban

    Joined:
    May 20, 2014
    Posts:
    1
    Thanks a lot for sharing this
     
  14. CouchRonin

    CouchRonin

    Joined:
    Jul 9, 2017
    Posts:
    1
    Thank you so much for sharing this, it's just perfect for a game I am working on.
     
  15. GeneralKaiminus

    GeneralKaiminus

    Joined:
    Feb 17, 2018
    Posts:
    6
    Thank you for the share woah i'm now getting to understand how it works XD
     
  16. Kev00

    Kev00

    Joined:
    Dec 6, 2016
    Posts:
    167
    if all you need to know is what side an object is on there is another way.

    Vector3 localPos = objectFacing.InverseTransformPoint(objectToTest.transform.position);
    if (localPos.x < 0.0f) // left side
    else if (localPos.x > 0.0f) // right side
    else // center
     
    modernator24 and JamesThornton like this.
  17. abitofjohn

    abitofjohn

    Joined:
    Nov 6, 2012
    Posts:
    22
    Thanks so much HigherScriptingAuthority! You've saved me hours!
     
  18. modernator24

    modernator24

    Joined:
    Apr 7, 2017
    Posts:
    7
    @Kev00 That works. Thanks!
     
  19. erwtje013

    erwtje013

    Joined:
    Jun 13, 2018
    Posts:
    2
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;


    public class SamusDamage : MonoBehaviour
    {
    public GameObject Player;


    public Transform playerTransform;

    private float playerPos;
    private float collPos;




    private void OnCollisionEnter2D(Collision2D collision)
    {
    if(collision.gameObject.name == "Reo")
    {
    collPos = collision.transform.position.x;
    playerPos = Player.transform.position.x;



    if (playerPos >= collPos)
    {
    //you are on the right
    }
    else
    {
    //you are on the left
    }


    }
    }

    }



    this is for 2d
     
  20. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    336
    What if the player isn't facing straight forward?
     
  21. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    77
    Almost 10 years later, and this answer is still useful. Thanks You!
     
  22. Alvarezmd90

    Alvarezmd90

    Joined:
    Jul 21, 2016
    Posts:
    70
    Wait.. can I use this for checking f.e. which side of a door a player is standing?
    'Cause I use a mouse axis code to make the player pull the door, but on the other side it's inverted. 0__o