Home Game Development entity component system – In Unity 2021.3.29(built-in render pipeline, entities 0.51.1-preview.21), what is the proper way of DOTS based collision detection?

entity component system – In Unity 2021.3.29(built-in render pipeline, entities 0.51.1-preview.21), what is the proper way of DOTS based collision detection?

0
entity component system – In Unity 2021.3.29(built-in render pipeline, entities 0.51.1-preview.21), what is the proper way of DOTS based collision detection?

[ad_1]

Packages Installed:

Entities: com.unity.entities Version 0.51.1-preview.21
Documentation URL: https://docs.unity3d.com/Packages/[email protected]/manual/index.html

Physics: com.unity.physics Version 0.51.0-preview.32 – June 15, 2022
Documentation URL: https://docs.unity3d.com/Packages/[email protected]/manual/index.html

Havok Physics: com.havok.physics Version 0.50.0-preview.24 – March 16, 2022
Documentation URL: https://docs.unity3d.com/Packages/[email protected]/manual/index.html

Hybrid Renderer: com.unity.rendering.hybrid Version 0.51.1-preview.21 – August 02, 2022
Documentation URL: https://docs.unity3d.com/Packages/[email protected]/manual/index.html

enter image description here

The entity for which I want to detect collisions for are child objects in a prefab, as illustrated in the above image(heartslime_entity).

I have attached both Physics Shape and Physics Body on each entity, ConvertToEntity.cs(built-in) and a custom authoring script that completes the conversion to an entity and adds component data. For some reason that I have no idea how to debug for, these entities, after they are instantiated, are not properly colliding with each other. I don’t see them colliding physically nor do they properly register a CollisionEvent in an implemented ICollisionEventsJob. Here is my main SystemBase script that has multiple responsibilities, as well as detecting collisions.
VertexUpdater.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Jobs;
using Unity.Collections;
using HerminkasGams.SpriteSquash;
using System.Linq;
using UnityEditor;
using Unity.Burst;
using Unity.Collections.LowLevel.Unsafe;
using System.Runtime.Serialization;
using Unity.VisualScripting;
using System.Security.Cryptography;
using System;
using Unity.Physics;
using Unity.Physics.Systems;
// using Unity.Physics.Stateful;
using UnityEngine.Rendering;
using Unity.Mathematics;

public struct MeshDataComponent : IComponentData
{
    public DynamicBuffer<VertexBufferElement> vertices;
}

//[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
// [UpdateAfter(typeof(PhysicsInitializeGroup))]
// [UpdateAfter(typeof(PhysicsSimulationGroup))]
//[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
//[UpdateAfter(typeof(StatefulTriggerEventBufferSystem))]
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup)), UpdateBefore(typeof(EndFramePhysicsSystem)), UpdateAfter(typeof(StepPhysicsWorld))]
public partial class VertexUpdater : SystemBase
{
    public GameObject ObjectManager;
    public ObjectManagerController objectManagerController;
    private BuildPhysicsWorld _buildPhysicsWorld;
    private StepPhysicsWorld _stepPhysicsWorld;
    private EndFramePhysicsSystem endFramePhysicsSystem;
    private EndSimulationEntityCommandBufferSystem endSimulationEntityCommandBufferSystem;

    [HideInInspector] public List<SpriteMeshModifier> spriteMeshModifiers = new List<SpriteMeshModifier>();
    // [HideInInspector] public List<Vertex> vertices = new List<Vertex>();  // List of vertices; each element of this variable is what I must make magnetic
    bool merged = false;

    private struct VertexCopy {
        public Vector3 _currentPos;
        public Vector3 _initialPos;
        public Vector3 _revertingPos;
        public int _metaballEdgePointCount;

        //_parentSpriteMeshModifier variables:
        public Vector3 _parentSpriteMeshModifierPosition;
        public Quaternion _parentSpriteMeshModifierRotation;
        public Vector3 _parentSpriteMeshModifierLocalscale;

        [HideInInspector]public int _index;
        [HideInInspector]public Vector3 _closestMagnetPoint;
        [HideInInspector] public float _minDistanceToInitialpos;
    
