namespace Zinnia.Tracking.Query
{
using UnityEngine;
using UnityEngine.Events;
using Zinnia.Extension;
using Zinnia.Process;
///
/// Determines whether a faces (through the local forward direction) another .
///
///
/// No physics checks are done and as such occlusion isn't part of the information gained by this component.
///
public class FacingQuery : MonoBehaviour, IProcessable
{
[Tooltip("The object used as the origin to check if it is facing towards Target.")]
[SerializeField]
private GameObject source;
///
/// The object used as the origin to check if it is facing towards .
///
public GameObject Source
{
get
{
return source;
}
set
{
source = value;
}
}
[Tooltip("The object that will be checked to see if Source is facing it.")]
[SerializeField]
private GameObject target;
///
/// The object that will be checked to see if is facing it.
///
public GameObject Target
{
get
{
return target;
}
set
{
target = value;
}
}
[Tooltip("A sphere radius that defines the volume in which Target can still be considered seen by the Source.")]
[SerializeField]
private float targetRadius = 0.1f;
///
/// A sphere radius that defines the volume in which can still be considered seen by the .
///
public float TargetRadius
{
get
{
return targetRadius;
}
set
{
targetRadius = value;
}
}
///
/// Emitted when is facing .
///
public UnityEvent TargetFaced = new UnityEvent();
///
/// Emitted when no longer faces .
///
public UnityEvent TargetNotFaced = new UnityEvent();
///
/// Whether was previously facing .
///
protected bool? wasPreviouslyFacing;
///
/// Clears .
///
public virtual void ClearSource()
{
if (!this.IsValidState())
{
return;
}
Source = default;
}
///
/// Clears .
///
public virtual void ClearTarget()
{
if (!this.IsValidState())
{
return;
}
Target = default;
}
///
/// Determines whether is facing defined by its position and .
///
public virtual void Process()
{
Vector3 sourcePosition = Source.transform.position;
Vector3 targetPosition = Target.transform.position;
float distance = Vector3.Distance(targetPosition, sourcePosition);
Vector3 glancePoint = sourcePosition + (Source.transform.forward * distance);
bool isFacing = Vector3.Distance(targetPosition, glancePoint) <= TargetRadius;
if (isFacing == wasPreviouslyFacing)
{
return;
}
wasPreviouslyFacing = isFacing;
if (isFacing)
{
TargetFaced?.Invoke();
}
else
{
TargetNotFaced?.Invoke();
}
}
protected virtual void OnDisable()
{
wasPreviouslyFacing = null;
}
}
}