XESOFT Explore Argus
Free / one file / no dependencies

Simple Vision Sensor for Unity

A clean starting point for enemy sight: distance, horizontal field of view, obstruction tests, last-seen position, and useful Scene-view gizmos. Use it in commercial projects.

Free for personal and commercial use. Attribution is appreciated, not required.

GUARD OCCLUDER TARGET LOS: BLOCKED
01

Small enough to understand in one sitting.

The sensor follows the usual inexpensive detection order. It rejects targets outside the range first, then checks the horizontal angle, and only performs a physics raycast for candidates that passed both cheap tests.

  • Configurable range and horizontal field of view.
  • Separate eye and target sample heights.
  • Layer-filtered obstruction raycast.
  • Public CanSeeTarget and LastSeenPosition values.
  • Scene-view range, cone, target ray, and last-seen gizmos.
  • No packages, editor scripts, tags, or project settings required.
02

Setup takes four steps.

  1. Download the script and place it anywhere under your project Assets folder.
  2. Add SimpleVisionSensor to the enemy GameObject.
  3. Assign the player Transform and select the layers that can block sight.
  4. Tune the range, field of view, eye height, and target sample height in Play mode.

Tip: exclude trigger-only gameplay volumes from the occluder mask so they do not block vision.

03

The important part of the source.

The downloadable file adds the complete gizmo drawing code; the detection path is shown here in full.

SimpleVisionSensor.csDownload ↓
using UnityEngine;

public sealed class SimpleVisionSensor : MonoBehaviour
{
    [SerializeField] private Transform target;
    [Min(0f)] [SerializeField] private float targetSampleHeight = 1f;

    [Header("Vision")]
    [Min(0.1f)] [SerializeField] private float range = 15f;
    [Range(1f, 360f)] [SerializeField] private float horizontalFieldOfView = 90f;
    [Min(0f)] [SerializeField] private float eyeHeight = 1.65f;
    [SerializeField] private LayerMask occluders = ~0;

    public bool CanSeeTarget { get; private set; }
    public Vector3 LastSeenPosition { get; private set; }

    private void Update() => CanSeeTarget = Evaluate(target);

    public bool Evaluate(Transform candidate)
    {
        if (candidate == null) return false;

        Vector3 origin = transform.position + Vector3.up * eyeHeight;
        Vector3 sample = candidate.position + Vector3.up * targetSampleHeight;
        Vector3 toTarget = sample - origin;

        if (toTarget.sqrMagnitude > range * range) return false;

        Vector3 planarDirection = Vector3.ProjectOnPlane(toTarget, Vector3.up);
        if (planarDirection.sqrMagnitude < 0.0001f) return false;
        if (Vector3.Angle(transform.forward, planarDirection)
            > horizontalFieldOfView * 0.5f) return false;

        float distance = toTarget.magnitude;
        if (Physics.Raycast(origin, toTarget / distance, out RaycastHit hit,
                distance, occluders, QueryTriggerInteraction.Ignore)
            && hit.transform.root != candidate.root) return false;

        LastSeenPosition = sample;
        return true;
    }

    // The download also includes a Scene-view cone and line-of-sight gizmo.
}
04

Use this until the game needs memory.

A single vision boolean is enough for a prototype. Production stealth AI usually grows into awareness buildup, peripheral vision, posture, lighting, hearing, clue discovery, evidence memory, last-known positions, suspicion hysteresis, searches, squad reports, threat arbitration, and debugging that explains every reaction.

That is the Argus boundary

Keep the simple rule. Add the complete system.

Argus preserves the readable sensor model and connects it to the rest of a production enemy-awareness stack.