        public VertexCopy(Vector3 pos, Vector3 initialPos, int index, int metaballEdgePointCount, Vector3 parentSpriteMeshModifierPosition, Quaternion parentSpriteMeshModifierRotation, Vector3 parentSpriteMeshModifierLocalscale, Vector3 closestMagnetPoint) {
            _currentPos = pos;
            _initialPos = initialPos;
            _revertingPos = pos;
            _index = index;
            _metaballEdgePointCount = metaballEdgePointCount;
            //_parentSpriteMeshModifierPosition variables
            _parentSpriteMeshModifierPosition = parentSpriteMeshModifierPosition;
            _parentSpriteMeshModifierRotation = parentSpriteMeshModifierRotation;
            _parentSpriteMeshModifierLocalscale = parentSpriteMeshModifierLocalscale;
            _closestMagnetPoint = closestMagnetPoint;
            _minDistanceToInitialpos = 0;
        }

        public (Vector3, float) FindNearestMagnetPoint(NativeArray<Vector3> metaballVertexPositionArray) {
            float minDistanceUnaltered = 99999;
            // float minDistanceToInitialposUnaltered = 0;
            Vector3 scpInitial = _parentSpriteMeshModifierRotation * _initialPos;
            Vector3 pointInitial = new Vector3(scpInitial.x * _parentSpriteMeshModifierLocalscale.x, scpInitial.y * _parentSpriteMeshModifierLocalscale.y, scpInitial.z * _parentSpriteMeshModifierLocalscale.z) + _parentSpriteMeshModifierPosition;
            //Compute the nearest metaball edge magnet point by iterating through them if metaballEdgePointVertexGOs is not empty
            if (_metaballEdgePointCount > 0) {
                int index = 0;
                Vector3 scp = _parentSpriteMeshModifierRotation * _currentPos;
                Vector3 point = new Vector3(scp.x * _parentSpriteMeshModifierLocalscale.x, scp.y * _parentSpriteMeshModifierLocalscale.y, scp.z * _parentSpriteMeshModifierLocalscale.z) + _parentSpriteMeshModifierPosition;
                
                float minDistance = 99999;

                //Will iterate through metaballEdgePointVertexGOs to find closest
                //Vector3 scpMagnet = new Vector3(0,0,0);
                for (int i = 0; i < _metaballEdgePointCount; i++)
                {   
                    float dis = Vector2.Distance(point, metaballVertexPositionArray[i]);
                    if (dis < minDistance)
                    {
                        index = i;
                        minDistance = dis;
                    }
                }
                _minDistanceToInitialpos = Vector2.Distance(point, pointInitial);
                
                //Invert metaballVertexPositionArray[index] back to vertex coordinates
                Vector3 vec1 = metaballVertexPositionArray[index] - _parentSpriteMeshModifierPosition;
                Vector3 vec2 = _parentSpriteMeshModifierLocalscale;
                Vector3 result = new Vector3(vec1.x / vec2.x, vec1.y / vec2.y, vec1.z / vec2.z);
                Vector3 scpLocal = Quaternion.Inverse(_parentSpriteMeshModifierRotation) * (result);
                return (scpLocal, minDistance);
            }
            return (new Vector3(0,0,-1), minDistanceUnaltered);
        }
    }

    [BurstCompile]
    private struct ComputeJob : IJobFor {
        [NativeDisableParallelForRestriction] public NativeArray<VertexCopy> vertexCopyArray;
        //[NativeDisableParallelForRestriction] public NativeArray<Vector3> updatePositionsArray;
        // Pointers to the start of the mesh.vertices array
        // [NativeDisableParallelForRestriction][NativeDisableUnsafePtrRestriction] public Vector3* meshVertices;
        // [NativeDisableParallelForRestriction][NativeDisableUnsafePtrRestriction] public Vector3* Vertices;
        [ReadOnly] public NativeArray<Vector3> metaballVertexPositionArray;
        
        public unsafe void Execute(int index) {
            VertexCopy vertexCopy = vertexCopyArray[index];
            float minDistance = 9999;
            (vertexCopy._closestMagnetPoint, minDistance) = vertexCopy.FindNearestMagnetPoint(metaballVertexPositionArray);
            //If closest distance is less than threshold
            if (minDistance < 0.8f) {
                //vertexCopy._currentPos = vertexCopy._closestMagnetPoint;
                Vector3 updatePosition = Vector3.Lerp(vertexCopy._closestMagnetPoint, vertexCopy._initialPos, (vertexCopy._minDistanceToInitialpos + minDistance * (1 - vertexCopy._minDistanceToInitialpos / 0.8f)) / (1.0f + minDistance * (1 - vertexCopy._minDistanceToInitialpos / 0.8f)));
                //updatePositionsArray[index] = updatePosition;
                vertexCopy._currentPos = updatePosition;
                vertexCopyArray[index] = vertexCopy;
                //UnsafeUtility.WriteArrayElement(meshVertices, vertCount + n, vertexCopyArray);
            }
            else {
                //Rewrite to reset position
                vertexCopy._currentPos = vertexCopy._initialPos;
                //updatePositionsArray[index] = vertexCopy._initialPos;
                vertexCopyArray[index] = vertexCopy;
            }
        }
    }

