namespace Zinnia.Action
{
using UnityEngine;
using Zinnia.Data.Type;
using Zinnia.Extension;
///
/// Emits a value when the received current position and previous position exceed the specified distance.
///
public class SurfaceChangeAction : BooleanAction
{
[Tooltip("The distance between the current surface and previous surface to consider a valid change.")]
[SerializeField]
private float changeDistance = 0.5f;
///
/// The distance between the current surface and previous surface to consider a valid change.
///
public float ChangeDistance
{
get
{
return changeDistance;
}
set
{
changeDistance = value;
if (this.IsMemberChangeAllowed())
{
OnAfterChangeDistanceChange();
}
}
}
[Tooltip("The axes to check for distance differences on.")]
[SerializeField]
private Vector3State checkAxis = Vector3State.True;
///
/// The axes to check for distance differences on.
///
public Vector3State CheckAxis
{
get
{
return checkAxis;
}
set
{
checkAxis = value;
if (this.IsMemberChangeAllowed())
{
OnAfterCheckAxisChange();
}
}
}
protected SurfaceData previousData;
///
/// Sets the x value.
///
/// The value to set to.
public virtual void SetCheckAxisX(bool value)
{
CheckAxis = new Vector3State(value, CheckAxis.yState, CheckAxis.zState);
}
///
/// Sets the y value.
///
/// The value to set to.
public virtual void SetCheckAxisY(bool value)
{
CheckAxis = new Vector3State(CheckAxis.xState, value, CheckAxis.zState);
}
///
/// Sets the z value.
///
/// The value to set to.
public virtual void SetCheckAxisZ(bool value)
{
CheckAxis = new Vector3State(CheckAxis.xState, CheckAxis.yState, value);
}
///
/// Digests and compares the current surface to the previous surface to determine if a change has occurred.
///
/// The to check on.
public virtual void Receive(SurfaceData surfaceData)
{
if (!this.IsValidState() || !ValidSurfaceData(surfaceData))
{
return;
}
Vector3 generatedOrigin = GetCollisionPoint(surfaceData.PreviousCollisionData, surfaceData.PositionalOffset);
Vector3 generatedTarget = GeneratePoint(surfaceData.Position, Vector3.zero);
bool result = !generatedOrigin.ApproxEquals(generatedTarget, ChangeDistance);
Receive(result);
previousData = surfaceData;
}
///
/// Checks to see if the given is valid.
///
/// The to check on.
/// if the given is valid.
protected virtual bool ValidSurfaceData(SurfaceData surfaceData)
{
return surfaceData != null && surfaceData.IsValid;
}
///
/// Attempts to get the collision point for the given data.
///
/// The data to get the collision point from.
/// The positional offset to apply.
/// The collision point.
protected virtual Vector3 GetCollisionPoint(RaycastHit collisionData, Vector3 offset)
{
return collisionData.transform != null ? GeneratePoint(collisionData.point, offset) : Vector3.zero;
}
///
/// Creates a based on the given point for the valid axes.
///
/// The Point to generate the from.
/// The positional offset to apply.
/// The point only within the valid axes.
protected virtual Vector3 GeneratePoint(Vector3 point, Vector3 offset)
{
float resultX = CheckAxis.xState ? point.x + offset.x : 0f;
float resultY = CheckAxis.yState ? point.y + offset.y : 0f;
float resultZ = CheckAxis.zState ? point.z + offset.z : 0f;
return new Vector3(resultX, resultY, resultZ);
}
///
/// Called after has been changed.
///
protected virtual void OnAfterChangeDistanceChange()
{
if (previousData != null)
{
Receive(previousData);
}
}
///
/// Called after has been changed.
///
protected virtual void OnAfterCheckAxisChange()
{
if (previousData != null)
{
Receive(previousData);
}
}
}
}