Search Unity

Vision Cones in 2D

Discussion in '2D' started by TheDryden, May 24, 2018.

  1. TheDryden

    TheDryden

    Joined:
    Oct 20, 2017
    Posts:
    6
    I'm building a fully 2D game where characters sprites can be facing either North, East, South or West, I want to be able to use vision cones based on which way they are facing to determine what they can see. I've adapted similar code for 3D projects to match what I'm doing, however the East and West directions get swapped when I convert them to vectors. In other words if the character is looking left (east) the vector for their cone is facing right (west). The code works perfect however if they're facing North or South. I was hoping someone could help me with the math, I could probably brute force a fix, but I was hoping to understand why they were flipped.

    Note: since they are only 4 possible direction they can face, I'm storing the pre-calculated results so that it doesn't have to be calculated on the fly at every update.

    Note 2:_visionAngle is a variable passed to the constructor that indicates the width of the cone, typically this will be 90 degrees.

    Note 3: everything starts with underscore (_) because all of the values are accessed by property (i.e. _visionConeVectorA is accessed with the property VisionConeVectorA) using a stored index to determine which item is pulled from the array (that way the calling codes doesn't need to know which direction the character is facing).

    Code (CSharp):
    1.         _directionAngle = new float[] { 0f, 90f, 180f, 270f };
    2.  
    3.         for ( int i = 0; i < _x.Length; i++)
    4.         {
    5.             _visionConeAngleA[i] = _directionAngle[i] - (_visionAngle / 2);
    6.             _visionConeAngleB[i] = _directionAngle[i] + (_visionAngle / 2);
    7.  
    8.             float a = ( _visionConeAngleA[i] + 90f ) * Mathf.Deg2Rad
    9.                 , b = ( _visionConeAngleB[i] + 90f ) * Mathf.Deg2Rad;
    10.  
    11.             _visionConeVectorA[i] = new Vector3(Mathf.Cos(a), Mathf.Sin(a), 0f);
    12.             _visionConeVectorB[i] = new Vector3(Mathf.Cos(b), Mathf.Sin(b), 0f);
    13.         }
    Thanks!
     
  2. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    I'm not sure where your math skills are, so my apologies if this is too basic - but this is how I would explain it.

    To get the x and y components of a vector you can use trig, specifically the formulas SIN(angle) = o/h and COS(angle) = a/h where o is the side opposite the angle, and a is the side adjacent the angle. Like this:


    So here I am showing a unit length vector for the cases where he is looking North (dirAngle = 0) and East (dirAngle = 90). You can see that for North the x component is the sin of the angle, and for East the x component is the cos of the angle. Since you're using 45 degrees, when you add 90 to it you get 135 degrees, and sin and cos for 135 degrees are inverse from each other.
     
    Last edited: Jun 4, 2018
  3. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    What I do for 2D is basically get the angle between the enemy and player, check if it is less then the "see angle", check distance, and finally make sure there is nothing blocking the view.

    This is an example from a game I was working on where the player carries a flashlight that is always pointing in the direction of movement, hence I used it for the looking direction. But hopefully you can get the basic idea.
    Code (CSharp):
    1. bool SeesPlayer ()
    2.     {
    3.         // find the angle between player and direction guard is looking to see if within cone of vision
    4.         Vector2 lookDir = (Vector2)(flashlight.transform.localRotation * Vector3.forward); // use flashlight direction as direction guard is looking
    5.         Vector2 playerDir = (Vector2)player.transform.position - (Vector2)transform.position; // direction to player
    6.         float playerAngle = Vector2.Angle (lookDir, playerDir);
    7.  
    8.         // find distance to player
    9.         float playerDist = Vector3.Distance (player.transform.position, transform.position);
    10.         float seeDistance = player.GetComponent<PlayerController> ().flashlight.isOn ? float.PositiveInfinity : seeDist;
    11.  
    12.         // if player could be seen, check if there are obstacles (walls) between
    13.         if (playerAngle <= seeAngleHalf && playerDist <= seeDistance)
    14.         {
    15.             RaycastHit2D hit = Physics2D.Raycast (transform.position, playerDir, playerDist, cantSeeThru);
    16.             if (!hit) // no walls in the way
    17.             {
    18.                 //Debug.Log ("I see you!");
    19.                 alert = true;
    20.                 return true;
    21.             }
    22.         }
    23.  
    24.         return false; // can't see player
    25.     }
    26.  
     
    JoeStrout likes this.