/// --------------------------------------------- /// Movement Pack for Behavior Designer Pro /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.BehaviorDesigner.AddOns.MovementPack.Runtime.Tasks { using Opsive.BehaviorDesigner.Runtime.Tasks; using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; using Opsive.GraphDesigner.Runtime; using Opsive.GraphDesigner.Runtime.Variables; using UnityEngine; [Opsive.Shared.Utility.Description("Rotates towards the target rotation using Quaternion.RotateTowards. The rotation can either be specified by a Transform or rotation. " + "If the Transform is used then the rotation will not be used.")] [NodeIcon("b3a51997594f86c4e87b5b7f2044b96d", "8d266206744b431478023101189e616b")] public class RotateTowards : Action { [Tooltip("Is the agent rotating in 2D?")] [SerializeField] protected bool m_Use2DPhysics; [Tooltip("Should the angular speed be used instead of the maximum rotation delta?")] [SerializeField] protected bool m_UseAngularSpeed; [Tooltip("The maximum number of angles the agent can rotate in a single tick (in degrees).")] [SerializeField] protected SharedVariable m_MaxRotationDelta = 1; [Tooltip("The angular speed of the agent (in degrees per second).")] [SerializeField] protected SharedVariable m_AngularSpeed = 90f; [Tooltip("Specifies the angle when the agent has arrived at the target rotation (in degrees).")] [SerializeField] protected SharedVariable m_ArrivedAngle = 0.5f; [Tooltip("Should the rotation only affect the Y axis?")] [SerializeField] protected SharedVariable m_OnlyY = true; [Tooltip("The GameObject that the agent is rotating towards.")] [SerializeField] protected SharedVariable m_Target; [Tooltip("If target is null then use the target rotation.")] [SerializeField] protected SharedVariable m_TargetRotation; /// /// Rotates towards the target. /// /// Success when the agent has rotated towards the target. public override TaskStatus OnUpdate() { var targetRotation = GetTargetRotation(); // Return a task status of success once the agent is done rotating. if (Quaternion.Angle(transform.rotation, targetRotation) < m_ArrivedAngle.Value) { return TaskStatus.Success; } // Keep rotating towards the target. if (!m_UseAngularSpeed) { transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, m_MaxRotationDelta.Value); } else { transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, m_AngularSpeed.Value * Time.deltaTime); } return TaskStatus.Running; } /// /// Returns the target rotation. /// /// The target rotation. private Quaternion GetTargetRotation() { if (m_Target.Value == null) { return Quaternion.Euler(m_TargetRotation.Value); } var direction = m_Target.Value.transform.position - transform.position; if (m_OnlyY.Value) { direction.y = 0; } if (m_Use2DPhysics) { var angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; return Quaternion.AngleAxis(angle, Vector3.forward); } return Quaternion.LookRotation(direction); } /// /// Resets the task values back to their default. /// public override void Reset() { base.Reset(); m_Use2DPhysics = false; m_UseAngularSpeed = false; m_MaxRotationDelta = 1; m_AngularSpeed = 90f; m_ArrivedAngle = 0.5f; m_OnlyY = true; m_Target = null; m_TargetRotation = Vector3.zero; } } }