Please find attached a screenshot of the hierarchy.
SGEnvironment is the play environment.
Staff members is an empty GameObject that holds the assistants’ characters. Each Assistant has 4 components: its Transform, a capsule collider, a navmeshagent and a rigidbody.
Dependent patients is an empty GameObject that holds the patients to assist. Each patient has 6 components (see the attached picture : PatientComponents). The attached script called Patient is as follow:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Patient : MonoBehaviour
{
[Header("Physical profile")]
[Tooltip("Patient walking speed in m/s")]
[Range(0, 10)]
public float patientSpeed = 1;
//patient preparation time
public float preparationTime;
//patient attachment points
public GameObject[] attachmentPoints;
public EditorPathScript PathToFollow;
}
Emergency Groups is an empty Gameobject which holds EmergencyGroups (composed of multiple assistants). For example EG2 (see the third picture attached) is composed of 4 assistants, and has to assist 3 patients with a specific triage order.
The EmergencyGroupClass script is as follow :
using UnityEngine;
using UnityEngine.AI;
using System;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class emergencyGroupProfile
{
[Tooltip("Emergency group name")]
public string name;
[Tooltip("Emergency group description")]
public string description;
[Tooltip("Assistants")]
public List<GameObject> assistants = new List<GameObject>();
[Tooltip("Patients in need of assistance (e.g. people with reduced mobility)")]
public List<GameObject> assistedPatients = new List<GameObject>();
[Header("Triage approach")]
[Tooltip("No priority - Agents are assisted considering the distance to the attendants")]
public bool dstToAttendant = false;
[Tooltip("Agents in immediate danger are evacuated first, followed by those requiring the minimum assistance and then the agent with higher dependency level")]
public bool levelOfDependency = false;
[Tooltip("Priority is specified by the user")]
public bool userDefined = false;
[Tooltip("Triage order if defined by the user")]
public List<GameObject> triageOrder = new List<GameObject>();
}
public class EmergencyGroupsClass : MonoBehaviour
{
public emergencyGroupProfile emergencyGroupProfile;
public GameObject staffMembers = null;
private GameObject[] AttachmentPoints;
private float[] preparationTimes;
private bool gatheringPhaseFinished = false;
private bool attachmentPhaseFinished = false;
private float[] DistancesToAttachmentPoint;
private NavMeshAgent[] AssistantsNavMeshAgents;
private NavMeshPath[] AssistantsNavMeshPaths;
private CapsuleCollider[] AssistantsCapsuleColliders;
private BoxCollider[] patientsBoxColliders;
private int index = 0;
//The path to follow during the movement phase
public EditorPathScript PathToFollow;
public int CurrentWayPointID = 0;
private float arriveDistance = 0.5f;
//public string pathName;
private Vector3 lastPosition;
private Vector3 currentPosition;
//
public GameObject nearestExit;
private float dist;
private float timeTakenByAssistants;
private float farthestDist = 0f;
private float longestTime = 0f;
private GameObject farthestAgent = null;
private GameObject farthestAgentAttachmentPoint = null;
private Vector3 NextPatientInitialPosition;
private Quaternion NextPatientInitialRotation;
void Awake()
{
preparationTimes = new float[emergencyGroupProfile.triageOrder.Count];
AssistantsNavMeshAgents = new NavMeshAgent[emergencyGroupProfile.assistants.Count];
AssistantsNavMeshPaths = new NavMeshPath[emergencyGroupProfile.assistants.Count];
AssistantsCapsuleColliders = new CapsuleCollider[AssistantsNavMeshAgents.Length];
patientsBoxColliders = new BoxCollider[emergencyGroupProfile.assistedPatients.Count];
for (int i = 0; i < emergencyGroupProfile.triageOrder.Count; i++)
preparationTimes[i] = emergencyGroupProfile.triageOrder[i].GetComponent<Patient>().preparationTime;
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
AssistantsNavMeshAgents[i] = emergencyGroupProfile.assistants[i].GetComponent<NavMeshAgent>();
AssistantsNavMeshPaths[i] = new NavMeshPath();
}
}
void Update()
{
//Debug.Log(emergencyGroupProfile.triageOrder.Count);
if (index < emergencyGroupProfile.triageOrder.Count)
{
//Debug.Log(index);
PathToFollow = emergencyGroupProfile.triageOrder[index].GetComponent<Patient>().PathToFollow;
AttachmentPoints = new GameObject[emergencyGroupProfile.triageOrder[index].GetComponent<Patient>().attachmentPoints.Length];
AttachmentPoints = emergencyGroupProfile.triageOrder[index].GetComponent<Patient>().attachmentPoints;
DistancesToAttachmentPoint = new float[AttachmentPoints.Length];
if (!gatheringPhaseFinished)
{
gatheringPhase();
}
else if (!attachmentPhaseFinished)
{
attachmentPhase();
}
else
{
//preparation phase
StartCoroutine(preparationPhase());
}
}
/*else
{
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
float Distance = Vector3.Distance(AssistantsNavMeshAgents[i].transform.position, nearestExit.transform.position);
AssistantsNavMeshAgents[i].destination = nearestExit.transform.position;
if (Distance < AssistantsNavMeshAgents[i].stoppingDistance + 0.01f)
{
AssistantsNavMeshAgents[i].gameObject.SetActive(false);
Debug.Log(AssistantsNavMeshAgents[i].gameObject.name + " Exit time = " + Time.realtimeSinceStartup + " s");
}
}
return;
}*/
}
private bool gatheringPhase()
{
//Debug.Log("Gathering Phase started");
//float dist;
//float farthestDist = 0;
//GameObject farthestAgent = null;
//GameObject farthestAgentAttachmentPoint = null;
NextPatientInitialPosition=emergencyGroupProfile.triageOrder[index+1].transform.position;
NextPatientInitialRotation = emergencyGroupProfile.triageOrder[index + 1].transform.rotation;
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
if (AssistantsNavMeshAgents[i].enabled)
{
AssistantsNavMeshAgents[i].CalculatePath(AttachmentPoints[i].transform.position, AssistantsNavMeshPaths[i]);
}
emergencyGroupProfile.assistants[i].GetComponent<Collider>().enabled = true;
}
bool rotationFinished = false;
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
//DistancesToAttachmentPoint[i] = AssistantsNavMeshAgents[i].remainingDistance;
DistancesToAttachmentPoint[i] = CalculatePathLength(AttachmentPoints[i].transform.position, AssistantsNavMeshPaths[i]);
//DistancesToAttachmentPoint[i] = Vector3.Distance(AssistantsNavMeshAgents[i].transform.position, AttachmentPoints[i].transform.position);
dist = DistancesToAttachmentPoint[i];
timeTakenByAssistants = DistancesToAttachmentPoint[i] / AssistantsNavMeshAgents[i].speed;
if (timeTakenByAssistants > longestTime)
{
farthestDist = dist;
longestTime = timeTakenByAssistants;
farthestAgent = AssistantsNavMeshAgents[i].gameObject;
farthestAgentAttachmentPoint = AttachmentPoints[i].gameObject;
//Debug.Log(farthestDist);
}
Debug.Log(farthestAgent.name);
AssistantsNavMeshAgents[i].destination = AttachmentPoints[i].transform.position;
}
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
if (HasArrived(AssistantsNavMeshAgents[i]))
{
emergencyGroupProfile.assistants[i].transform.rotation = Quaternion.RotateTowards(emergencyGroupProfile.assistants[i].transform.rotation,
AttachmentPoints[i].transform.rotation, AssistantsNavMeshAgents[i].angularSpeed * Time.deltaTime);
}
}
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
float fartestAgentLocalAngle;
fartestAgentLocalAngle = farthestAgent.gameObject.transform.localEulerAngles.y;
float fartestAgentAttachmentPointLocalAngle;
fartestAgentAttachmentPointLocalAngle = farthestAgentAttachmentPoint.gameObject.transform.parent.gameObject.transform.eulerAngles.y;
//Debug.Log(dist);
dist = Vector3.Distance(AssistantsNavMeshAgents[i].transform.position, AttachmentPoints[i].transform.position);
if (dist <= AssistantsNavMeshAgents[i].stoppingDistance + 0.1f)
{
//Debug.Log(farthestAgent.gameObject.transform.localEulerAngles.y);
//Debug.Log(farthestAgentAttachmentPoint.gameObject.transform.parent.transform.eulerAngles.y);
float anglesDiff = Mathf.Abs(fartestAgentLocalAngle) - Mathf.Abs(fartestAgentAttachmentPointLocalAngle);
//Debug.Log(anglesDiff);
if (Mathf.Abs(fartestAgentLocalAngle - fartestAgentAttachmentPointLocalAngle) <= 1f )
{
Debug.Log("Gathering Phase Finished");
rotationFinished = true;
}
}
}
//Debug.Log(rotationFinished);
if (rotationFinished)
{
return gatheringPhaseFinished = true;
}
return gatheringPhaseFinished = false;
}
private bool attachmentPhase()
{
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
emergencyGroupProfile.assistants[i].transform.parent = AttachmentPoints[i].transform ;
//emergencyGroupProfile.assistants[i].transform.position = AttachmentPoints[i].transform.position;
//emergencyGroupProfile.assistants[i].transform.rotation = AttachmentPoints[i].transform.rotation;
AssistantsNavMeshAgents[i].enabled = false;
}
//Debug.Log("Attachment Phase Finished");
return attachmentPhaseFinished = true;
}
private IEnumerator preparationPhase()
{
//Debug.Log(index);
//Debug.Log("Preparation Phase Started");
yield return new WaitForSeconds(emergencyGroupProfile.triageOrder[index].GetComponent<Patient>().preparationTime);
//movement phase
movementPhase();
}
private void movementPhase()
{
//emergencyGroupProfile.triageOrder[index].GetComponent<NavMeshObstacle>().enabled = false;
// emergencyGroupProfile.triageOrder[index].GetComponent<NavMeshAgent>().enabled = true;
//Debug.Log("Mouvement Phase Started");
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
emergencyGroupProfile.assistants[i].GetComponent<Collider>().enabled = false;
}
lastPosition = emergencyGroupProfile.triageOrder[index].gameObject.transform.position;
float distance = Vector3.Distance(PathToFollow.pathObjs[CurrentWayPointID].position, emergencyGroupProfile.triageOrder[index].gameObject.transform.position);
emergencyGroupProfile.triageOrder[index].gameObject.transform.position = Vector3.MoveTowards(emergencyGroupProfile.triageOrder[index].gameObject.transform.position, PathToFollow.pathObjs[CurrentWayPointID].position, Time.deltaTime * emergencyGroupProfile.triageOrder[index].gameObject.GetComponent<NavMeshAgent>().speed);
var rotation = Quaternion.LookRotation(PathToFollow.pathObjs[CurrentWayPointID].position - emergencyGroupProfile.triageOrder[index].transform.position);
emergencyGroupProfile.triageOrder[index].gameObject.transform.rotation = Quaternion.Slerp(emergencyGroupProfile.triageOrder[index].gameObject.transform.rotation, rotation, Time.deltaTime * emergencyGroupProfile.triageOrder[index].gameObject.GetComponent<NavMeshAgent>().angularSpeed);
if (distance <= arriveDistance)
{
CurrentWayPointID++;
}
if (CurrentWayPointID >= PathToFollow.pathObjs.Count)
{
//detach assistants
for (int i = 0; i < emergencyGroupProfile.assistants.Count; i++)
{
emergencyGroupProfile.assistants[i].transform.SetParent(staffMembers.transform); //null;
//AssistantsNavMeshAgents[i].baseOffset = 1.11f;
AssistantsNavMeshAgents[i].enabled = true;
}
emergencyGroupProfile.triageOrder[index].gameObject.SetActive(false);
Debug.Log(emergencyGroupProfile.triageOrder[index].gameObject.name + " Exit time = " + Time.realtimeSinceStartup + " s");
index++; //or //emergencyGroupProfile.triageOrder.Remove(emergencyGroupProfile.triageOrder[index].gameObject);
ResetValues();
}
}
protected bool HasArrived(NavMeshAgent navMeshAgent)
{
// The path hasn't been computed yet if the path is pending.
float remainingDistance;
if (navMeshAgent.pathPending)
{
remainingDistance = float.PositiveInfinity;
}
else
{
remainingDistance = navMeshAgent.remainingDistance;
}
return remainingDistance <= navMeshAgent.stoppingDistance + 1.0f;
}
private void ResetValues()
{
gatheringPhaseFinished = false;
attachmentPhaseFinished = false;
CurrentWayPointID = 0;
dist = 0;
farthestDist = 0;
timeTakenByAssistants = 0f;
longestTime = 0f;
farthestAgent = null;
farthestAgentAttachmentPoint = null;
//emergencyGroupProfile.triageOrder[index].transform.position = NextPatientInitialPosition;
//emergencyGroupProfile.triageOrder[index].transform.rotation = NextPatientInitialRotation;
}
private float CalculatePathLength(Vector3 targetPosition, NavMeshPath path)
{
float pathLength = 0f;
Vector3[] allWayPoints = new Vector3[path.corners.Length + 2];
allWayPoints[0] = gameObject.transform.position + new Vector3(0 ,1.1f,0);
allWayPoints[allWayPoints.Length - 1] = targetPosition + new Vector3(0, 1.1f, 0);
//Debug.Log(path.corners.Length);
//Debug.Log(allWayPoints.Length);
for (int i = 0; i < path.corners.Length; i++)
{
allWayPoints[i + 1] = path.corners[i];
}
for (int i = 0; i < allWayPoints.Length - 1; i++)
{
//Debug.Log(allWayPoints[i]);
pathLength += Vector3.Distance(allWayPoints[i], allWayPoints[i + 1]);
}
return pathLength;
}
}
I hope it is clear now. And I’m sorry if I’m making mistakes because I’m a bit new on programming.
Thank you for your help.