    // [BurstCompile]
    public struct CollisionEventJob : ICollisionEventsJob
    {
        public ComponentDataFromEntity<IsStaticComponent> isStatic;
        public ComponentDataFromEntity<SizeComponent> size;
        public ComponentDataFromEntity<MarkForDelete> markForDelete;
 
        public void Execute(CollisionEvent evt)
        {
            Debug.Log("Fuck");
            // Ensure both entities have the IsStaticComponent.
            if (!isStatic.HasComponent(evt.EntityA) || !isStatic.HasComponent(evt.EntityB))
            {
                return; // At least one of the entities doesn't have the required component, so we skip.
            }
            Entity staticEntity;
            Entity dynamicEntity;

            IsStaticComponent entityAStatic = isStatic[evt.EntityA];
            IsStaticComponent entityBStatic = isStatic[evt.EntityB];

            // Determine which entity is static and which is dynamic.
            if(entityAStatic.isStatic && !entityBStatic.isStatic)
            {
                staticEntity = evt.EntityA;
                dynamicEntity = evt.EntityB;
            }
            else if(!entityAStatic.isStatic && entityBStatic.isStatic)
            {
                staticEntity = evt.EntityB;
                dynamicEntity = evt.EntityA;
            }
            else
            {
                // Either both are static or both are dynamic.
                // Randomly select one to be the static entity and the other to be the dynamic entity.
                bool randomDecision = UnityEngine.Random.value > 0.5f;
                if (randomDecision)
                {
                    staticEntity = evt.EntityA;
                    dynamicEntity = evt.EntityB;
                }
                else
                {
                    staticEntity = evt.EntityB;
                    dynamicEntity = evt.EntityA;
                }
            }

            // Modify the size of the static entity by adding the size of the dynamic entity.
            SizeComponent staticSize = size[staticEntity];
            SizeComponent dynamicSize = size[dynamicEntity];

            float currentArea = staticSize.width * staticSize.height;
            float updatedArea = currentArea + dynamicSize.width * dynamicSize.height;
            staticSize.width = (updatedArea/currentArea)*staticSize.width;
            staticSize.height = (updatedArea/currentArea)*staticSize.height;

            size[staticEntity] = staticSize;

            // Mark the dynamic entity for deletion.
            //markForDelete[dynamicEntity] = new MarkForDelete { markForDelete = true };
        }
    }

    protected override void OnStartRunning()
    {
        ObjectManager = GameObject.Find("ObjectManager");
        objectManagerController = ObjectManager.GetComponent<ObjectManagerController>();
        // GameObject.Find("SpriteMeshModifier");
        // EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        // // Create an Entity "archetype" that will have MyComponent
        // EntityArchetype spriteMeshModifierArchetype = entityManager.CreateArchetype(typeof(SpriteMeshModifier));
        // // Create an entity with that archetype
        // Entity spriteMeshModifierEntity = entityManager.CreateEntity(spriteMeshModifierArchetype);

        List<GameObject> waterslimesDisplay = objectManagerController.colorSlimesDisplayGlobal;
        foreach (GameObject waterslimeDisplay in waterslimesDisplay) {
            spriteMeshModifiers.Add(waterslimeDisplay.GetComponent<SpriteMeshModifier>());
        }
        // Get references to the required physics systems
        _buildPhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>();
        _stepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
        endSimulationEntityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
        // Register the physics system as read-write or read-only based on your requirements
        this.RegisterPhysicsRuntimeSystemReadWrite();
        base.OnStartRunning();
    }

