File size: 4,382 Bytes
05c9ac2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
using System;
using Unity.Mathematics;
using UnityEngine;
namespace Unity.MLAgents.Areas
{
/// <summary>
/// The Training Ares Replicator allows for a training area object group to be replicated dynamically during runtime.
/// </summary>
[DefaultExecutionOrder(-5)]
public class TrainingAreaReplicator : MonoBehaviour
{
/// <summary>
/// The base training area to be replicated.
/// </summary>
public GameObject baseArea;
/// <summary>
/// The number of training areas to replicate.
/// </summary>
public int numAreas = 1;
/// <summary>
/// The separation between each training area.
/// </summary>
public float separation = 10f;
/// <summary>
/// Whether to replicate in the editor or in a build only. Default = true
/// </summary>
public bool buildOnly = true;
int3 m_GridSize = new(1, 1, 1);
int m_AreaCount;
string m_TrainingAreaName;
/// <summary>
/// The size of the computed grid to pack the training areas into.
/// </summary>
public int3 GridSize => m_GridSize;
/// <summary>
/// The name of the training area.
/// </summary>
public string TrainingAreaName => m_TrainingAreaName;
/// <summary>
/// Called before the simulation begins to computed the grid size for distributing
/// the replicated training areas and set the area name.
/// </summary>
public void Awake()
{
// Computes the Grid Size on Awake
ComputeGridSize();
// Sets the TrainingArea name to the name of the base area.
m_TrainingAreaName = baseArea.name;
}
/// <summary>
/// Called after Awake and before the simulation begins and adds the training areas before
/// the Academy begins.
/// </summary>
public void OnEnable()
{
// Adds the training as replicas during OnEnable to ensure they are added before the Academy begins its work.
if (buildOnly)
{
#if UNITY_STANDALONE && !UNITY_EDITOR
AddEnvironments();
#endif
return;
}
AddEnvironments();
}
/// <summary>
/// Computes the Grid Size for replicating the training area.
/// </summary>
void ComputeGridSize()
{
// check if running inference, if so, use the num areas set through the component,
// otherwise, pull it from the academy
if (Academy.Instance.Communicator != null)
numAreas = Academy.Instance.NumAreas;
var rootNumAreas = Mathf.Pow(numAreas, 1.0f / 3.0f);
m_GridSize.x = Mathf.CeilToInt(rootNumAreas);
m_GridSize.y = Mathf.CeilToInt(rootNumAreas);
var zSize = Mathf.CeilToInt((float)numAreas / (m_GridSize.x * m_GridSize.y));
m_GridSize.z = zSize == 0 ? 1 : zSize;
}
/// <summary>
/// Adds replicas of the training area to the scene.
/// </summary>
/// <exception cref="UnityAgentsException"></exception>
void AddEnvironments()
{
if (numAreas > m_GridSize.x * m_GridSize.y * m_GridSize.z)
{
throw new UnityAgentsException("The number of training areas that you have specified exceeds the size of the grid.");
}
for (int z = 0; z < m_GridSize.z; z++)
{
for (int y = 0; y < m_GridSize.y; y++)
{
for (int x = 0; x < m_GridSize.x; x++)
{
if (m_AreaCount == 0)
{
// Skip this first area since it already exists.
m_AreaCount = 1;
}
else if (m_AreaCount < numAreas)
{
m_AreaCount++;
var area = Instantiate(baseArea, new Vector3(x * separation, y * separation, z * separation), Quaternion.identity);
area.name = m_TrainingAreaName;
}
}
}
}
}
}
}
|