Nested for loops with Job System

Hi programmers,

i am looking into converting some code in my project to use the Job System. The problem i cant wrap my head around right now is how i can get this to work with nested (for) loops.
For a single loop i think i understand and there a some examples out there. I create NativeArrays to get the variables into the Jobstruct and use the index to get through my loop. This is a test for single loop:

public class ExampleJob : MonoBehaviour
{
    public List<BurningObject> burningObjects = new List<BurningObject>();

    private void Start()
    {
        BurningObject[] allBurningObjects = FindObjectsOfType<BurningObject>();
        foreach (BurningObject burningObject in allBurningObjects)
        {
            if (burningObject != null)
            {
                burningObjects.Add(burningObject);
            }        
        }
    }

    private void Update()
    {
        // simplified code with a single loop i want to run with the job system
        for (int i = 0; i < burningObjects.Count; i++)
        {
            burningObjects[i].temperature += Time.deltaTime;
        }

        // From here with the job system
        NativeArray<float> temperatureArray = new NativeArray<float>(burningObjects.Count, Allocator.Persistent);

        for (int i = 0; i < burningObjects.Count; i++)
        {
            temperatureArray[i] = burningObjects[i].temperature;
        }

        BurningObjectJob burningObjectJob = new BurningObjectJob
        {
            deltaTime = Time.deltaTime,
            temperature = temperatureArray,
        };

        JobHandle jobHandle = burningObjectJob.Schedule(burningObjects.Count, 10);
        jobHandle.Complete();
    }
}

public struct BurningObjectJob : IJobParallelFor
{
    public float deltaTime;
    public NativeArray<float> temperature;

    public void Execute(int index)
    {
        temperature[index] += deltaTime;
    }
}

My problem is with nested for loops, this is the simplyfied code i want to convert using the job system: Iam not quite clear how i can get the sceond loop out of the Job, its using the “OverLappingBurningObjectsList” from every burningObject and lists are nullable, so i cant put this into an NativeArray.

public class BurningSystem : MonoBehaviour
{
    public List<BurningObject> burningObjects = new List<BurningObject>();

    private void Start()
    {
        BurningObject[] allBurningObjects = FindObjectsOfType<BurningObject>();
        foreach (BurningObject burningObject in allBurningObjects)
        {
            burningObjects.Add(burningObject);
        }
    }

    private void Update()
    {
        for (int i = 0; i < burningObjects.Count; i++)
        {
            BurningObject burningObject = burningObjects[i];

            // Loop through all otherBurningObject inside Collider of burningObject
            for (int j = 0; j < burningObject.OverLappingBurningObjectsList.Count; j++)
            {
                GameObject gameObjectInsideOverlappingList = burningObject.OverLappingBurningObjectsList[j];
                BurningObject otherBurningObjectComponent = gameObjectInsideOverlappingList.GetComponent<BurningObject>();
                if (otherBurningObjectComponent != null)
                {
                    // Calculate the distance from the center of the sphere collider
                    float distance = Vector3.Distance(burningObject.transform.position, gameObjectInsideOverlappingList.transform.position);

                    // Calculate the temperature increase based on the distance
                    float temperatureIncrease = Mathf.Lerp(0f, otherBurningObjectComponent.maxTemperatureIncrease, 1f - (distance / burningObject.sphereCollider.radius));

                    if (otherBurningObjectComponent.temperature + temperatureIncrease * Time.deltaTime > otherBurningObjectComponent.maxBurningTemperature)
                    {
                        // cap the temperature of the other burning object at maxBurningTemperature
                        otherBurningObjectComponent.temperature = burningObject.maxBurningTemperature;
                    }
                    else
                    {
                        // Increase the temperature of the other burning object
                        otherBurningObjectComponent.temperature += temperatureIncrease * Time.deltaTime;
                    }
                    //Debug.Log("BurningSystem: OtherGameObject" + gameObjectInsideOverlappingList.name + "; temperatureIncrease: " + temperatureIncrease);
                }
            }

            // Heat up the burningObject if it's on fire
            if (burningObject.isBurning)
            {
                float temperatureIncrease = burningObject.maxTemperatureIncrease;
                if (burningObject.temperature + temperatureIncrease * Time.deltaTime > burningObject.maxBurningTemperature)
                {
                    // cap the temperature at maxBurningTemperature
                    burningObject.temperature = burningObject.maxBurningTemperature;
                }
                else
                {
                    // Increase the temperature of the burning object
                    burningObject.temperature += temperatureIncrease * Time.deltaTime;
                }
            }
        }
    }
}

If you’re stuck at how to read / write random Entity data - ComponentLookup & BufferLookup are exactly for that purpose;

Might be worth checking:
https://docs.unity3d.com/Packages/com.unity.entities@1.0/manual/systems-looking-up-data.html

1 Like

Thanks for the reply, got it working.
Needed some time to wrap my head around stuff. So the difference in thinking when using DOTS/Jobs/Burst and Monobehaviour is, that DOTS means DATA oriented technology stack, obviously. So i dont need to pass a GameObject when i only, for example use the transform of the GameObject in my method, just pass the data you need to work with and then you dont get nullable objects and other errors…

1 Like