Get Your Personalized Game Dev Plan Tailored tips, tools, and next steps - just for you.

This page may contain affiliate links.

Creating a Basic Stealth System in Unity with C#

Posted by Gemma Ellison
./
July 21, 2025

The thrill of sneaking past an enemy, the tension of being spotted, the satisfaction of a perfectly executed stealth maneuver – these are the core elements that make stealth games so captivating. But how do you, as a developer, translate that feeling into code? Let’s dive into creating a rudimentary stealth system using Unity and C#, focusing on the essential components that will form the foundation of your game’s sneaky mechanics. This isn’t just about slapping some code together; it’s about understanding why we do things a certain way and arming you with the knowledge to customize and expand upon this basic framework.

Setting Up the Vision Cone

The vision cone is the cornerstone of our AI’s awareness. Forget raycasting pointlessly - we’re using a more focused approach.

First, create a new material in your project. Set its shader to "Particles/Additive". Give it a color – a semi-transparent green is a good start. Next, create a new Mesh in your script (C#).

using UnityEngine;

public class VisionCone : MonoBehaviour
{
    public int segments = 12;
    public float viewDistance = 10f;
    public float viewAngle = 90f;
    public Material coneMaterial;

    private Mesh visionMesh;

    void Start()
    {
        visionMesh = CreateVisionConeMesh();
        GameObject coneObject = new GameObject("VisionConeMesh");
        coneObject.transform.SetParent(transform, false); //Attach cone to the parent and maintain world position
        coneObject.AddComponent<MeshFilter>().mesh = visionMesh;
        coneObject.AddComponent<MeshRenderer>().material = coneMaterial;
    }

    private Mesh CreateVisionConeMesh()
    {
        Mesh mesh = new Mesh();

        Vector3[] vertices = new Vector3[segments + 2];
        int[] triangles = new int[segments * 3];

        vertices[0] = Vector3.zero; // Origin point

        float angleIncrement = viewAngle / segments;
        for (int i = 0; i <= segments; i++)
        {
            float angle = -viewAngle / 2 + angleIncrement * i;
            Vector3 vertex = Quaternion.Euler(0, angle, 0) * Vector3.forward * viewDistance;
            vertices[i + 1] = vertex;
        }

        for (int i = 0; i < segments; i++)
        {
            triangles[i * 3] = 0;
            triangles[i * 3 + 1] = i + 1;
            triangles[i * 3 + 2] = i + 2;
        }

        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();

        return mesh;
    }
}

Attach this script to your AI character. Adjust segments, viewDistance, and viewAngle to tweak the cone’s shape. Assign your material. Now you have a visual representation of what the AI can see!

Pitfall: Don’t crank up the segments value too high. It impacts performance. Start low and increase only if necessary.

AI Detection Logic: Visibility and Distance

Now that we have a vision cone, let’s make the AI use it. The AI needs to consider both the player’s visibility and their distance. This gives a more realistic feel.

Create a script called AIDetection and attach it to the AI character.

using UnityEngine;

public class AIDetection : MonoBehaviour
{
    public float detectionDistance = 10f;
    public float visibilityThreshold = 0.5f; // How visible the player needs to be to be detected
    public LayerMask obstructionMask;

    private Transform player;

    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player").transform; //Ensure player has tag
    }

    void Update()
    {
        if (CanSeePlayer())
        {
           //Do something, e.g. Raise an Alert
           Debug.Log("Player Detected!");
        }
    }

    bool CanSeePlayer()
    {
        Vector3 directionToPlayer = player.position - transform.position;
        float distanceToPlayer = directionToPlayer.magnitude;

        if (distanceToPlayer > detectionDistance) return false;

        float angleToPlayer = Vector3.Angle(transform.forward, directionToPlayer.normalized);
        VisionCone visionCone = GetComponent<VisionCone>(); //Get ref to vision cone script

        if (angleToPlayer > visionCone.viewAngle / 2) return false;

        // Visibility check: Use Raycast to determine if the player is visible
        RaycastHit hit;
        if (Physics.Raycast(transform.position, directionToPlayer.normalized, out hit, distanceToPlayer, obstructionMask))
        {
            if (hit.transform != player) //Something is obstructing the player
            {
                return false;
            }
        }

        return true;
    }
}

