Search Unity

Trying to understand the best way to avoid nested loops

Discussion in 'Entity Component System' started by tomzigza, Oct 6, 2019.

  1. tomzigza

    tomzigza

    Joined:
    Aug 4, 2017
    Posts:
    31
    In this example, I am trying to create targeting logic that would work well with tons of units.
    The obvious example is to just double itterate everything but that will get worse and worse.

    My best guess on how to solve this is to have a 2 stage job approach.
    Job 1 goes through all the entities and assigns them a region based on where they are on the map
    Job 2 then goes through each entity and looks for other entities in the neighboring regions only.

    A couple questions arise.
    1) If i stored in a native array all the entity ids for each region I would not have to double iterate at all. Instead I could pick a list of entities for my region and adjacent regions and just scan that instead of the whole entity list. However this feels like its doing memory lookups for each entity 1 by 1, which sounds like the "old way" and not taking advantage of the power of ECS
    2) if only one thing can exist in each grid location, a job could have every unit pick its destination, but not actually move. When it comes time to moving however, all the translation adjustments would need to be done in such a way that they are cancelled if a once open location is now occupied
     
  2. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
  3. threedots1

    threedots1

    Joined:
    Oct 9, 2014
    Posts:
    88
    What you've described is pretty much how the Boids demo works.

    I've done a similar thing with a raycast algo. Divide world into regions, fill a NativeMultiHashMap with the key as the region ID and the value as the entity ID or whatever data you need.

    Pass the hash map into your targeting job and you should be good to go.

    As far as the 'old way', these sort of data access patterns tend to be random anyway.
     
  4. tomzigza

    tomzigza

    Joined:
    Aug 4, 2017
    Posts:
    31
    @Arowx That could probably work, but I feel like in a grid based solution where you only need to look a few squares away from you, there is a much better option out there.
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
  6. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    There are quite a few space partitioning data structures https://en.wikipedia.org/wiki/Space_partitioning designed to reduce the search space in these types of problems. These are already built into and heavily optimised in most physics engines, even your board game space is still a space that could be represented by the physics engine.

    Hint: Don't reinvent the wheel by making a Hexa/Octa Wheel.(Using unoptimised own code instead of professionally optimised code).

    However, if your using a grid based approach you could try a lower resolution regional grid e.g. if your working on a 1m grid you could opt for a regional grid of 10m,100m,1000m this would just be a 'smaller' array of lists that contain everything in that region.

    Benefits here are if you need to test for 50 m you would only need to scan 100*, 1**,1** (**worst case 4) regions instead of potentially thousands of tests if you test against units of 10,000 if your scanning 100x100 1m grid squares.

    if you get the region size right for the viewing/targeting radius you can simply loop through a set of regional lists that have potential targets.
    If you are going for a nearest target first you could spiral search outwards and stop on the first target you find. Massively reducing the workload.

    Cons you need to ensure all movement on the high resolution grid is reflected in the low resolution grid.

    * Hint you could reduce this further if you exclude regions outside of the radius.
     
    Last edited: Oct 8, 2019
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Typically for these types of problems it is more efficient to bake out whatever data is needed to select a target into a NativeArray when building up the spatial data structures so that your evaluation of the entities nearby when trying to pick a target is actually just iterating through a subset of the array.