/// </summary>
public class GridSensor : ISensor , IBuiltInSensor
{
/// <summary>
/// Name of this grid sensor.
/// </summary>
string Name ;
//
// Main Parameters
//
/// <summary>
/// The scale of each grid cell.
/// </summary>
Vector3 CellScale ;
/// <summary>
/// The number of grid on each side.
/// </summary>
Vector3Int GridNumSide ;
/// <summary>
/// Rotate the grid based on the direction the agent is facing.
/// </summary>
bool RotateWithAgent ;
/// <summary>
/// Array holding the depth of each channel.
/// </summary>
int [ ] ChannelDepth ;
/// <summary>
/// List of tags that are detected.
/// </summary>
string [ ] DetectableObjects ;
/// <summary>
/// The layer mask.
/// </summary>
LayerMask ObserveMask ;
/// <summary>
/// The data layout that the grid should output.
/// </summary>
GridDepthType gridDepthType = GridDepthType . Channel ;
/// <summary>
/// The reference of the root of the agent. This is used to disambiguate objects with the same tag as the agent. Defaults to current GameObject.
/// </summary>
GameObject rootReference ;
int MaxColliderBufferSize ;
int InitialColliderBufferSize ;
Collider [ ] m_ColliderBuffer ;
float [ ] m_ChannelBuffer ;
string m_Name ;
Vector3 m_CellScale ;
Vector3Int m_GridSize ;
bool m_RotateWithAgent ;
GameObject m_RootReference ;
int m_MaxColliderBufferSize ;
int m_InitialColliderBufferSize ;
LayerMask m_ColliderMask ;
GridDepthType m_GridDepthType ;
int [ ] m_ChannelDepths ;
string [ ] m_DetectableObjects ;
SensorCompressionType m_CompressionType ;
ObservationSpec m_ObservationSpec ;
//
// Hidden Parameters
//
/// <summary>
/// The total number of observations per cell of the grid. Its equivalent to the "channel" on the outgoing tensor.
/// </summary>
int ObservationPerCell ;
/// <summary>
/// The offsets used to specify where within a cell's allotted data, certain observations will be inserted.
/// </summary>
int [ ] ChannelOffsets ;
/// <summary>
/// The main storage of perceptual information.
/// </summary>
// Buffers
/// <summary>
/// The default value of the perceptionBuffer when using the ChannelHot DepthType. Used to reset the array/
/// </summary>
/// <summary>
/// Array of Colors needed in order to load the values of the perception buffer to a texture.
/// </summary>
/// <summary>
/// Texture where the colors are written to so that they can be compressed in PNG format.
/// </summary>
Texture2D m_perceptionTexture2D ;
Texture2D m_PerceptionTexture ;
Collider [ ] m_ColliderBuffer ;
float [ ] m_CellDataBuffer ;
int [ ] m_ChannelOffsets ;
Vector3 [ ] m_CellLocalPositions ;
int [ ] m_GizmoColorIndexes ;
Vector3 [ ] m_CellGlobalPosition ;
//
//
/// <summary>
/// Radius of grid, used for normalizing the distance.
/// </summary>
float InverseSphereRadius ;
/// <summary>
/// Total Number of cells (width*height)
/// </summary>
int NumCells ;
/// <summary>
/// Offset used for calculating CellToPoint
/// </summary>
float OffsetGridNumSide = 7.5f ; // (gridNumSideZ - 1) / 2;
/// <summary>
/// Cached ObservationSpec
/// </summary>
ObservationSpec m_ObservationSpec ;
//
// Debug Parameters
//
SensorCompressionType m_CompressionType = SensorCompressionType . PNG ;
/// <summary>
/// Array of colors displaying the DebugColors for each cell in OnDrawGizmos. Only updated if ShowGizmos.
/// </summary>
int [ ] m_CellActivity ;
/// <summary>
/// Array of global positions where each position is the center of a cell.
/// </summary>
Vector3 [ ] m_GizmoCellPosition ;
int m_NumCells ;
int m_CellObservationSize ;
float m_InverseSphereRadius ;
float m_OffsetGridNumSide ;
/// <summary>
/// Array of local positions where each position is the center of a cell.
/// </summary>
Vector3 [ ] CellPoints ;
Vector3Int gridNumSide ,
Vector3Int gridNum ,
int [ ] channelDepth ,
int [ ] channelDepths ,
LayerMask observeMask ,
LayerMask colliderMask ,
GameObject root ,
GameObject rootReference ,
Name = name ;
CellScale = cellScale ;
GridNumSide = gridNumSide ;
if ( GridNumSide . y ! = 1 )
m_Name = name ;
m_CellScale = cellScale ;
m_GridSize = gridNum ;
m_RotateWithAgent = rotateWithAgent ;
m_RootReference = rootReference ;
m_MaxColliderBufferSize = maxColliderBufferSize ;
m_InitialColliderBufferSize = initialColliderBufferSize ;
m_ColliderMask = colliderMask ;
m_GridDepthType = depthType ;
m_ChannelDepths = channelDepths ;
m_DetectableObjects = detectableObjects ;
m_CompressionType = compression ;
if ( m_GridSize . y ! = 1 )
RotateWithAgent = rotateWithAgent ;
ChannelDepth = channelDepth ;
DetectableObjects = detectableObjects ;
ObserveMask = observeMask ;
gridDepthType = depthType ;
rootReference = root ;
CompressionType = compression ;
MaxColliderBufferSize = maxColliderBufferSize ;
InitialColliderBufferSize = initialColliderBufferSize ;
if ( gridDepthType = = GridDepthType . Counting & & DetectableObjects . Length ! = ChannelDepth . Length )
if ( m_GridDepthType = = GridDepthType . Counting & & m_DetectableObjects . Length ! = m_ChannelDepths . Length )
{
throw new UnityAgentsException ( "The channels of a CountingGridSensor is equal to the number of detectableObjects" ) ;
}
InitCellPoints ( ) ;
ResetPerceptionBuffer ( ) ;
m_ObservationSpec = ObservationSpec . Visual ( GridNumSide . x , GridNumSide . z , ObservationPerCell ) ;
m_perceptionTexture2D = new Texture2D ( GridNumSide . x , GridNumSid e. z , TextureFormat . RGB24 , false ) ;
m_ColliderBuffer = new Collider [ Math . Min ( MaxColliderBufferSize , InitialColliderBufferSize ) ] ;
m_ObservationSpec = ObservationSpec . Visual ( m_GridSize . x , m_GridSize . z , m_CellObservationSize ) ;
m_PerceptionTexture = new Texture2D ( m_GridSize . x , m_GridSiz e. z , TextureFormat . RGB24 , false ) ;
m_ColliderBuffer = new Collider [ Math . Min ( m_ MaxColliderBufferSize, m_ InitialColliderBufferSize) ] ;
}
public SensorCompressionType CompressionType
}
public int [ ] CellActivity
public bool RotateWithAgent
{
get { return m_RotateWithAgent ; }
set { m_RotateWithAgent = value ; }
}
public LayerMask ColliderMask
{
get { return m_ColliderMask ; }
set { m_ColliderMask = value ; }
}
public int [ ] GizmoColorIndexes
get { return m_CellActivity ; }
get { return m_GizmoColorIndexes ; }
}
/// <summary>
{
NumCells = GridNumSide . x * GridNumSid e. z ;
float sphereRadiusX = ( CellScale . x * GridNumSid e. x ) / Mathf . Sqrt ( 2 ) ;
float sphereRadiusZ = ( CellScale . z * GridNumSid e. z ) / Mathf . Sqrt ( 2 ) ;
InverseSphereRadius = 1.0f / Mathf . Max ( sphereRadiusX , sphereRadiusZ ) ;
OffsetGridNumSide = ( GridNumSid e. z - 1f ) / 2f ;
m_ NumCells = m_GridSize . x * m_GridSiz e. z ;
float sphereRadiusX = ( m_ CellScale. x * m_GridSiz e. x ) / Mathf . Sqrt ( 2 ) ;
float sphereRadiusZ = ( m_ CellScale. z * m_GridSiz e. z ) / Mathf . Sqrt ( 2 ) ;
m_ InverseSphereRadius = 1.0f / Mathf . Max ( sphereRadiusX , sphereRadiusZ ) ;
m_ OffsetGridNumSide = ( m_GridSiz e. z - 1f ) / 2f ;
}
/// <summary>
void InitDepthType ( )
{
if ( g ridDepthType = = GridDepthType . ChannelHot )
if ( m_G ridDepthType = = GridDepthType . ChannelHot )
ObservationPerCell = ChannelDepth . Sum ( ) ;
m_CellObservationSize = m_ChannelDepths . Sum ( ) ;
ChannelOffsets = new int [ ChannelDepth . Length ] ;
for ( int i = 1 ; i < ChannelDepth . Length ; i + + )
m_ ChannelOffsets = new int [ m_ ChannelDepths . Length ] ;
for ( int i = 1 ; i < m_ ChannelDepths . Length ; i + + )
ChannelOffsets [ i ] = ChannelOffsets [ i - 1 ] + ChannelDepth [ i - 1 ] ;
m_ ChannelOffsets[ i ] = m_ ChannelOffsets[ i - 1 ] + m_ ChannelDepths [ i - 1 ] ;
m_ChannelHotDefaultPerceptionBuffer = new float [ ObservationPerCell ] ;
for ( int i = 0 ; i < ChannelDepth . Length ; i + + )
m_ChannelHotDefaultPerceptionBuffer = new float [ m_CellObservationSize ] ;
for ( int i = 0 ; i < m_ ChannelDepths . Length ; i + + )
if ( ChannelDepth [ i ] > 1 )
if ( m_ ChannelDepths [ i ] > 1 )
m_ChannelHotDefaultPerceptionBuffer [ ChannelOffsets [ i ] ] = 1 ;
m_ChannelHotDefaultPerceptionBuffer [ m_ ChannelOffsets[ i ] ] = 1 ;
ObservationPerCell = ChannelDepth . Length ;
m_CellObservationSize = m_ChannelDepths . Length ;
Assert . IsTrue ( ObservationPerCell < ( 2 5 5 * 3 ) , "The maximum number of channels per cell must be less than 255 * 3" ) ;
Assert . IsTrue ( m_CellObservationSize < ( 2 5 5 * 3 ) , "The maximum number of channels per cell must be less than 255 * 3" ) ;
}
/// <summary>
{
CellPoin ts = new Vector3 [ NumCells ] ;
m_ CellLocal Pos ition s = new Vector3 [ m_ NumCells] ;
for ( int i = 0 ; i < NumCells ; i + + )
for ( int i = 0 ; i < m_ NumCells; i + + )
CellPoin ts [ i ] = CellToLocalPos ition ( i ) ;
m_ CellLocal Pos ition s[ i ] = CellToLocalPoin t ( i ) ;
}
}
{
if ( m_PerceptionBuffer ! = null )
{
if ( g ridDepthType = = GridDepthType . ChannelHot )
if ( m_G ridDepthType = = GridDepthType . ChannelHot )
for ( int i = 0 ; i < NumCells ; i + + )
for ( int i = 0 ; i < m_ NumCells; i + + )
Array . Copy ( m_ChannelHotDefaultPerceptionBuffer , 0 , m_PerceptionBuffer , i * ObservationPerCell , ObservationPerCell ) ;
Array . Copy ( m_ChannelHotDefaultPerceptionBuffer , 0 , m_PerceptionBuffer , i * m_CellObservationSize , m_CellObservationSize ) ;
}
}
else
}
else
{
m_PerceptionBuffer = new float [ ObservationPerCell * NumCells ] ;
m_ColliderBuffer = new Collider [ Math . Min ( MaxColliderBufferSize , InitialColliderBufferSize ) ] ;
m_Chann elBuffer = new float [ ChannelDepth . Length ] ;
m_PerceptionColors = new Color [ NumCells ] ;
m_Gizmo CellPosition = new Vector3 [ NumCells ] ;
m_PerceptionBuffer = new float [ m_CellObservationSize * m_ NumCells] ;
m_ColliderBuffer = new Collider [ Math . Min ( m_ MaxColliderBufferSize, m_ InitialColliderBufferSize) ] ;
m_CellData Buffer = new float [ m_ ChannelDepths . Length ] ;
m_PerceptionColors = new Color [ m_ NumCells] ;
m_CellGloba lPosition = new Vector3 [ m_ NumCells] ;
}
}
if ( m_CellActivity = = null )
m_CellActivity = new int [ NumCells ] ;
if ( m_GizmoColorIndexes = = null )
m_GizmoColorIndexes = new int [ m_NumCells ] ;
for ( int i = 0 ; i < NumCells ; i + + )
for ( int i = 0 ; i < m_NumCells ; i + + )
m_CellActivity [ i ] = - 1 ;
m_GizmoColorIndexes [ i ] = - 1 ;
}
}
{
return Name ;
return m_ Name;
}
/// <inheritdoc/>
using ( TimerStack . Instance . Scoped ( "GridSensor.GetCompressedObservation" ) )
{
var allBytes = new List < byte > ( ) ;
var numImages = ( ObservationPerCell + 2 ) / 3 ;
var numImages = ( m_CellObservationSize + 2 ) / 3 ;
ChannelsToTexture ( channelIndex , Math . Min ( 3 , ObservationPerCell - channelIndex ) ) ;
allBytes . AddRange ( m_perceptionTexture2D . EncodeToPNG ( ) ) ;
ChannelsToTexture ( channelIndex , Math . Min ( 3 , m_CellObservationSize - channelIndex ) ) ;
allBytes . AddRange ( m_PerceptionTexture . EncodeToPNG ( ) ) ;
}
return allBytes . ToArray ( ) ;
/// <param name="numChannelsToAdd"></param>
void ChannelsToTexture ( int channelIndex , int numChannelsToAdd )
{
for ( int i = 0 ; i < NumCells ; i + + )
for ( int i = 0 ; i < m_ NumCells; i + + )
m_PerceptionColors [ i ] [ j ] = m_PerceptionBuffer [ i * ObservationPerCell + channelIndex + j ] ;
m_PerceptionColors [ i ] [ j ] = m_PerceptionBuffer [ i * m_CellObservationSize + channelIndex + j ] ;
m_perceptionTexture2D . SetPixels ( m_PerceptionColors ) ;
m_PerceptionTexture . SetPixels ( m_PerceptionColors ) ;
}
/// <summary>
ResetPerceptionBuffer ( ) ;
using ( TimerStack . Instance . Scoped ( "GridSensor.Perceive" ) )
{
var halfCellScale = new Vector3 ( CellScale . x / 2f , CellScale . y , CellScale . z / 2f ) ;
var halfCellScale = new Vector3 ( m_ CellScale. x / 2f , m_ CellScale. y , m_ CellScale. z / 2f ) ;
for ( var cellIndex = 0 ; cellIndex < NumCells ; cellIndex + + )
for ( var cellIndex = 0 ; cellIndex < m_ NumCells; cellIndex + + )
{
var cellCenter = GetCellGlobalPosition ( cellIndex ) ;
var numFound = BufferResizingOverlapBoxNonAlloc ( cellCenter , halfCellScale , GetGridRotation ( ) ) ;
if ( gridDepthType = = GridDepthType . Counting )
if ( m_GridDepthType = = GridDepthType . Counting )
{
ParseCollidersAll ( m_ColliderBuffer , numFound , cellIndex , cellCenter ) ;
}
// until we're sure we can hold them all (or until we hit the max size).
while ( true )
{
numFound = Physics . OverlapBoxNonAlloc ( cellCenter , halfCellScale , m_ColliderBuffer , rotation , Observe Mask) ;
if ( numFound = = m_ColliderBuffer . Length & & m_ColliderBuffer . Length < MaxColliderBufferSize )
numFound = Physics . OverlapBoxNonAlloc ( cellCenter , halfCellScale , m_ColliderBuffer , rotation , m_Collider Mask) ;
if ( numFound = = m_ColliderBuffer . Length & & m_ColliderBuffer . Length < m_ MaxColliderBufferSize)
m_ColliderBuffer = new Collider [ Math . Min ( MaxColliderBufferSize , m_ColliderBuffer . Length * 2 ) ] ;
InitialColliderBufferSize = m_ColliderBuffer . Length ;
m_ColliderBuffer = new Collider [ Math . Min ( m_ MaxColliderBufferSize, m_ColliderBuffer . Length * 2 ) ] ;
m_ InitialColliderBufferSize = m_ColliderBuffer . Length ;
}
else
{
var currentColliderGo = foundColliders [ i ] . gameObject ;
// Continue if the current collider go is the root reference
if ( ReferenceEquals ( currentColliderGo , r ootReference) )
if ( ReferenceEquals ( currentColliderGo , m_R ootReference) )
var currentDistanceSquared = ( closestColliderPoint - r ootReference. transform . position ) . sqrMagnitude ;
var currentDistanceSquared = ( closestColliderPoint - m_R ootReference. transform . position ) . sqrMagnitude ;
for ( var ii = 0 ; ii < DetectableObjects . Length ; ii + + )
for ( var ii = 0 ; ii < m_ DetectableObjects. Length ; ii + + )
if ( currentColliderGo . CompareTag ( DetectableObjects [ ii ] ) )
if ( currentColliderGo . CompareTag ( m_ DetectableObjects[ ii ] ) )
{
index = ii ;
break ;
if ( ! ReferenceEquals ( closestColliderGo , null ) )
{
LoadObjectData ( closestColliderGo , cellIndex , ( float ) Math . Sqrt ( minDistanceSquared ) * InverseSphereRadius ) ;
LoadObjectData ( closestColliderGo , cellIndex , ( float ) Math . Sqrt ( minDistanceSquared ) * m_ InverseSphereRadius) ;
}
Profiler . EndSample ( ) ;
}
currentColliderGo = foundColliders [ i ] . gameObject ;
// Continue if the current collider go is the root reference
if ( currentColliderGo = = r ootReference)
if ( currentColliderGo = = m_R ootReference)
Vector3 . Distance ( closestColliderPoint , r ootReference. transform . position ) * InverseSphereRadius ) ;
Vector3 . Distance ( closestColliderPoint , m_R ootReference. transform . position ) * m_ InverseSphereRadius) ;
}
Profiler . EndSample ( ) ;
}
/// </example>
protected virtual float [ ] GetObjectData ( GameObject currentColliderGo , float typeIndex , float normalizedDistance )
{
Array . Clear ( m_Chann elBuffer , 0 , m_Chann elBuffer . Length ) ;
m_Chann elBuffer [ 0 ] = typeIndex ;
return m_Chann elBuffer ;
Array . Clear ( m_CellData Buffer , 0 , m_CellData Buffer . Length ) ;
m_CellData Buffer [ 0 ] = typeIndex ;
return m_CellData Buffer ;
}
/// <summary>
if ( channelValues [ j ] < 0 )
throw new UnityAgentsException ( "Expected ChannelValue[" + j + "] for " + currentColliderGo . name + " to be non-negative, was " + channelValues [ j ] ) ;
if ( channelValues [ j ] > ChannelDepth [ j ] )
throw new UnityAgentsException ( "Expected ChannelValue[" + j + "] for " + currentColliderGo . name + " to be less than ChannelDepth[" + j + "] (" + ChannelDepth [ j ] + "), was " + channelValues [ j ] ) ;
if ( channelValues [ j ] > m_ ChannelDepths [ j ] )
throw new UnityAgentsException ( "Expected ChannelValue[" + j + "] for " + currentColliderGo . name + " to be less than ChannelDepth[" + j + "] (" + m_ ChannelDepths [ j ] + "), was " + channelValues [ j ] ) ;
}
}
protected virtual void LoadObjectData ( GameObject currentColliderGo , int cellIndex , float normalizedDistance )
{
Profiler . BeginSample ( "GridSensor.LoadObjectData" ) ;
var channelHotVals = new ArraySegment < float > ( m_PerceptionBuffer , cellIndex * ObservationPerCell , ObservationPerCell ) ;
for ( var i = 0 ; i < DetectableObjects . Length ; i + + )
var channelHotVals = new ArraySegment < float > ( m_PerceptionBuffer , cellIndex * m_CellObservationSize , m_CellObservationSize ) ;
for ( var i = 0 ; i < m_ DetectableObjects. Length ; i + + )
if ( g ridDepthType ! = GridDepthType . Counting )
if ( m_G ridDepthType ! = GridDepthType . Counting )
{
for ( var ii = 0 ; ii < channelHotVals . Count ; ii + + )
{
if ( ! ReferenceEquals ( currentColliderGo , null ) & & currentColliderGo . CompareTag ( DetectableObjects [ i ] ) )
if ( ! ReferenceEquals ( currentColliderGo , null ) & & currentColliderGo . CompareTag ( m_ DetectableObjects[ i ] ) )
{
// TODO: Create the array already then set the values using "out" in GetObjectData
// Using i+1 as the type index as "0" represents "empty"
switch ( gridDepthType )
switch ( m_GridDepthType )
{
case GridDepthType . Channel :
{
// Array.Copy(channelValues, 0, PerceptionBuffer, cell_id*ObservationPerCell, ObservationPerCell);
for ( int j = 0 ; j < channelValues . Length ; j + + )
{
channelValues [ j ] / = ChannelDepth [ j ] ;
channelValues [ j ] / = m_ ChannelDepths [ j ] ;
Array . Copy ( channelValues , 0 , m_PerceptionBuffer , cellIndex * ObservationPerCell , ObservationPerCell ) ;
Array . Copy ( channelValues , 0 , m_PerceptionBuffer , cellIndex * m_CellObservationSize , m_CellObservationSize ) ;
break ;
}
// Array.Copy(channelHotVals, 0, PerceptionBuffer, cell_id*ObservationPerCell, ObservationPerCell);
for ( int j = 0 ; j < channelValues . Length ; j + + )
{
if ( ChannelDepth [ j ] > 1 )
if ( m_ ChannelDepths [ j ] > 1 )
m_PerceptionBuffer [ channelHotVals . Offset + ( int ) channelValues [ j ] + ChannelOffsets [ j ] ] = 1f ;
m_PerceptionBuffer [ channelHotVals . Offset + ( int ) channelValues [ j ] + m_ ChannelOffsets[ j ] ] = 1f ;
m_PerceptionBuffer [ channelHotVals . Offset + ChannelOffsets [ j ] ] = channelValues [ j ] ;
m_PerceptionBuffer [ channelHotVals . Offset + m_ ChannelOffsets[ j ] ] = channelValues [ j ] ;
}
}
break ;
// The observations are "channel count" so each grid is WxHxC where C is the number of tags
// This means that each value channelValues[i] is a counter of gameobject included into grid cells
// where i is the index of the tag in DetectableObjects
int countIndex = cellIndex * ObservationPerCell + i ;
m_PerceptionBuffer [ countIndex ] = Mathf . Min ( 1f , m_PerceptionBuffer [ countIndex ] + 1f / ChannelDepth [ i ] ) ;
int countIndex = cellIndex * m_CellObservationSize + i ;
m_PerceptionBuffer [ countIndex ] = Mathf . Min ( 1f , m_PerceptionBuffer [ countIndex ] + 1f / m_ ChannelDepths [ i ] ) ;
break ;
}
}
/// <summary>Converts the index of the cell to the 3D point (y is zero) relative to grid center</summary>
/// <returns>Vector3 of the position of the center of the cell relative to grid center</returns>
/// <param name="cell">The index of the cell</param>
Vector3 CellToLocalPos ition ( int cellIndex )
Vector3 CellToLocalPoin t ( int cellIndex )
float x = ( cellIndex % GridNumSid e. z - OffsetGridNumSide ) * CellScale . x ;
float z = ( cellIndex / GridNumSid e. z - OffsetGridNumSide ) * CellScale . z - ( GridNumSide . z - GridNumSid e. x ) ;
float x = ( cellIndex % m_GridSiz e. z - m_ OffsetGridNumSide) * m_ CellScale. x ;
float z = ( cellIndex / m_GridSiz e. z - m_ OffsetGridNumSide) * m_ CellScale. z - ( m_GridSize . z - m_GridSiz e. x ) ;
if ( RotateWithAgent )
if ( m_ RotateWithAgent)
return r ootReference. transform . TransformPoint ( CellPoin ts [ cellIndex ] ) ;
return m_R ootReference. transform . TransformPoint ( m_ CellLocal Pos ition s[ cellIndex ] ) ;
return CellPoin ts [ cellIndex ] + r ootReference. transform . position ;
return m_ CellLocal Pos ition s[ cellIndex ] + m_R ootReference. transform . position ;
return RotateWithAgent ? r ootReference. transform . rotation : Quaternion . identity ;
return m_ RotateWithAgent ? m_R ootReference. transform . rotation : Quaternion . identity ;
}
/// <inheritdoc/>
using ( TimerStack . Instance . Scoped ( "GridSensor.Write" ) )
{
int index = 0 ;
for ( var h = GridNumSid e. z - 1 ; h > = 0 ; h - - )
for ( var h = m_GridSiz e. z - 1 ; h > = 0 ; h - - )
for ( var w = 0 ; w < GridNumSid e. x ; w + + )
for ( var w = 0 ; w < m_GridSiz e. x ; w + + )
for ( var d = 0 ; d < ObservationPerCell ; d + + )
for ( var d = 0 ; d < m_CellObservationSize ; d + + )
{
writer [ h , w , d ] = m_PerceptionBuffer [ index ] ;
index + + ;
internal int [ ] PerceiveGizmoColor ( )
{
ResetGizmoBuffer ( ) ;
var halfCellScale = new Vector3 ( CellScale . x / 2f , CellScale . y , CellScale . z / 2f ) ;
var halfCellScale = new Vector3 ( m_ CellScale. x / 2f , m_ CellScale. y , m_ CellScale. z / 2f ) ;
for ( var cellIndex = 0 ; cellIndex < NumCells ; cellIndex + + )
for ( var cellIndex = 0 ; cellIndex < m_ NumCells; cellIndex + + )
{
var cellCenter = GetCellGlobalPosition ( cellIndex ) ;
var numFound = BufferResizingOverlapBoxNonAlloc ( cellCenter , halfCellScale , GetGridRotation ( ) ) ;
for ( var i = 0 ; i < numFound ; i + + )
{
var currentColliderGo = m_ColliderBuffer [ i ] . gameObject ;
if ( ReferenceEquals ( currentColliderGo , r ootReference) )
if ( ReferenceEquals ( currentColliderGo , m_R ootReference) )
var currentDistanceSquared = ( closestColliderPoint - r ootReference. transform . position ) . sqrMagnitude ;
var currentDistanceSquared = ( closestColliderPoint - m_R ootReference. transform . position ) . sqrMagnitude ;
for ( var ii = 0 ; ii < DetectableObjects . Length ; ii + + )
for ( var ii = 0 ; ii < m_ DetectableObjects. Length ; ii + + )
if ( currentColliderGo . CompareTag ( DetectableObjects [ ii ] ) )
if ( currentColliderGo . CompareTag ( m_ DetectableObjects[ ii ] ) )
{
index = ii ;
break ;
tagIndex = index ;
}
}
CellActivity [ cellIndex ] = tagIndex ;
m_GizmoColorIndexes [ cellIndex ] = tagIndex ;
return CellActivity ;
return m_GizmoColorIndexes ;
for ( var i = 0 ; i < NumCells ; i + + )
for ( var i = 0 ; i < m_ NumCells; i + + )
m_Gizmo CellPosition [ i ] = GetCellGlobalPosition ( i ) ;
m_CellGloba lPosition [ i ] = GetCellGlobalPosition ( i ) ;
return m_Gizmo CellPosition ;
return m_CellGloba lPosition ;
}
}
}