private void Awake()
    {
        Instance = this;

        EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

        EntityArchetype boidArchetype = entityManager.CreateArchetype(
            typeof(BoidECS),
            typeof(RenderMesh),
            typeof(RenderBounds),
            typeof(LocalToWorld)
            );

        NativeArray <Entity> boidArray = new NativeArray <Entity>(boidAmount, Allocator.Temp);

        entityManager.CreateEntity(boidArchetype, boidArray);

        for (int i = 0; i < boidArray.Length; i++)
        {
            Unity.Mathematics.Random rand = new Unity.Mathematics.Random((uint)i + 1);
            entityManager.SetComponentData(boidArray[i], new LocalToWorld {
                Value = float4x4.TRS(
                    RandomPosition(),
                    RandomRotation(),
                    new float3(1f))
            });
            entityManager.SetSharedComponentData(boidArray[i], new RenderMesh {
                mesh     = sharedMesh,
                material = sharedMaterial,
            });
        }

        boidArray.Dispose();
    }
    protected override void OnUpdate()
    {
        // This runs only if there exists a BoidControllerECS instance.
        if (!controller)
        {
            controller = BoidControllerECS.Instance;
        }
        if (controller)
        {
            EntityQuery            boidQuery        = GetEntityQuery(ComponentType.ReadOnly <BoidECS>(), ComponentType.ReadOnly <LocalToWorld>());
            NativeArray <float4x4> newBoidPositions = new NativeArray <float4x4>(boidQuery.CalculateEntityCount(), Allocator.Temp);

            int boidIndex = 0;
            Entities.WithAll <BoidECS>().ForEach((Entity boid, ref LocalToWorld localToWorld) => {
                float3 boidPosition = localToWorld.Position;

                float3 seperationSum = float3.zero;
                float3 positionSum   = float3.zero;
                float3 headingSum    = float3.zero;

                int boidsNearby = 0;

                Entities.WithAll <BoidECS>().ForEach((Entity otherBoid, ref LocalToWorld otherLocalToWorld) => {
                    if (boid != otherBoid)
                    {
                        float distToOtherBoid = math.length(boidPosition - otherLocalToWorld.Position);
                        if (distToOtherBoid < controller.boidPerceptionRadius)
                        {
                            seperationSum += -(otherLocalToWorld.Position - boidPosition) * (1f / math.max(distToOtherBoid, .0001f));
                            positionSum   += otherLocalToWorld.Position;
                            headingSum    += otherLocalToWorld.Forward;

                            boidsNearby++;
                        }
                    }
                });

                float3 force = float3.zero;

                if (boidsNearby > 0)
                {
                    force += (seperationSum / boidsNearby) * controller.separationWeight;
                    force += ((positionSum / boidsNearby) - boidPosition) * controller.cohesionWeight;
                    force += (headingSum / boidsNearby) * controller.alignmentWeight;
                }
                if (math.min(math.min(
                                 (controller.cageSize / 2f) - math.abs(boidPosition.x),
                                 (controller.cageSize / 2f) - math.abs(boidPosition.y)),
                             (controller.cageSize / 2f) - math.abs(boidPosition.z))
                    < controller.avoidWallsTurnDist)
                {
                    force += -math.normalize(boidPosition) * controller.avoidWallsWeight;
                }

                float3 velocity = localToWorld.Forward * controller.boidSpeed;
                velocity       += force * Time.DeltaTime;
                velocity        = math.normalize(velocity) * controller.boidSpeed;

                newBoidPositions[boidIndex] = float4x4.TRS(
                    localToWorld.Position + velocity * Time.DeltaTime,
                    quaternion.LookRotationSafe(velocity, localToWorld.Up),
                    new float3(1f)
                    );
                boidIndex++;
            });

            boidIndex = 0;
            Entities.WithAll <BoidECS>().ForEach((Entity boid, ref LocalToWorld localToWorld) => {
                localToWorld.Value = newBoidPositions[boidIndex];
                boidIndex++;
            });
        }
    }