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); } } } }