Master Engineering & Neuroscience

Stealth Vision Architecture: Dynamic Light Raycasting, Shadow Volume Sampling & Acoustic Attenuation

By DopaBrain AI Systems & Spatial Simulation Team • 2026-10-01
Stress Check Guard patrol tension, discovery panic & silent infiltration heart-rate composure Reaction Time Corner peek timing, takedown reflex & shadow-to-shadow sprint reaction latency 2048 Coach Field of view dot product calculus, inverse-square illumination & acoustic attenuation Brain Type Test Ghost infiltration vs aggressive takedown tactical stealth archetype

In tactical stealth games, survival horror titles, and infiltration espionage experiences on Roblox (such as Entry Point, The Rake, and tactical co-op incursions), realistic NPC sensory awareness is paramount. Players quickly lose immersion if guards possess omniscience through solid walls, or conversely, if enemies fail to spot an infiltrator sprinting across a brightly lit courtyard.

Creating convincing stealth demands a multi-modal sensory architecture combining optical cone calculations, physical shadow occlusion, ambient light level evaluation, and acoustic wave attenuation. In this technical engineering masterclass, we architect a production-grade stealth sensory pipeline in Luau. We implement dot-product vision cones, raycast-based shadow volume tests, surface-dependent footstep sound propagation, and a state machine transitioning smoothly from Unaware to Combat.

1. The Omniscience Dilemma: Why Naive Distance Checks Fail

Primitive stealth systems rely solely on Euclidean distance checks (`(guard.Position - player.Position).Magnitude < range`), introducing game-breaking design flaws:

2. Mathematical Foundations: Dot Product Cones, Light Attenuation & Acoustic Decibels

Realistic stealth sensory simulation combines vector geometry, inverse-square light propagation, and material acoustic absorption:

3. Complete Production Stealth Sensory Controller Luau Implementation

The following modular Luau script evaluates guard sight, light exposure, and sound propagation on Heartbeat intervals with RaycastParams caching:

StealthSensoryController.luau (Vision Cones, Light Sampling & Alert FSM)
--!strict
-- StealthSensoryController.luau
-- Production stealth sensory perception engine for Roblox Studio

local Workspace = game:GetService("Workspace")
local Players = game:GetService("Players")

export type AlertState = "Unaware" | "Suspicious" | "Alerted" | "Combat"

export type GuardSensoryConfig = {
    FieldOfViewDeg: number,
    SightRangeMax: number,
    HearingRangeMax: number,
    ShadowDetectionFactor: number, -- Visibility multiplier in dark shadows (e.g. 0.35)
    AlertBuildRate: number,        -- Awareness points per second
    AlertDecayRate: number,        -- Awareness points lost per second
}

local StealthController = {}
StealthController.__index = StealthController

function StealthController.new(guardModel: Model, config: GuardSensoryConfig)
    local self = setmetatable({}, StealthController)
    self.Guard = guardModel
    self.Config = config
    self.Head = guardModel:WaitForChild("Head") :: BasePart
    self.Awareness = 0 -- 0 to 100 scale
    self.State = "Unaware" :: AlertState

    -- Raycast parameters setup with collision filtering
    self.RayParams = RaycastParams.new()
    self.RayParams.FilterType = RaycastFilterType.Exclude
    self.RayParams.FilterDescendantsInstances = {guardModel}
    self.RayParams.IgnoreWater = true

    return self
end

function StealthController:IsTargetInSightCone(targetPos: Vector3): (boolean, number)
    local eyePos = self.Head.Position
    local lookDir = self.Head.CFrame.LookVector
    local toTarget = targetPos - eyePos
    local distance = toTarget.Magnitude

    if distance > self.Config.SightRangeMax then
        return false, 0
    end

    local dirNormalized = toTarget.Unit
    local dotProduct = lookDir:Dot(dirNormalized)
    local minDot = math.cos(math.rad(self.Config.FieldOfViewDeg * 0.5))

    if dotProduct >= minDot then
        return true, distance
    end
    return false, distance
end

