Can someone help me to convert this to use Job System?
void FindNearestTarget()
{
for (int i = 0; i < targetManager.TroopsArray.Length; i++)
{
shortestDistanceToTarget_sq = Mathf.Infinity;
Transform nearestTarget = null;
foreach (GameObject Target in targetManager.LootTargetsArray)
{
float distanceToTarget_sq = math.distancesq(targetManager.TroopsArray*.transform.position, Target.transform.position);
if (distanceToTarget_sq < shortestDistanceToTarget_sq)
{
shortestDistanceToTarget_sq = distanceToTarget_sq;
nearestTarget = Target.transform;
}
}
if (nearestTarget != null)
{
targetManager.TroopsArray_.GetComponent<MovementH>().Movement((nearestTarget.position - targetManager.TroopsArray*.transform.position).normalized);
}
}
}
FindNearestTargetJob
[Unity.Burst.BurstCompile]
public struct FindNearestTargetJob : IJobParallelFor
{
[ReadOnly] public NativeList<float3> Origins;// reads one per jobIndex
[ReadOnly][NativeDisableParallelForRestriction] public NativeList<float3> Targets;// reads all per jobIndex
[WriteOnly] public NativeArray<int> Results;
void IJobParallelFor.Execute ( int jobIndex )
{
float3 origin = Origins[jobIndex];
int candidate = -1;
float candidateDistSq = float.PositiveInfinity;
for( int i=0 ; i<Targets.Length ; i++ )
{
float distSq = math.distancesq( origin , Targets *);
if( distSq<candidateDistSq )
{
candidateDistSq = distSq;
candidate = i;
}
}
Results[jobIndex] = candidate;
}
}