Set detectionDistance to match your vision cone’s range. The obstructionMask is crucial. Set it to include any layers that can block the AI’s view (walls, boxes, etc.).

Challenge: AI constantly detects the player, even when crouching? Check that the player’s collider and obstruction mask are configured correctly and that crouching logic is modifying the visibilityThreshold.

Crouching to Reduce Visibility

Crouching is a classic stealth mechanic. Let’s implement it.

Create a simple script called PlayerCrouch.

using UnityEngine;

public class PlayerCrouch : MonoBehaviour
{
    public float crouchHeight = 0.5f;
    public float standingHeight = 2f;
    public float crouchSpeed = 5f;

    private CharacterController characterController;
    private bool isCrouching = false;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        standingHeight = characterController.height; //Store the initial height
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.LeftControl))
        {
            isCrouching = !isCrouching;
            AdjustCharacterHeight();
        }
    }

    void AdjustCharacterHeight()
    {
        if (isCrouching)
        {
            characterController.height = crouchHeight;
        }
        else
        {
            characterController.height = standingHeight;
        }
    }
}

Attach this to your player character. Make sure your player has a CharacterController component.

Now, let’s modify the AIDetection script to account for crouching. We’ll add a public crouchVisibilityMultiplier to the AIDetection script. Modify the CanSeePlayer() method to include this:

public float crouchVisibilityMultiplier = 0.5f;

//Inside CanSeePlayer()
        if (player.GetComponent<PlayerCrouch>().isCrouching)
        {
            visibilityThreshold *= crouchVisibilityMultiplier;
        }

        // Visibility check: Use Raycast to determine if the player is visible
        RaycastHit hit;
        if (Physics.Raycast(transform.position, directionToPlayer.normalized, out hit, distanceToPlayer, obstructionMask))
        {
            if (hit.transform != player) //Something is obstructing the player
            {
                return false;
            }
        }

Value Added: This simple multiplier allows you to easily balance how much harder it is to detect a crouching player.

Putting It All Together: A Basic Stealth Scenario

Imagine a warehouse. You, the player, need to sneak past a patrolling guard to reach a locked door. The guard has a limited vision cone, as defined by the VisionCone script. The AIDetection script determines if the guard can “see” you, considering both distance and obstructions. Crouching makes you harder to detect, but also slows you down (you’d need to add speed reduction to the PlayerCrouch script).

Step-by-Step Breakdown:

  1. Setup: Create a simple warehouse environment with walls and boxes for cover.
  2. AI Placement: Place the guard in a strategic location, like patrolling a hallway.
  3. Vision Cone Adjustment: Fine-tune the guard’s viewDistance and viewAngle to create a challenging but fair detection range.
  4. Testing: Playtest! Can you sneak past the guard by using cover and crouching? Is the detection range balanced? Adjust the detectionDistance, visibilityThreshold, and crouchVisibilityMultiplier as needed.

Beyond the Basics: Expanding Your Stealth System

This is just a starting point. Here are some ideas to expand your stealth system:

  • Sound: Implement sound-based detection. Footsteps, opening doors, etc. should alert the AI.
  • Alert States: Give the AI different alert states (Suspicious, Searching, Alerted) to make their behavior more dynamic.
  • Lighting: Make the player harder to see in shadows.
  • Distractions: Allow the player to throw objects to distract the AI.

Stealth game development is an iterative process. Experiment, tweak, and most importantly, playtest! This foundation will give you a head start in crafting compelling and engaging stealth experiences. The key is to go beyond the surface and create a system that feels both challenging and rewarding. Good luck sneaking!