    protected override void OnUpdate()
    {
        spriteMeshModifiers = new List<SpriteMeshModifier>();
        List<GameObject> waterslimesDisplay = objectManagerController.colorSlimesDisplayGlobal;
        foreach (GameObject waterslimeDisplay in waterslimesDisplay) {
            spriteMeshModifiers.Add(waterslimeDisplay.GetComponent<SpriteMeshModifier>());
        }
        consolidateGameObjectToPos2D(Vector3.zero, 0.6f);
        //revertGameObjectToInitialpos2D(0.6f);
        CallJobs();
        //QueryVelocitiesAndUpdateStaticComponents();

        // Collision Job
        CollisionEventJob collisionJob = new CollisionEventJob
        {
            isStatic = GetComponentDataFromEntity<IsStaticComponent>(),
            size = GetComponentDataFromEntity<SizeComponent>(),
            markForDelete = GetComponentDataFromEntity<MarkForDelete>()
        };
        // Schedule the job with the dependencies of the StepPhysicsWorld system
        JobHandle jobHandle = collisionJob.Schedule(_stepPhysicsWorld.Simulation, Dependency);

        //Code that is necessary for some reason
        endSimulationEntityCommandBufferSystem.AddJobHandleForProducer(Dependency);

        // Make sure to complete the job before the end of the frame
        // This line is necessary if you need to read the job data in the same frame
        jobHandle.Complete();

        // Update the Dependency handle
        Dependency = jobHandle;

        //Update the actual MonoBehavior game objects based on conditions of the entities
        //UpdateMonoBehaviorGameObjectsAfterCollision();
        //throw new System.NotImplementedException();
    }

    private unsafe void CallJobs() {
        foreach (SpriteMeshModifier spriteMeshModifier in spriteMeshModifiers) {
            //&& spriteMeshModifier._isRegenerated
            if(spriteMeshModifier.vertices.Count > 0 && spriteMeshModifier._isSerializedRegenerated && spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count > 0) {
                NativeArray<VertexCopy> vertexCopies = new NativeArray<VertexCopy>(spriteMeshModifier.vertices.Count, Allocator.TempJob);
                //NativeArray<Vector3> updatePositions = new NativeArray<Vector3>(spriteMeshModifier.vertices.Count, Allocator.TempJob);
                NativeArray<Vector3> metaballVertexPositions = new NativeArray<Vector3>(spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count, Allocator.TempJob);
                
                CopyThingsTo(ref vertexCopies, ref metaballVertexPositions, spriteMeshModifier);
                // Do heavy computation in a job
                ComputeJob job = new ComputeJob() {
                    vertexCopyArray = vertexCopies,
                    //updatePositionsArray = updatePositions,
                    metaballVertexPositionArray = metaballVertexPositions,
                };
                job.ScheduleParallel(vertexCopies.Length, 64, default).Complete();
                //spriteMeshModifier.GetComponent<MeshFilter>().sharedMesh.vertices = mesh.vertices;
                //Dispose obsolete NativeArrays
                // updatePositions.Dispose();
                metaballVertexPositions.Dispose();

                //Update SpriteMeshmodifier.vertices' currentPos
                for (int i = 0; i < spriteMeshModifier.vertices.Count; i++) {
                    spriteMeshModifier.vertices[i]._closestMagnetPoint = vertexCopies[i]._closestMagnetPoint;
                    spriteMeshModifier.vertices[i].currentPos = vertexCopies[i]._currentPos;
                }
                spriteMeshModifier.UpdateMesh();

                // Don't forget to dispose
                vertexCopies.Dispose();
            }
            else if(spriteMeshModifier.vertices.Count > 0 && spriteMeshModifier._isSerializedRegenerated && spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count <= 0) {
                // Debug.Log("metaballEdgePointVertices.Count: " + spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count);
                //Reset vertices for each game object
                spriteMeshModifier.Reset();
            }
        }
    }

    //ref NativeArray<Vector3> updatePositionsArray, 
    private void CopyThingsTo(ref NativeArray<VertexCopy> copiesArray, ref NativeArray<Vector3> metaballVertexPositionsArray, SpriteMeshModifier spriteMeshModifier) {
        for (int i = 0; i < spriteMeshModifier.vertices.Count; i++) {
            Vertex vertex = spriteMeshModifier.vertices[i];
            copiesArray[i] = new VertexCopy(vertex.currentPos, vertex.initialPos, i, vertex._objectManagerController.metaballEdgePointVertices.Count, vertex._parentSpriteMeshModifier.transform.parent.gameObject.transform.position, vertex._parentSpriteMeshModifier.gameObject.transform.rotation, vertex._parentSpriteMeshModifier.gameObject.transform.localScale, vertex._closestMagnetPoint);
            //updatePositionsArray[i] = new Vector3(vertex.currentPos.x, vertex.currentPos.y, vertex.currentPos.z);
        }
        for (int i = 0; i < spriteMeshModifier.objectManagerController.metaballEdgePointVertices.Count; i++) {
            Vector3 metaballEdgePointVertex = spriteMeshModifier.objectManagerController.metaballEdgePointVertices[i];
            metaballVertexPositionsArray[i] = metaballEdgePointVertex;
        }
    }

