public static CollisionMap GenerateMapFor(List <JCollider> bodies, int maxNumberOfElements, Bounds bounds)
        {
            var rootCollisionMap = new CollisionMap();

            if (bodies.Count <= maxNumberOfElements || bounds.size.x <= MinBoundsWidth)
            {
                rootCollisionMap.bodies = new List <JCollider>(bodies);
                rootCollisionMap.bounds = bounds;
            }
            else
            {
                var newXSize = bounds.size.x / 2;

                var boundsChildA = new Bounds(
                    new Vector3(newXSize / 2 + bounds.min.x, 0, bounds.center.z),
                    new Vector3(newXSize, 0, bounds.size.z));

                var boundsChildB = new Bounds(
                    new Vector3(newXSize / 2 + bounds.center.x, 0, bounds.center.z),
                    new Vector3(newXSize, 0, bounds.size.z));

                List <JCollider> childABodies = new List <JCollider>();
                List <JCollider> childBBodies = new List <JCollider>();

                for (var i = 0; i < bodies.Count; i++)
                {
                    var body = bodies[i];
                    if (JMeshOverlap.AABBOverlap(boundsChildA, body.meshFrame.AABB))
                    {
                        childABodies.Add(body);
                    }
                    if (JMeshOverlap.AABBOverlap(boundsChildB, body.meshFrame.AABB))
                    {
                        childBBodies.Add(body);
                    }
                }

                rootCollisionMap.subMaps = new List <CollisionMap>();
                rootCollisionMap.subMaps.Add(GenerateMapFor(childABodies, maxNumberOfElements, boundsChildA));
                rootCollisionMap.subMaps.Add(GenerateMapFor(childBBodies, maxNumberOfElements, boundsChildB));
            }

            return(rootCollisionMap);
        }
        void LateUpdate()
        {
            pushPairs.Clear();
            collisionMapQueue.Clear();

            var allActiveJColliders       = JColliderContainer.INSTANCE.ActiveColliders();
            var lengthAllActiveJColliders = allActiveJColliders.Count;

            if (lengthAllActiveJColliders == 0)
            {
                return;
            }

            // Update bounds, vertices and normals for each collider based on their transform
            for (int i = 0; i < lengthAllActiveJColliders; i++)
            {
                var collider = allActiveJColliders[i];
                collider.meshFrame = JMesh.FromMeshAndTransform(collider.meshIdentity, collider.meshFilter.transform.localToWorldMatrix);
            }

            var completedCollisionsThisFrame = new HashSet <JCollisionPair>();
            var collisionMap = CollisionMap.GenerateMapFor(allActiveJColliders, 4, CameraHelper.GetCameraWorldCoordinateBounds());

            collisionMapQueue.Add(collisionMap);
            while (collisionMapQueue.HasNext())
            {
                var currentCollisionMap = collisionMapQueue.Next();
                if (currentCollisionMap.bodies != null)
                {
                    DoCollisionChecks(currentCollisionMap.bodies, completedCollisionsThisFrame);
                }
                else
                {
                    collisionMapQueue.Add(currentCollisionMap.subMaps);
                }
            }

            enterStayExitManager.CompleteFrame();
        }