Here is a full, working example based not on entities but common gameObjects
.
(sourcing these positions from entities is a much easier case)
LetFindNearestTargets
// web* src = https://gist.github.com/andrew-raphael-lukasik/e9c3c1c85a149d2c041532e3632fe4e3
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Jobs;
using Unity.Mathematics;
using Unity.Jobs;
using Unity.Collections;
using Unity.Profiling;
public class LetFindNearestTargets : MonoBehaviour
{
public List<Transform>
troopsToAdd = new List<Transform>() ,
troopsToRemove = new List<Transform>() ,
targetsToAdd = new List<Transform>() ,
targetsToRemove = new List<Transform>();
TransformAccessArray _troopsDataAccess, _targetsDataAccess;
NativeList<float3> _troopPositions, _targetPositions;
NativeList<int> _nearestTargetIndices;
public JobHandle Dependency;
ProfilerMarker
___proc_results = new ProfilerMarker("process job results") ,
___maintain_data_access = new ProfilerMarker("maintan data access") ,
___schedule_new = new ProfilerMarker("schedule jobs") ,
___schedule = new ProfilerMarker("schedule calls");
const float k_tick_rate = 0.4f;// tick every 0.4s
void OnEnable ()
{
InvokeRepeating( nameof(Tick) , k_tick_rate , k_tick_rate );
_troopsDataAccess = new TransformAccessArray( 32 );
_targetsDataAccess = new TransformAccessArray( 32 );
_troopPositions = new NativeList<float3>( 32 , Allocator.Persistent );
_targetPositions = new NativeList<float3>( 32 , Allocator.Persistent );
_nearestTargetIndices = new NativeList<int>( 32 , Allocator.Persistent );
}
void OnDisable ()
{
CancelInvoke();
Dependency.Complete();
if( _troopsDataAccess.isCreated ) _troopsDataAccess.Dispose();
if( _targetsDataAccess.isCreated ) _targetsDataAccess.Dispose();
if( _troopPositions.IsCreated ) _troopPositions.Dispose();
if( _targetPositions.IsCreated ) _targetPositions.Dispose();
if( _nearestTargetIndices.IsCreated ) _nearestTargetIndices.Dispose();
}
#if UNITY_EDITOR
void OnDrawGizmos ()
{
if( !Application.isPlaying ) return;
Gizmos.color = Color.blue;
for( int i=_troopsDataAccess.length-1 ; i!=-1 ; i-- )
Gizmos.DrawWireCube( _troopsDataAccess*.position , Vector3.one );
Gizmos.color = Color.red;
for( int i=_targetsDataAccess.length-1 ; i!=-1 ; i-- )
Gizmos.DrawWireSphere( _targetsDataAccess*.position , 1f );
}
#endif
void Tick ()
{
Dependency.Complete();
// process results
___proc_results.Begin();
{
// don't do this like I'm doing here, it's just for quick & dirty viz
// i.e. avoid reading/writing from native collection outside jobs, it very slow (especially in big loops)
int numResults = _nearestTargetIndices.Length;
for( int i=0 ; i<numResults ; i++ )
{
int nearestTargetIndex = _nearestTargetIndices*;
Debug.DrawLine( _troopPositions *, _targetPositions[nearestTargetIndex] , Color.yellow , k_tick_rate );
// Transform troop = _troopsDataAccess*;
// Transform target = _targetsDataAccess[nearestTargetIndex];
}
}
___proc_results.End();
// TransformAccessArray maintainance
___maintain_data_access.Begin();
{
int numTroopsToRemove = troopsToRemove.Count;
if( numTroopsToRemove!=0 )
{
for( int i=0 ; i<numTroopsToRemove ; i++ )
{
Transform next = troopsToRemove*;
if( next!=null )
for( int k=_troopsDataAccess.length-1 ; k!=-1 ; k-- )
{
if( _troopsDataAccess[k]==next )
{
_troopsDataAccess.RemoveAtSwapBack( k );
break;
}
}
}
troopsToRemove.Clear();
}
int numTroopsToAdd = troopsToAdd.Count;
if( numTroopsToAdd!=0 )
{
for( int i=0 ; i<numTroopsToAdd ; i++ )
if( troopsToAdd*!=null )
_troopsDataAccess.Add( troopsToAdd *);
troopsToAdd.Clear();
}
int numTargetsToRemove = targetsToRemove.Count;
if( numTargetsToRemove!=0 )
{
for( int i=0 ; i<numTargetsToRemove ; i++ )
{
Transform next = targetsToRemove*;
if( next!=null )
for( int k=_targetsDataAccess.length-1 ; k!=-1 ; k-- )
{
if( _targetsDataAccess[k]==next )
{
_targetsDataAccess.RemoveAtSwapBack( k );
break;
}
}
}
targetsToRemove.Clear();
}
int numTargetsToAdd = targetsToAdd.Count;
if( numTargetsToAdd!=0 )
{
for( int i=0 ; i<numTargetsToAdd ; i++ )
if( targetsToAdd*!=null )
_targetsDataAccess.Add( targetsToAdd *);
targetsToAdd.Clear();
}
}
___maintain_data_access.End();
// schedule new jobs:
___schedule_new.Begin();
int numTroops = _troopsDataAccess.length;
int numTargets = _targetsDataAccess.length;
if( numTroops!=0 && numTargets!=0 )
{
___schedule.Begin();
_troopPositions.Length = numTroops;
_nearestTargetIndices.Length = numTroops;
_targetPositions.Length = numTargets;
JobHandle troopPositionsJobHandle = new ReadPositionsJob{ Results = _troopPositions }
.Schedule( _troopsDataAccess );
JobHandle targetPositionsJobHandle = new ReadPositionsJob{ Results = _targetPositions }
.Schedule( _targetsDataAccess );
var findNearestTargetJob = new FindNearestTargetJob
{
Origins = _troopPositions ,
Targets = _targetPositions ,
Results = _nearestTargetIndices ,
};
Dependency = JobHandle.CombineDependencies( troopPositionsJobHandle , targetPositionsJobHandle , Dependency );
Dependency = findNearestTargetJob.Schedule(
arrayLength: numTroops ,
innerloopBatchCount: math.max( numTroops/SystemInfo.processorCount/4 , 1 ) ,
dependsOn: Dependency
);
___schedule.End();
}
___schedule_new.End();
}
}
[Unity.Burst.BurstCompile]
public struct ReadPositionsJob : IJobParallelForTransform
{
[WriteOnly] public NativeArray<float3> Results;
void IJobParallelForTransform.Execute ( int index , TransformAccess transform )
=> Results[index] = transform.position;
}