namespace Zinnia.Data.Operation.Mutation { using System; using UnityEngine; using Zinnia.Data.Type; using Zinnia.Extension; /// /// Mutates the Euler rotation of a transform with an optional custom rotation origin. /// public class TransformEulerRotationMutator : TransformPropertyMutator { #region Rotation Settings [Header("Rotation Settings")] [Tooltip("An optional rotation origin to perform the rotation around. The origin must be a child of the TransformPropertyMutator.Target.")] [SerializeField] private GameObject origin; /// /// An optional rotation origin to perform the rotation around. The origin must be a child of the . /// public GameObject Origin { get { return origin; } set { origin = value; if (this.IsMemberChangeAllowed()) { OnAfterOriginChange(); } } } [Tooltip("Determines which axes to consider from the Origin.")] [SerializeField] private Vector3State applyOriginOnAxis = Vector3State.True; /// /// Determines which axes to consider from the . /// public Vector3State ApplyOriginOnAxis { get { return applyOriginOnAxis; } set { applyOriginOnAxis = value; } } #endregion /// /// Clears . /// public virtual void ClearOrigin() { if (!this.IsValidState()) { return; } Origin = default; } /// /// Clears . /// public virtual void ClearApplyOriginOnAxis() { if (!this.IsValidState()) { return; } ApplyOriginOnAxis = default; } /// /// Sets the x value. /// /// The value to set to. public virtual void SetApplyOriginOnAxisX(bool value) { ApplyOriginOnAxis = new Vector3State(value, ApplyOriginOnAxis.yState, ApplyOriginOnAxis.zState); } /// /// Sets the y value. /// /// The value to set to. public virtual void SetApplyOriginOnAxisY(bool value) { ApplyOriginOnAxis = new Vector3State(ApplyOriginOnAxis.xState, value, ApplyOriginOnAxis.zState); } /// /// Sets the z value. /// /// The value to set to. public virtual void SetApplyOriginOnAxisZ(bool value) { ApplyOriginOnAxis = new Vector3State(ApplyOriginOnAxis.xState, ApplyOriginOnAxis.yState, value); } /// protected override float GetGlobalAxisValue(int axis) { return Target != null ? Target.transform.eulerAngles[axis] : default; } /// protected override float GetLocalAxisValue(int axis) { return Target != null ? Target.transform.localEulerAngles[axis] : default; } /// protected override Vector3 GetNewSetValue(Vector3 input) { return input; } /// protected override Vector3 GetNewIncrementValue(Vector3 input) { if (Target == null) { return default; } return (UseLocalValues ? Target.transform.localEulerAngles : Target.transform.eulerAngles) + input; } /// protected override Vector3 SetGlobalTargetValue(Vector3 input) { if (Target == null) { return default; } Vector3 originPosition = GetOriginPosition(); Target.transform.eulerAngles = input; ApplyRotationOriginPosition(originPosition); return Target.transform.eulerAngles; } /// protected override Vector3 SetLocalTargetValue(Vector3 input) { if (Target == null) { return default; } Vector3 originPosition = GetOriginPosition(); Target.transform.localEulerAngles = input; ApplyRotationOriginPosition(originPosition); return Target.transform.localEulerAngles; } protected virtual void OnEnable() { OnAfterOriginChange(); } /// /// Returns the position if a is defined. /// /// The origin position. protected virtual Vector3 GetOriginPosition() { if (Origin == null) { return Vector3.zero; } Vector3 originAxesToApply = ApplyOriginOnAxis.ToVector3(); Vector3? cachedOriginLocalPosition = null; if (!originAxesToApply.ApproxEquals(Vector3.one)) { cachedOriginLocalPosition = Origin.transform.localPosition; originAxesToApply.Scale(Origin.transform.localPosition); Origin.transform.localPosition = originAxesToApply; } Vector3 returnValue = Origin.transform.position; if (cachedOriginLocalPosition != null) { Origin.transform.localPosition = cachedOriginLocalPosition.GetValueOrDefault(); } return returnValue; } /// /// Applies the position of the to the to ensure it rotates around the set origin. /// /// The offset position to apply. protected virtual void ApplyRotationOriginPosition(Vector3 originPosition) { if (Origin == null) { return; } originPosition -= GetOriginPosition(); Target.transform.position += originPosition; } /// /// Called after has been changed. /// protected virtual void OnAfterOriginChange() { if (Origin == null || Target == null) { return; } if (!Origin.transform.IsChildOf(Target.transform)) { throw new ArgumentException($"The `RotationOrigin` [{Origin.name}] must be a child of the `Target` [{Target.name}] GameObject."); } } [Obsolete("Use `OnAfterOriginChange` instead.")] protected virtual void OnAfterRotationOriginChange() { OnAfterOriginChange(); } } }