Adding Line of Sight Player Detection to AI in Unity 3D

Published

After implementing a Patrolling System, it is now time to implement other behaviours. But before that, we need a trigger to will get us from one active behaviour to another. In the case of a patrolling system, it is quite useful for our AI to be able to see the player and start attacking him.

Indeed, this a staple of many genres of game (FPS, stealth, RPG…) and we’ll implement is simply by using SphereCasting.

Implementing Line of Sight detection

In the class responsible for handling state management, we’ll set a method responsible for performing a spherecast (which is our detection system), with a given width and depth of view (defining our Line of Sight).

public class StateManager : MonoBehaviour {
    public float mRaycastRadius;  // width of our line of sight (x-axis and y-axis)
    public float mTargetDetectionDistance;  // depth of our line of sight (z-axis)

    private RaycastHit _mHitInfo;   // allocating memory for the raycasthit
    // to avoid Garbage
    private bool _bHasDetectedEnnemy = false;   // tracking whether the player
    // is detected to change color in gizmos

    public void CheckForTargetInLineOfSight()
    {
        _bHasDetectedEnnemy = Physics.SphereCast(transform.position, mRaycastRadius, transform.forward, out _mHitInfo, mTargetDetectionDistance);

        if (_bHasDetectedEnnemy)
        {
            if (_mHitInfo.transform.CompareTag("Player"))
            {
                Debug.Log("Detected Player");
                // insert fighting logic here
            } else
            {
                Debug.Log("No Player detected");
                // no player detected, insert your own logic
            }

        } else
        {
            // no player detected, insert your own logic
        }
    }
}

Visualizing Detection Range using Gizmos

Gizmos are an Editor tool to visualize elements in your editor view, such as colliders or lights positions. It can be very useful to draw your own.

For this system, we’ll visualize our spherecasting and set it as red if the AI has got the player in its line of sight, and green if it hasn’t. Unfortunately, gizmos have no method for drawing sphere casting directly so we’ll just draw a cube.

The code is pretty straightforward: we set the color by checking the value of _bHasDetectedEnnemy (which is set by our spherecasting solely for this purpose) and then draw our cube.

One nice tip for handling gizmos: it can be messy to draw gizmos properly, so I prefer to work in local space and set the gizmo matrix to handle the conversion to world space.

Here’s our code:

private void OnDrawGizmos()
{
    if (_bHasDetectedEnnemy)
    {
        Gizmos.color = Color.red;
    } else
    {
        Gizmos.color = Color.green;
    }

    Gizmos.matrix = transform.localToWorldMatrix;

    Gizmos.DrawCube(new Vector3(0f, 0f, mTargetDetectionDistance / 2f), new Vector3(mRaycastRadius, mRaycastRadius, mTargetDetectionDistance));
}

Now that we’ve done all this, here’s the result once you have implemented a proper fighting system:

Spherecasting Player Detection
Using SphereCasting to Detect Player, and Gizmos to show detection range in Editor

As you can see, the gizmo which is initially green turns red when we enter the detection area, and the Orc rushes to attack the player when it detects him. Big Success!