Virtual sensors adapted from real world sensors

Good day,

I am trying to build a virtual smart home with virtual sensors that mimic the real world sensors. I need ideas on how I can formulate a wearable sensor to listen for movement of an avatar in the game environment. I need help with how I can perform handling the logic for listening for movement of a particular object.

Below is the schematic of another sensor for motion that has already been implemented. It requires a component called Field Of View which I will show below. It inherits its type form a class called Poll sensor which I will also show below.


/* this is a motion sensor which is just placed in the home*/
using UnityEngine;
[RequireComponent (typeof(FieldOfView))]
public class MotionSensor : PollSensor {

    [Header("Motion Sensor Attributes")]
    public FieldOfView SensorFOVComponent;
    [ReadOnly] public bool CurrentSensorValue = false;
    private bool PreviousSensorValue = false;                   

    public delegate void OnMotionDetectedDelegate();
    public event OnMotionDetectedDelegate OnMotionDetected;

    protected override void Start()
    {
        // Init
        base.Start();
        TypeOfSensor = SensorType.Motion;
        if (SettingsManager.Instance.PollMotionSensorsOnStart)
            StartPollCycle();
    }

    protected override void Poll()
    {
        CurrentSensorValue = ObtainSensorValue();

        if (MotionHasBeenDetected())
        {
            // Let listeners know of the motion occurance
            if (OnMotionDetected != null)
                OnMotionDetected();

            ObtainSensorReadingAndPublishToSensorStream();
        }
    }

    protected override void ObtainSensorReadingAndPublishToSensorStream()
    {
        PublishSensorReadingToSensorStream(GenerateBaseSensorReading());
    }

    private bool MotionHasBeenDetected()
    {
        /*
         * This is to mimic the behaviour of a PIR motion sensor.
         * 
         * Raw data seems to only be published ONCE detecting a
         * target if there previously wasn't a target within FOV.
         * 
         * It looks like this from my perspective:
         * - if from True -> True, then nothing
         * - if from False -> False, then nothing
         * - if from True -> False, then nothing
         * * if from False -> True, then publish (i.e true)
         * 
         * Lastly, make sure to reference the previous value
         */ 

        if (CurrentSensorValue)
        {
            if (!PreviousSensorValue)
            {
                PreviousSensorValue = CurrentSensorValue;
                return true;
            }
        }  

        PreviousSensorValue = CurrentSensorValue;
        return false;
    }

    private bool ObtainSensorValue()
    {
        if (SensorFOVComponent)
            return SensorFOVComponent.AreThereTargetsInFOV();
        else
        {
            Debug.LogError(SensorName + ": FOV Component missing.");
            return false;
        }
    }
}
`

Below is the field of view component snippet:

using System.Collections.Generic;
using UnityEngine;

public class FieldOfView : MonoBehaviour {

    [Header("Basic FOV Attributes")]
    public float PollRate = 2f;             // Timer for rate at which voxels are identifiied in FOV
    public float FOVRadius;                // Length from centre of Game Object, for defining FOV size
    [Range(0, 180)]
    public float ConeAngle;                 // Angle defining the cone for valid detection of targets
    public LayerMask TargetMask;            // Layer mask for detecting the target
    public LayerMask ObstacleMask;          // Layer mask for detecting obstacles

    [HideInInspector]
    public List<Transform> AllTargets = 
        new List<Transform>();              // List of all targets within FOV
    [HideInInspector]
    public List<Transform> VisibleTargets 
        = new List<Transform>();            // List of visible targets within FOV

    public bool AreThereTargetsInFOV()
    {
        // Obtain targets, filter vs. obstacles
        GetTargetsInFOV(AllTargets);
        FilterTargetsFromObstacles(AllTargets, VisibleTargets);

        return AllTargets.Count > 0;
    }
    
    void GetTargetsInFOV(List<Transform> targetsInFOV)
    {
        targetsInFOV.Clear();

        // Detect all collisions within a sphere from the sensor position
        Collider[] colliders = Physics.OverlapSphere(transform.position, FOVRadius, TargetMask);

        // Iterate through all targets in radius
        for (int x = 0; x < colliders.Length; x++)
        {
            // Calculate the angle between the two vectors
            Vector3 sensorToVoxel = colliders[x].gameObject.transform.position - transform.position;
            Vector3 sensorForward = transform.forward;
            float angleBetweenTheVectors = Vector3.Angle(sensorToVoxel, sensorForward);

            // Is it within the cone radius specified? Add it to the list
            if (angleBetweenTheVectors <= ConeAngle)
                targetsInFOV.Add(colliders[x].gameObject.transform);
        }
    }

    /// <summary>
    /// Filters targets that are not 'visible' using the obstacle mask.
    /// </summary>
    /// <param name="allTargets">List of the transform components of target game objects</param>
    /// <param name="visibleTargets">Filtered list of the transform components of target game objects</param>
    void FilterTargetsFromObstacles(List<Transform> allTargets, List<Transform> visibleTargets)
    {
        visibleTargets.Clear();

        // Iterate through all targets in FOV
        foreach (Transform aTarget in allTargets)
        {
            // Shoot ray from current position to target, check if it DOESN'T hit an obstacle
            if (!Physics.Linecast(transform.position, aTarget.position, ObstacleMask))

                // Since did not hit an obstacle, add to visible list
                visibleTargets.Add(aTarget);
        }
    }

Here are is the Poll sensor abstract class

public abstract class PollSensor : Sensor {

    [Header("Poll Sensor Attributes")]
    public float SensorPollRate = 0.5f;   // Rate at which sensor readings are polled

    protected override void Start()
    {
        ClassOfSensor = SensorClass.Poll;
    }

    /// <summary>
    /// 
    /// Method that handles collection/calculation of sensor readings and
    /// publishing of sensor readings to sensor streams (through calling 
    /// associated method).
    /// 
    /// </summary>
    protected virtual void Poll()
    {
        // may or may not be implemented by deriving class
    }

    /// <summary>
    /// 
    /// Public access method for initiating periodic poll callbacks.
    /// 
    /// </summary>
    public virtual void StartPollCycle()
    {
        // may or may not be implemented by deriving class
        try
        {
            InvokeRepeating("Poll", 0f,
                TimeController.Instance.ScaleSecondsToSimulationTime(SensorPollRate));
        }
        catch (System.Exception)
        {
            Debug.LogError(TypeOfSensor.ToString() + ": " + SensorName + " - TimeController not defined.");
        }
    }

    /// <summary>
    /// 
    /// Public access method for stopping periodic poll callbacks.
    /// 
    /// </summary>
    public virtual void StopPollCycle()
    {
        // may or may not be implemented by deriving class
        CancelInvoke("Poll");
    }

    public virtual void TogglePolling(bool startPoll)
    {
        // may or may not be implemented by deriving class
        if (startPoll)
            StartPollCycle();
        else
            StopPollCycle();
    }
}

First, I would use triggers to detect if the avatar is close enough to a sensor to activate it. it should then track it’s position and by calculating the frame delta you will know if it moved.

nice code thanks