Files
SoulliesOfficial ef7b479712 initial
2025-11-25 08:19:33 -05:00

154 lines
6.1 KiB
C#

/// ---------------------------------------------
/// 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.Utility;
using Opsive.GraphDesigner.Runtime;
using Opsive.GraphDesigner.Runtime.Variables;
using System;
using Unity.Entities;
using UnityEngine;
[Opsive.Shared.Utility.Description("Patrols around the specified waypoints.")]
[NodeIcon("6f82a4685e473054986cedbfb24bf8bd", "ed44a06209d60e943819270678e69b89")]
public class Patrol : MovementBase
{
[Tooltip("The waypoints that the agent should move between.")]
[SerializeField] protected SharedVariable<GameObject[]> m_Waypoints;
[Tooltip("Should the agent start patrolling to the closest waypoint?")]
[SerializeField] protected SharedVariable<bool> m_ClosestWaypointStart;
[Tooltip("Should the agent patrol the waypoints randomly?")]
[SerializeField] protected SharedVariable<bool> m_RandomPatrol;
[Tooltip("The length of time that the agent should pause when arriving at a waypoint.")]
[SerializeField] protected SharedVariable<RangeFloat> m_WaypointPauseDuration;
private int m_Index;
private float m_NextDestinationTime;
// Callback when the agent arrives at a waypoint.
public Action<GameObject> OnWaypointArrival { get; set; }
/// <summary>
/// The task has started.
/// </summary>
public override void OnStart()
{
base.OnStart();
if (m_RandomPatrol.Value) {
m_Index = UnityEngine.Random.Range(0, m_Waypoints.Value.Length);
} else if (m_ClosestWaypointStart.Value) {
// Move towards the closest waypoint at the start.
var distance = Mathf.Infinity;
float localDistance;
for (int i = 0; i < m_Waypoints.Value.Length; ++i) {
if ((localDistance = Vector3.SqrMagnitude(transform.position - m_Waypoints.Value[i].transform.position)) < distance) {
distance = localDistance;
m_Index = i;
}
}
}
m_NextDestinationTime = -1;
SetDestination(GetTargetDestination());
}
/// <summary>
/// Returns the target destination.
/// </summary>
/// <returns>The target destination.</returns>
private Vector3 GetTargetDestination()
{
if (m_Index >= m_Waypoints.Value.Length) {
return transform.position;
}
return m_Waypoints.Value[m_Index].transform.position;
}
/// <summary>
/// Patrol around the different waypoints specified in the waypoint array.
/// </summary>
/// <returns>Always returns a status of running. </returns>
public override TaskStatus OnUpdate()
{
if (m_Waypoints.Value.Length == 0) {
return TaskStatus.Failure;
}
if (HasArrived()) {
if (m_NextDestinationTime == -1) {
m_NextDestinationTime = Time.time + m_WaypointPauseDuration.Value.RandomValue;
// Others may be interested when the agent arrives at a waypoint.
OnWaypointArrival?.Invoke(m_Waypoints.Value[m_Index]);
}
// Wait the required duration before switching waypoints.
if (m_NextDestinationTime <= Time.time) {
if (m_RandomPatrol.Value) {
if (m_Waypoints.Value.Length == 1) {
m_Index = 0;
} else {
// Prevent the same waypoint from being selected.
var nextIndex = m_Index;
while (nextIndex == m_Index) {
nextIndex = UnityEngine.Random.Range(0, m_Waypoints.Value.Length);
}
m_Index = nextIndex;
}
} else {
m_Index = (m_Index + 1) % m_Waypoints.Value.Length;
}
SetDestination(GetTargetDestination());
m_NextDestinationTime = -1;
}
}
return TaskStatus.Running;
}
/// <summary>
/// Returns the current task state.
/// </summary>
/// <param name="world">The DOTS world.</param>
/// <param name="entity">The DOTS entity.</param>
/// <returns>The current task state.</returns>
public override object Save(World world, Entity entity)
{
var saveData = new object[3];
saveData[0] = base.Save(world, entity);
saveData[1] = m_Index;
saveData[2] = Time.time - m_NextDestinationTime;
return saveData;
}
/// <summary>
/// Loads the previous task state.
/// </summary>
/// <param name="saveData">The previous task state.</param>
/// <param name="world">The DOTS world.</param>
/// <param name="entity">The DOTS entity.</param>
public override void Load(object saveData, World world, Entity entity)
{
var saveDataArray = (object[])saveData;
base.Load(saveDataArray[0], world, entity);
m_Index = (int)saveDataArray[1];
m_NextDestinationTime = Time.time - (float)saveDataArray[1];
}
/// <summary>
/// Resets the task values back to their default.
/// </summary>
public override void Reset()
{
base.Reset();
m_Waypoints = new GameObject[0];
m_ClosestWaypointStart = false;
m_RandomPatrol = false;
m_WaypointPauseDuration = new RangeFloat();
}
}
}