91 lines
3.9 KiB
C#
Raw Normal View History

using UnityEngine;
namespace BehaviorDesigner.Runtime.Tasks.Movement
{
[TaskDescription("Queue in a line using the Unity NavMesh.")]
[TaskCategory("Movement")]
[HelpURL("https://www.opsive.com/support/documentation/behavior-designer-movement-pack/")]
[TaskIcon("Assets/Behavior Designer Movement/Editor/Icons/{SkinColor}QueueIcon.png")]
public class Queue : NavMeshGroupMovement
{
[Tooltip("Agents less than this distance apart are neighbors")]
public SharedFloat neighborDistance = 10;
[Tooltip("The distance that the agents should be separated")]
public SharedFloat separationDistance = 2;
[Tooltip("The distance the the agent should look ahead to see if another agent is in the way")]
public SharedFloat maxQueueAheadDistance = 2;
[Tooltip("The radius that the agent should check to see if another agent is in the way")]
public SharedFloat maxQueueRadius = 20;
[Tooltip("The multiplier to slow down if an agent is in front of the current agent")]
public SharedFloat slowDownSpeed = 0.15f;
[Tooltip("The target to seek towards")]
public SharedGameObject target;
// The agents will always be flocking so always return running
public override TaskStatus OnUpdate()
{
// Determine a destination for each agent
for (int i = 0; i < agents.Length; ++i) {
if (AgentAhead(i)) {
SetDestination(i, transforms[i].position + transforms[i].forward * slowDownSpeed.Value + DetermineSeparation(i));
} else {
SetDestination(i, target.Value.transform.position);
}
}
return TaskStatus.Running;
}
// Returns the agent that is ahead of the current agent
private bool AgentAhead(int index)
{
// queueAhead is the distance in front of the current agent
var queueAhead = Velocity(index) * maxQueueAheadDistance.Value;
for (int i = 0; i < agents.Length; ++i) {
// Return the first agent that is ahead of the current agent
if (index != i && Vector3.SqrMagnitude(queueAhead - transforms[i].position) < maxQueueRadius.Value) {
return true;
}
}
return false;
}
// Determine the separation between the current agent and all of the other agents also queuing
private Vector3 DetermineSeparation(int agentIndex)
{
var separation = Vector3.zero;
int neighborCount = 0;
var agentTransform = transforms[agentIndex];
// Loop through each agent to determine the separation
for (int i = 0; i < agents.Length; ++i) {
// The agent can't compare against itself
if (agentIndex != i) {
// Only determine the parameters if the other agent is its neighbor
if (Vector3.SqrMagnitude(transforms[i].position - agentTransform.position) < neighborDistance.Value) {
// This agent is the neighbor of the original agent so add the separation
separation += transforms[i].position - agentTransform.position;
neighborCount++;
}
}
}
// Don't move if there are no neighbors
if (neighborCount == 0) {
return Vector3.zero;
}
// Normalize the value
return ((separation / neighborCount) * -1).normalized * separationDistance.Value;
}
// Reset the public variables
public override void OnReset()
{
base.OnReset();
neighborDistance = 10;
separationDistance = 2;
maxQueueAheadDistance = 2;
maxQueueRadius = 20;
slowDownSpeed = 0.15f;
}
}
}