Avoidance using ECS

Hi there

I’m a newbie interested in developing high performance games.
I’m trying to understand the concepts digging through the Unity ECS Documentation located at:
https://docs.unity3d.com/Packages/com.unity.entities@0.1/manual/index.html
It would really help me to understand the concepts (entity, component, and especially the parallel job system) if somebody could explain me (high level or pseudo code is perfectly fine) how to implement a avoidance system.
lets say we have simple position components and every position component should avoid the others so they don’t collide.
the goal should be to use parallel jobs as much as possible.
i hope i don’t ask for too much…

any pointers are highly appreciated.

Maybe you should take a look at the Boids example:

This is based on the time to collision avoidance described in GameAI Pro2. Can’t attest to the quality, it doesn’t work well for my situation and you’ll need a spatial partition to find nearby units, you can probably use the BVH from Unity.Physics by looking at the sample that draws rays to nearby colliders.

public class CollisionAvoidanceSystem : JobComponentSystem{
    [BurstCompile]
    public struct AvoidanceJob : IJobForEachWithEntity<Avoidance>{
        [ReadOnly] public ComponentDataFromEntity<Translation> positions;
        [ReadOnly] public ComponentDataFromEntity<RigidbodyData> velocities;
        public float dt;
        [ReadOnly] public QTree tree;
        public void Execute(Entity entity, int index, [WriteOnly] ref Avoidance actor){
            actor.force = 2.0f*(velocities[entity].latentVelocity - velocities[entity].velocity);
            float radius = 1.6f; //No radius component atm.
            var entityBuffer = new NativeList<Entity>(Allocator.Temp);
            AABBTreeUtility.Query(tree, AABBTreeUtility.GetAABB(
                positions[entity].Value,radius*6f,2.14f,2.14f), tree.root.Value ,ref entityBuffer,5
            );
            for(var i = 0; i < entityBuffer.Length; i++){
                if(!velocities.Exists(entityBuffer[i]))
                    continue;
                var r = radius*2f;
                var w = positions[entity].Value - positions[entityBuffer[i]].Value;

                var c = math.dot(w,w) - r;
                if(c < 0)
                    c = math.dot(w,w) - r/2f;
               
                var v = velocities[entity].velocity - velocities[entityBuffer[i]].velocity;
                var a = math.dot(v,v);
                var b = math.dot(w,v);
                var discr = b*b - a*c;
                if(discr <=0)
                    continue; //Time till collision is infinite
               
                var tau = (b-math.sqrt(discr))/a;

                if(tau < 0)
                    continue; //Time till collision is infinite
               
                var forceAvoid = positions[entity].Value + velocities[entity].velocity * tau - positions[entityBuffer[i]].Value - velocities[entityBuffer[i]].velocity * tau;
               
                if(forceAvoid.x != 0 && forceAvoid.z != 0)
                    forceAvoid /= math.sqrt(math.dot(forceAvoid,forceAvoid));

                var mag = 0f;
                if(tau <= 5.5f) //Time horizion = 5
                    mag = (5.5f-tau) / (tau + 0.001f);
                actor.force = actor.force.setY(0);
                actor.force += forceAvoid*math.min(mag,20f); //cap
            }
        }
    }
1 Like

thanks guys!
in addition i just right now found:

which i will check out tomorrow :slight_smile: (it also mentions the boids demo…so seems like i’m on the right path)
looks like creating quadrants is necessary to split up the work in the end (i think that is what @riskparitygawd meant with spatial partition)

1 Like