    // private void AssignComputedValues(in NativeArray<VertexCopy> copiesArray, SpriteMeshModifier spriteMeshModifier) {
    //     for (int i = 0; i < spriteMeshModifier.vertices.Count; ++i) {
    //         spriteMeshModifier.vertices[i]._closestMagnetPoint = copiesArray[i]._closestMagnetPoint;
    //     }
    // }

    private void UpdatePositions(NativeArray<VertexCopy> copiesArray, SpriteMeshModifier spriteMeshModifier) {
        spriteMeshModifier.UpdateMesh();
    }
    private void consolidateGameObjectToPos2D(Vector3 pos, float speed) {
        if(!merged) {
            merged = true;
            foreach (SpriteMeshModifier spriteMeshModifier in spriteMeshModifiers) {
                if(spriteMeshModifier.transform.parent.gameObject.transform.position != pos) {
                    //Compute GCD Vector3 between spriteMeshModifier.transform.parent.gameObject.transform.position and Vector3.zero
                    Vector3 deltaVector = pos - spriteMeshModifier.transform.parent.gameObject.transform.position;
                    //int gcd = binaryGCD(Math.Abs((int)deltaVector.x), Math.Abs((int)deltaVector.y));
                    
                    deltaVector = new Vector3(speed * (deltaVector.x / System.Math.Abs(deltaVector.x)), speed * (deltaVector.y / System.Math.Abs(deltaVector.x)), deltaVector.z);
                    spriteMeshModifier.transform.parent.gameObject.transform.position += deltaVector;
                    
                    if((spriteMeshModifier.transform.parent.gameObject.transform.position.x > pos.x + 0.01f) || (spriteMeshModifier.transform.parent.gameObject.transform.position.x < pos.x - 0.01f) || (spriteMeshModifier.transform.parent.gameObject.transform.position.y > pos.y + 0.01f) || (spriteMeshModifier.transform.parent.gameObject.transform.position.y < pos.y - 0.01f)) {
                        merged = false;
                    }
                }
            }
        }
    }
    private void revertGameObjectToInitialpos2D(float speed) {
        if(merged) {
            merged = false;
            foreach (SpriteMeshModifier spriteMeshModifier in spriteMeshModifiers) {
                Vector3 initialPos = spriteMeshModifier.colorslimeMainInitialPos;
                if(spriteMeshModifier.transform.parent.gameObject.transform.position != initialPos) {
                    //Compute GCD Vector3 between spriteMeshModifier.transform.parent.gameObject.transform.position and Vector3.zero
                    Vector3 deltaVector = initialPos - spriteMeshModifier.transform.parent.gameObject.transform.position;
                    //int gcd = binaryGCD(Math.Abs((int)deltaVector.x), Math.Abs((int)deltaVector.y));
                    
                    deltaVector = new Vector3(speed * (deltaVector.x / System.Math.Abs(deltaVector.x)), speed * (deltaVector.y / System.Math.Abs(deltaVector.x)), deltaVector.z);
                    spriteMeshModifier.transform.parent.gameObject.transform.position += deltaVector;
                    
                    if((spriteMeshModifier.transform.parent.gameObject.transform.position.x > initialPos.x + 0.001f) || (spriteMeshModifier.transform.parent.gameObject.transform.position.x < initialPos.x - 0.001f) || (spriteMeshModifier.transform.parent.gameObject.transform.position.y > initialPos.y + 0.001f) || (spriteMeshModifier.transform.parent.gameObject.transform.position.y < initialPos.y - 0.001f)) {
                        merged = true;
                    }
                }
            }
        }
    }
    private void QueryVelocitiesAndUpdateStaticComponents() {
        Entities.WithAll<IsStaticComponent>().ForEach(
        (ref PhysicsVelocity velocity, ref IsStaticComponent isStatic) =>
        {
            isStatic.isStatic = math.length(velocity.Linear) < 0.0001f; 
        }).Run();
    }
    private void UpdateMonoBehaviorGameObjectsAfterCollision() {
        EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        foreach (SpriteMeshModifier spriteMeshModifier in spriteMeshModifiers) {
            GameObject gameObjectMain = spriteMeshModifier.transform.parent.gameObject;
            GameObject gameObjectDisplay = spriteMeshModifier.gameObject;
            Entity entity = gameObjectMain.GetComponent<HeartSlimeMainController>().entityWrapper.GetComponent<SlimeAuthoring>().thisEntity;
            // Check if entity exists (extra caution)
            if (!entityManager.Exists(entity))
                continue;
            // Check if entity has the MarkForDelete component and if it's set to true
            if (entityManager.HasComponent<MarkForDelete>(entity)) 
            {
                MarkForDelete markForDelete = entityManager.GetComponentData<MarkForDelete>(entity);
                if (markForDelete.markForDelete) 
                {
                    // Delete the GameObject and continue to the next iteration
                    gameObjectMain.GetComponent<HeartSlimeMainController>().DestroyGameObject();
                    continue;
                }
            }
            // If not deleted, modify the size based on the SizeComponent
            if (entityManager.HasComponent<SizeComponent>(entity)) 
            {
                SizeComponent sizeComponent = entityManager.GetComponentData<SizeComponent>(entity);
                MeshRenderer meshRenderer = gameObjectDisplay.GetComponent<MeshRenderer>();
                float previousWidth = meshRenderer.bounds.size.x;
                float previousHeight = meshRenderer.bounds.size.y;
                float updatedWidth = sizeComponent.width;
                float updatedHeight = sizeComponent.height;
                float widthScaleFactor = updatedWidth / previousWidth;
                float heightScaleFactor = updatedHeight / previousHeight;

                // Assuming you want to modify the local scale of the gameObject, based on sizeComponent.size
                Vector3 previousScale = spriteMeshModifier.gameObject.transform.localScale;
                spriteMeshModifier.gameObject.transform.localScale = new Vector3(previousScale.x * widthScaleFactor, previousScale.y * heightScaleFactor, previousScale.z);
            }
        }
    }
    private int binaryGCD(int u, int v) {
        if (u == 0) return v;
        if (v == 0) return u;

        int shift;
        // Compute the greatest power of 2 dividing both u and v
        for (shift = 0; ((u | v) & 1) == 0; ++shift) {
            u >>= 1;
            v >>= 1;
        }

        while ((u & 1) == 0) u >>= 1;

        // From here on, u is always odd.
        do {
            // Remove all factors of 2 in v since they are not common
            while ((v & 1) == 0)  v >>= 1;

            // Now u and v are both odd. Swap if necessary so u <= v, then set v = v - u (which is even).
            if (u > v) {
                int temp = v; 
                v = u; 
                u = temp; // Swap u and v.
            }
        
            v = v - u; // Here v >= u.
        } while (v != 0);

        // Restore common factors of 2.
        return u << shift;
    }
}

