| using System; |
| using UnityEngine; |
|
|
| namespace Unity.MLAgents.Sensors |
| { |
| |
| |
| |
| internal class BoxOverlapChecker : IGridPerception |
| { |
| Vector3 m_CellScale; |
| Vector3Int m_GridSize; |
| bool m_RotateWithAgent; |
| LayerMask m_ColliderMask; |
| GameObject m_CenterObject; |
| GameObject m_AgentGameObject; |
| string[] m_DetectableTags; |
| int m_InitialColliderBufferSize; |
| int m_MaxColliderBufferSize; |
|
|
| int m_NumCells; |
| Vector3 m_HalfCellScale; |
| Vector3 m_CellCenterOffset; |
| Vector3[] m_CellLocalPositions; |
|
|
| #if MLA_UNITY_PHYSICS_MODULE |
| Collider[] m_ColliderBuffer; |
|
|
| public event Action<GameObject, int> GridOverlapDetectedAll; |
| public event Action<GameObject, int> GridOverlapDetectedClosest; |
| public event Action<GameObject, int> GridOverlapDetectedDebug; |
| #endif |
|
|
| public BoxOverlapChecker( |
| Vector3 cellScale, |
| Vector3Int gridSize, |
| bool rotateWithAgent, |
| LayerMask colliderMask, |
| GameObject centerObject, |
| GameObject agentGameObject, |
| string[] detectableTags, |
| int initialColliderBufferSize, |
| int maxColliderBufferSize) |
| { |
| m_CellScale = cellScale; |
| m_GridSize = gridSize; |
| m_RotateWithAgent = rotateWithAgent; |
| m_ColliderMask = colliderMask; |
| m_CenterObject = centerObject; |
| m_AgentGameObject = agentGameObject; |
| m_DetectableTags = detectableTags; |
| m_InitialColliderBufferSize = initialColliderBufferSize; |
| m_MaxColliderBufferSize = maxColliderBufferSize; |
|
|
| m_NumCells = gridSize.x * gridSize.z; |
| m_HalfCellScale = new Vector3(cellScale.x / 2f, cellScale.y, cellScale.z / 2f); |
| m_CellCenterOffset = new Vector3((gridSize.x - 1f) / 2, 0, (gridSize.z - 1f) / 2); |
| #if MLA_UNITY_PHYSICS_MODULE |
| m_ColliderBuffer = new Collider[Math.Min(m_MaxColliderBufferSize, m_InitialColliderBufferSize)]; |
| #endif |
|
|
| InitCellLocalPositions(); |
| } |
|
|
| public bool RotateWithAgent |
| { |
| get { return m_RotateWithAgent; } |
| set { m_RotateWithAgent = value; } |
| } |
|
|
| public LayerMask ColliderMask |
| { |
| get { return m_ColliderMask; } |
| set { m_ColliderMask = value; } |
| } |
|
|
| |
| |
| |
| void InitCellLocalPositions() |
| { |
| m_CellLocalPositions = new Vector3[m_NumCells]; |
|
|
| for (int i = 0; i < m_NumCells; i++) |
| { |
| m_CellLocalPositions[i] = GetCellLocalPosition(i); |
| } |
| } |
|
|
| public Vector3 GetCellLocalPosition(int cellIndex) |
| { |
| float x = (cellIndex / m_GridSize.z - m_CellCenterOffset.x) * m_CellScale.x; |
| float z = (cellIndex % m_GridSize.z - m_CellCenterOffset.z) * m_CellScale.z; |
| return new Vector3(x, 0, z); |
| } |
|
|
| public Vector3 GetCellGlobalPosition(int cellIndex) |
| { |
| if (m_RotateWithAgent) |
| { |
| return m_CenterObject.transform.TransformPoint(m_CellLocalPositions[cellIndex]); |
| } |
| else |
| { |
| return m_CellLocalPositions[cellIndex] + m_CenterObject.transform.position; |
| } |
| } |
|
|
| public Quaternion GetGridRotation() |
| { |
| return m_RotateWithAgent ? m_CenterObject.transform.rotation : Quaternion.identity; |
| } |
|
|
| public void Perceive() |
| { |
| #if MLA_UNITY_PHYSICS_MODULE |
| for (var cellIndex = 0; cellIndex < m_NumCells; cellIndex++) |
| { |
| var cellCenter = GetCellGlobalPosition(cellIndex); |
| var numFound = BufferResizingOverlapBoxNonAlloc(cellCenter, m_HalfCellScale, GetGridRotation()); |
|
|
| if (GridOverlapDetectedAll != null) |
| { |
| ParseCollidersAll(m_ColliderBuffer, numFound, cellIndex, cellCenter, GridOverlapDetectedAll); |
| } |
| if (GridOverlapDetectedClosest != null) |
| { |
| ParseCollidersClosest(m_ColliderBuffer, numFound, cellIndex, cellCenter, GridOverlapDetectedClosest); |
| } |
| } |
| #endif |
| } |
|
|
| public void UpdateGizmo() |
| { |
| #if MLA_UNITY_PHYSICS_MODULE |
| for (var cellIndex = 0; cellIndex < m_NumCells; cellIndex++) |
| { |
| var cellCenter = GetCellGlobalPosition(cellIndex); |
| var numFound = BufferResizingOverlapBoxNonAlloc(cellCenter, m_HalfCellScale, GetGridRotation()); |
|
|
| ParseCollidersClosest(m_ColliderBuffer, numFound, cellIndex, cellCenter, GridOverlapDetectedDebug); |
| } |
| #endif |
| } |
|
|
| #if MLA_UNITY_PHYSICS_MODULE |
| |
| |
| |
| |
| |
| |
| |
| |
| int BufferResizingOverlapBoxNonAlloc(Vector3 cellCenter, Vector3 halfCellScale, Quaternion rotation) |
| { |
| int numFound; |
| |
| |
| while (true) |
| { |
| numFound = Physics.OverlapBoxNonAlloc(cellCenter, halfCellScale, m_ColliderBuffer, rotation, m_ColliderMask); |
| if (numFound == m_ColliderBuffer.Length && m_ColliderBuffer.Length < m_MaxColliderBufferSize) |
| { |
| m_ColliderBuffer = new Collider[Math.Min(m_MaxColliderBufferSize, m_ColliderBuffer.Length * 2)]; |
| m_InitialColliderBufferSize = m_ColliderBuffer.Length; |
| } |
| else |
| { |
| break; |
| } |
| } |
| return numFound; |
| } |
|
|
| |
| |
| |
| void ParseCollidersClosest(Collider[] foundColliders, int numFound, int cellIndex, Vector3 cellCenter, Action<GameObject, int> detectedAction) |
| { |
| GameObject closestColliderGo = null; |
| var minDistanceSquared = float.MaxValue; |
|
|
| for (var i = 0; i < numFound; i++) |
| { |
| var currentColliderGo = foundColliders[i].gameObject; |
|
|
| |
| if (ReferenceEquals(currentColliderGo, m_AgentGameObject)) |
| { |
| continue; |
| } |
|
|
| var closestColliderPoint = foundColliders[i].ClosestPointOnBounds(cellCenter); |
| var currentDistanceSquared = (closestColliderPoint - m_CenterObject.transform.position).sqrMagnitude; |
|
|
| if (currentDistanceSquared >= minDistanceSquared) |
| { |
| continue; |
| } |
|
|
| |
| var index = -1; |
| for (var ii = 0; ii < m_DetectableTags.Length; ii++) |
| { |
| if (currentColliderGo.CompareTag(m_DetectableTags[ii])) |
| { |
| index = ii; |
| break; |
| } |
| } |
| if (index > -1 && currentDistanceSquared < minDistanceSquared) |
| { |
| minDistanceSquared = currentDistanceSquared; |
| closestColliderGo = currentColliderGo; |
| } |
| } |
|
|
| if (!ReferenceEquals(closestColliderGo, null)) |
| { |
| detectedAction.Invoke(closestColliderGo, cellIndex); |
| } |
| } |
|
|
| |
| |
| |
| void ParseCollidersAll(Collider[] foundColliders, int numFound, int cellIndex, Vector3 cellCenter, Action<GameObject, int> detectedAction) |
| { |
| for (int i = 0; i < numFound; i++) |
| { |
| var currentColliderGo = foundColliders[i].gameObject; |
| if (!ReferenceEquals(currentColliderGo, m_AgentGameObject)) |
| { |
| detectedAction.Invoke(currentColliderGo, cellIndex); |
| } |
| } |
| } |
|
|
| #endif |
|
|
| public void RegisterSensor(GridSensorBase sensor) |
| { |
| #if MLA_UNITY_PHYSICS_MODULE |
| if (sensor.GetProcessCollidersMethod() == ProcessCollidersMethod.ProcessAllColliders) |
| { |
| GridOverlapDetectedAll += sensor.ProcessDetectedObject; |
| } |
| else |
| { |
| GridOverlapDetectedClosest += sensor.ProcessDetectedObject; |
| } |
| #endif |
| } |
|
|
| public void RegisterDebugSensor(GridSensorBase debugSensor) |
| { |
| #if MLA_UNITY_PHYSICS_MODULE |
| GridOverlapDetectedDebug += debugSensor.ProcessDetectedObject; |
| #endif |
| } |
| } |
| } |
|
|