using System.Collections; using RPGCore.ObjectModules.ActionObjectModule; using RPGCore.StatusEffect.ObjectModules.StatusObjectModule; using UnityEngine; namespace RPGCore.Movement.ObjectModules.UnitMovement.Actions { public class RotateAction : BaseActionParallel { private Coroutine _rotateCoroutine; private readonly bool _isEndless; private float _targetYaw; private readonly float _rotationSpeed; private readonly bool _isForced; public RotateAction(float rotationSpeed = 0) { _isEndless = true; _rotationSpeed = rotationSpeed; } public RotateAction(float targetYaw, float rotationSpeed = 0, bool isForced = false) { _targetYaw = targetYaw; _rotationSpeed = rotationSpeed; _isForced = isForced; } public RotateAction(Vector3 lookAt, float rotationSpeed = 0, bool isForced = false) { _targetYaw = Quaternion.LookRotation(lookAt - unit.transform.position).eulerAngles.y; _rotationSpeed = rotationSpeed; _isForced = isForced; } public void SetYaw(float targetYaw) { if (!_isEndless) { Debug.LogWarning($"Usage {nameof(SetYaw)} available only when rotating is endless."); return; } _targetYaw = targetYaw; } public override bool IsInRange() => true; public override void CanDoIt() { Check( _isForced || unit.GetComponent().IsControllable(), UnitIsBusyMessage); } protected override void OnDoIt() { BeforePerform(); // Instant rotation if (_rotationSpeed <= 0) { Rotate(_targetYaw); AfterPerform(); EndIt(); return; } // Endless rotation if (_isEndless) { _rotateCoroutine = unit.StartCoroutine(RotationEndlessCoroutine()); return; } // Simple rotation to given yaw _rotateCoroutine = unit.StartCoroutine(RotationCoroutine()); } private IEnumerator RotationCoroutine() { while (Mathf.Approximately(unit.transform.rotation.eulerAngles.y, _targetYaw) == false) { var deltaYaw = Mathf.DeltaAngle(unit.rigidbody.rotation.eulerAngles.y, _targetYaw); var deltaYawClamped = Mathf.Sign(deltaYaw) * Mathf.Clamp(Mathf.Abs(deltaYaw), 0, Time.fixedDeltaTime * _rotationSpeed); Rotate(unit.rigidbody.rotation.eulerAngles.y + deltaYawClamped); yield return new WaitForFixedUpdate(); } AfterPerform(); EndIt(); } private IEnumerator RotationEndlessCoroutine() { while (state is ActionState.Running) { var deltaYaw = Mathf.DeltaAngle(unit.rigidbody.rotation.eulerAngles.y, _targetYaw); var deltaYawClamped = Mathf.Sign(deltaYaw) * Mathf.Clamp(Mathf.Abs(deltaYaw), 0, Time.fixedDeltaTime * _rotationSpeed); Rotate(unit.rigidbody.rotation.eulerAngles.y + deltaYawClamped); yield return new WaitForFixedUpdate(); } } private void Rotate(float yaw) { var targetRotation = unit.transform.rotation.eulerAngles; targetRotation.y = yaw; unit.rigidbody.MoveRotation(Quaternion.Euler(targetRotation)); } protected override void OnEndIt() { } protected override void OnCancelIt() { if (_rotateCoroutine != null) unit.StopCoroutine(_rotateCoroutine); } } }