Renvix Assets

Vision Perception

Turns what a Vision Source sees into AI awareness. For each Vision Target it keeps an awareness meter that fills while the target is visible and falls after it is gone, three awareness levels, events, and the position where the target was last seen. It needs a Vision Source on the same object.

Vision Perception Inspector, the Events section unfolded.

How awareness works

Awareness of each target is a value from 0 to 1.

  1. While the target is visible, awareness grows. The speed depends on the distance (closer = faster), set in the Detection Profile, and is multiplied by the target's Noticeability.
  2. At Suspicious At (0.3 by default) the observer becomes suspicious. At 1 it is alerted: the target is detected.
  3. After the target is gone, awareness stays for Remember For seconds, then falls at Forget Speed.
  4. An alerted observer drops back to suspicious below Calm Down Below, and becomes unaware again when awareness falls under half of Suspicious At. Because of this gap the level does not flicker when a target steps in and out of view at the edge.

The observer also remembers each target's last known position and velocity, so your AI can go to where the target was last seen and guess where it went.

Settings

Detection

SettingDefaultDescription
ProfileEmptyThe Detection Profile with detection speed and memory. Empty = built-in defaults. New creates a profile asset and assigns it
Notices LayersEverythingOnly Vision Targets on these layers are noticed

Events

EventRaised when
On SpottedA target came into view
On SuspiciousAwareness of a target reached the suspicion level, also when an alert cools down to suspicious
On AlertedA target was fully detected
On LostA target went out of view
On CalmedAwareness of a target dropped back to unaware

Each event passes the VisionTarget it is about.

Runtime

In Play mode the Inspector shows a bar with the highest awareness and level, and a bar for each target the observer sees or remembers. In the Scene view, an observer that is suspicious or alerted shows ? or ! with its awareness in percent, and a marker at the last known position of each target it remembers.

Scripting

Namespace Renvix.VisionFog.

MemberDescription
float AlertnessHighest awareness over all targets, 0 to 1
AwarenessLevel LevelHighest level over all targets: Unaware, Suspicious or Alerted
VisionTarget PrimaryTargetThe target this observer is most aware of, or null
IReadOnlyList<TrackedTarget> TrackedTargets the observer sees now or still remembers
bool TryGetTracked(VisionTarget, out TrackedTarget)What the observer knows about one target
void GetVisibleTargets(List<VisionTarget>)Targets visible in the latest update
void ForgetAll()Clears all awareness and memory, e.g. after a respawn
DetectionProfile ProfileThe assigned profile, or the defaults
VisionSource SourceThe source this observer uses

Events in code, each with the observer and the target: Spotted, Lost, BecameSuspicious, BecameAlerted, Calmed. AlertnessChanged is raised with the observer whenever Alertness or Level changes.

TrackedTarget contains:

MemberDescription
TargetThe target
AwarenessValue (0 to 1), Level, Visible, TimeSinceSeen
IsVisibleVisible in the latest update
LastKnownPosition, LastKnownVelocityWhere the target was and how it moved when last seen
LastSeenTime, LastSeenDistanceWhen and how far away it was last seen

Example: a simple guard

using Renvix.VisionFog;
using UnityEngine;

public class Guard : MonoBehaviour
{
    VisionPerception _perception;

    void Awake() => _perception = GetComponent<VisionPerception>();

    void Update()
    {
        VisionTarget target = _perception.PrimaryTarget;
        if (target == null || !_perception.TryGetTracked(target, out var tracked))
        {
            Patrol();
            return;
        }

        switch (tracked.Awareness.Level)
        {
            case AwarenessLevel.Suspicious:
                LookAt(tracked.LastKnownPosition);
                break;
            case AwarenessLevel.Alerted:
                if (tracked.IsVisible) Chase(target.Position);
                else MoveTo(tracked.LastKnownPosition + tracked.LastKnownVelocity);
                break;
        }
    }

    void Patrol() { /* ... */ }
    void LookAt(Vector3 point) { /* ... */ }
    void Chase(Vector3 point) { /* ... */ }
    void MoveTo(Vector3 point) { /* ... */ }
}

The zombies in the demo shooter use this approach. Their full script is in Demo/Scripts/ZombieAI2D.cs.