function StealthController:IsTargetInShadow(targetPart: BasePart): boolean
    -- Directional sunlight raycast (estimating sun direction)
    local sunDir = Vector3.new(0.3, 0.9, 0.2).Unit
    local rayOrigin = targetPart.Position + Vector3.new(0, 1, 0)
    local rayDir = sunDir * 100

    local result = Workspace:Raycast(rayOrigin, rayDir, self.RayParams)
    -- If hit solid object above, target is occluded from direct sunlight
    return result ~= nil
end

function StealthController:EvaluateSensory(playerCharacter: Model, dt: number)
    local targetTorso = playerCharacter:FindFirstChild("HumanoidRootPart") :: BasePart?
    local targetHead = playerCharacter:FindFirstChild("Head") :: BasePart?
    if not targetTorso or not targetHead then return end

    local inCone, dist = self:IsTargetInSightCone(targetHead.Position)
    local canSee = false

    if inCone then
        -- Line-of-sight raycast check
        local eyePos = self.Head.Position
        local toHead = targetHead.Position - eyePos
        local hitResult = Workspace:Raycast(eyePos, toHead, self.RayParams)

        if hitResult and hitResult.Instance:IsDescendantOf(playerCharacter) then
            canSee = true
        end
    end

    if canSee then
        local inShadow = self:IsTargetInShadow(targetTorso)
        local lightFactor = inShadow and self.Config.ShadowDetectionFactor or 1.0
        local distanceFactor = 1.0 - math.clamp(dist / self.Config.SightRangeMax, 0, 1)

        -- Awareness builds faster at close range under bright light
        local buildIncrement = self.Config.AlertBuildRate * distanceFactor * lightFactor * dt
        self.Awareness = math.clamp(self.Awareness + buildIncrement, 0, 100)
    else
        -- Decay awareness when target lost
        self.Awareness = math.clamp(self.Awareness - (self.Config.AlertDecayRate * dt), 0, 100)
    end

    -- State transition evaluation
    if self.Awareness >= 100 then
        self.State = "Combat"
    elseif self.Awareness >= 70 then
        self.State = "Alerted"
    elseif self.Awareness >= 25 then
        self.State = "Suspicious"
    else
        self.State = "Unaware"
    end
end

return StealthController

4. Acoustic Sound Propagation & Alert Escalation State Machines

Vision is only half of stealth gameplay; sound creates dynamic cat-and-mouse tension through structural acoustics:

5. Production Optimization & Raycast Budgeting on Mobile Devices

Running dozens of active stealth guards at 60 FPS across mobile and low-end hardware requires rigorous computational throttling:

Frequently Asked Questions

How do I prevent NPCs from spotting players through semi-transparent glass or chain-link fences?

Configure the RaycastParams filter table or use CollisionGroups to mark transparent materials. If a ray intersects glass with a Transparency > 0.5, apply a visual distortion coefficient (e.g. 0.4x detection speed) rather than blocking vision entirely.

Why should sight cone checks use dot products before casting rays?

Raycasts perform expensive spatial intersection tests against the physics geometry. The dot product is a trivial 3-multiplication algebraic vector test that prunes out 75% of non-visible targets instantly, saving vital CPU frametime.

How can I implement dynamic shadow volumes for moving spotlights and flashlights?

For dynamic spotlights, cast a ray from the spotlight's position toward the player torso. If the distance is less than the spotlight range, within the spot angle, and unobstructed, the player is illuminated; otherwise, they remain in shadow.

How do I handle sound detection when multiple players sprint simultaneously?

Maintain an acoustic sound queue in the StealthController. Each frame, evaluate the loudest sound origin within hearing radius, causing the NPC to prioritize high-decibel stimuli (such as gunshots or breached doors) over distant footsteps.

What is the recommended alert decay rate for engaging stealth gameplay?

A decay rate of 10 to 15 awareness points per second allows players who break line-of-sight to hide behind cover and reset guard vigilance within 4 to 6 seconds, providing rewarding, responsive stealth recovery loops.

Explore More Interactive Tests & Guides

Discover personalized cognitive assessments, stress evaluations, and game psychology tools on DopaBrain.

Go to Portal Hub