Here is the custom authoring script:
SlimeAuthoring.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;

public class SlimeAuthoring : MonoBehaviour, IConvertGameObjectToEntity
{
    public float velocity;
    public Entity thisEntity;
    public GameObject targetSizeObject;

    public void SetEntity(Entity entity)
    {
        thisEntity = entity;
    }

    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        SetEntity(entity);
        dstManager.AddComponentData(entity, new IsStaticComponent { isStatic = true });

        // Extract size
        if(targetSizeObject != null)
        {
            MeshRenderer renderer = targetSizeObject.GetComponent<MeshRenderer>();
            if(renderer != null)
            {
                Vector3 size = renderer.bounds.size; // this gets the size of the mesh's bounding box
                dstManager.AddComponentData(entity, new SizeComponent { 
                    width = size.x,
                    height = size.y 
                }); // assuming SizeComponent takes a float for magnitude
            }
        }
    }
}
public struct IsStaticComponent : IComponentData
{
    public bool isStatic;
}

public struct SizeComponent : IComponentData
{
    public float width;
    public float height;
}

public struct MarkForDelete : IComponentData
{
    public bool markForDelete;
}

For my purposes, I cannot use URP, HDRP, or SRP, because there is a very important script somewhere else in the project that is dependent on the behavior of the built-in render pipeline. From what I have researched so far and what others state, the render pipeline should not matter when it comes to DOTS collision detection. So I assume there is a necessary step missing from what I have implemented so far, or something incorrect that is causing the entities to not properly collide with each other nor raise collision events. Please help me debug what this issue is.

[ad_2]