using System; using NodeCanvas.Framework; using ParadoxNotion.Design; using Sirenix.Utilities; using UnityEngine; using Random = UnityEngine.Random; namespace Reset.Units { [Category("Reset/Units")] [Description("Gives the unit a new direction that causes them to circle the target.")] public class CircleTarget : ActionTask{ enum StrafeDirection{ Forward = 0, Backwards, Left, Right } // References private IUnitTargetProvider targetProvider; // Pause settings [Description("How long will this unit wait to stop moving and pause")] public BBParameter pauseIntervalRange; [Description("How long this unit will within paused movement")] public BBParameter unpauseIntervalRange; // Speed settings public BBParameter speedRange; [Description("How long this unit will wait before switching movement speed")] public BBParameter speedChangeIntervalRange; [SliderField(0, 1)] public BBParameter speedSmoothing; // Strafe direction settings [Description("How long this unit will wait before switching strafe direction")] public BBParameter strafeDirectionChangeInterval; [SliderField(0, 1)] public BBParameter directionSmoothing; // Pause state management private bool strafePaused; private float lastPauseEnterTime; private float lastPauseExitTime; private float pauseChangeTimeElapsed; private float nextPauseChangeTime; // Direct state management private float lastDirectionChangeTime; private float directionChangeTimeElapsed; private StrafeDirection currentStrafeDirection; private float nextDirectionChangeTime; // Speed state management private float lastSpeedChangeTime; private float speedChangeTimeElapsed; private float currentSpeed; private float nextSpeedChangeTime; //Use for initialization. This is called only once in the lifetime of the task. //Return null if init was successfull. Return an error string otherwise protected override string OnInit() { if (pauseIntervalRange.value == Vector2.zero){ Debug.LogError($"Please set a setting for pause intervals on {agent.name}", agent.gameObject);} if (unpauseIntervalRange.value == Vector2.zero){ Debug.LogError($"Please set a setting for unpause intervals on {agent.name}", agent.gameObject);} if (speedRange.value == Vector2.zero){ Debug.LogError($"Please set a setting for speed range on {agent.name}", agent.gameObject);} if (speedChangeIntervalRange.value == Vector2.zero){ Debug.LogError($"Please set a setting for speed change intervals on {agent.name}", agent.gameObject);} if (strafeDirectionChangeInterval.value == Vector2.zero){ Debug.LogError($"Please set a setting for strafe direction change intervals on {agent.name}", agent.gameObject);} // Get reference to target provider targetProvider = agent.gameObject.GetComponent(); return null; } //This is called once each time the task is enabled. //Call EndAction() to mark the action as finished, either in success or failure. //EndAction can be called from anywhere. protected override void OnExecute(){ // Reset timers lastPauseEnterTime = 0f; lastPauseExitTime = 0f; pauseChangeTimeElapsed = 0f; lastDirectionChangeTime = 0f; directionChangeTimeElapsed = 0f; // Initialize with direction currentStrafeDirection = (StrafeDirection)Random.Range(0, 3); } //Called once per frame while the action is active. protected override void OnUpdate() { // Set a new direction agent.SetNewDirection(GetVector3Direction().ToVector2(), directionSmoothing.value, true); // Set paused or set new speed if unpaused if (strafePaused) { agent.SetNewSpeed(0f, speedSmoothing.value, true); } else { agent.SetNewSpeed(currentSpeed, speedSmoothing.value, true); } // Check the timers CheckForChange(); } // Method to quickly transform a strafe direction into a Vector3 Vector3 GetVector3Direction(){ switch (currentStrafeDirection) { case StrafeDirection.Forward: return agent.transform.position.DirectionTo(targetProvider.UnitTarget.transform.position); case StrafeDirection.Backwards: return -agent.transform.position.DirectionTo(targetProvider.UnitTarget.transform.position); case StrafeDirection.Left: return Quaternion.AngleAxis(-90f, Vector3.up) * agent.transform.position.DirectionTo(targetProvider.UnitTarget.transform.position); case StrafeDirection.Right: return Quaternion.AngleAxis(90f, Vector3.up) * agent.transform.position.DirectionTo(targetProvider.UnitTarget.transform.position); default: return Vector3.zero; } } void SetNewPauseChangeTime(){ if (strafePaused) { nextPauseChangeTime = elapsedTime + Random.Range(unpauseIntervalRange.value.x, unpauseIntervalRange.value.y); } else { nextPauseChangeTime = elapsedTime + Random.Range(pauseIntervalRange.value.x, pauseIntervalRange.value.y); } } void SetNewSpeedChangeTime(){ nextSpeedChangeTime = elapsedTime + Random.Range(speedChangeIntervalRange.value.x, speedChangeIntervalRange.value.y); } void SetNewDirectionChangeTime(){ nextDirectionChangeTime = elapsedTime + Random.Range(strafeDirectionChangeInterval.value.x, strafeDirectionChangeInterval.value.y); } void CheckForChange(){ if (nextPauseChangeTime > elapsedTime) { strafePaused = !strafePaused; SetNewPauseChangeTime(); } if (nextSpeedChangeTime > elapsedTime) { currentSpeed = Random.Range(speedRange.value.x, speedRange.value.y); SetNewSpeedChangeTime(); } if (nextDirectionChangeTime > elapsedTime) { currentStrafeDirection = (StrafeDirection)Random.Range(0, 3); SetNewDirectionChangeTime(); } } //Called when the task is disabled. protected override void OnStop() { } //Called when the task is paused. protected override void OnPause() { } } }