Unity DOTS how do I change the Motion Type in Physics Body when two objects collide?

Greetings, I ran into such a problem there is a wall that consists of many cubes, when I hit a sphere, I began to detect collisions and apply force to the object I encountered, but the joke is that the object I’m adjusting to has Motion Type Kinematic and I need to change it again to Dynamic when the sphere collided and cube. How do I do this? How do I get an instance of the Physics Body object to change the Motion Type in a collision?

Here’s the correct forum: Unity Engine - Unity Discussions

I’ll move your post for you.

1 Like

I have several code scripts that I can demonstrate.
First, spawn spheres in hybrid rendering:

using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

public class Shoot : MonoBehaviour
{
    public GameObject Bullet;
    public Transform PointSpawn;
    public Camera Cam;


    private Entity _sphereEntity;
    private EntityManager _entityManager;
    private BlobAssetStore _blobAssetStore;
    private GameObjectConversionSettings _conversionSettings;


    private void Start()
    {
        EntityObjectSetup();
    }

    private void EntityObjectSetup()
    {
        _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        _blobAssetStore = new BlobAssetStore();
        _conversionSettings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, _blobAssetStore);
        _sphereEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(Bullet, _conversionSettings);
    }


    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            var entity = _entityManager.Instantiate(_sphereEntity);
            var translation = new Translation
            {
                Value = new float3(PointSpawn.transform.position.x, PointSpawn.transform.position.y, PointSpawn.transform.position.z)
            };
            var entityECS = new BulletECS()
            {
                Direction = Cam.transform.forward,
                IsSpawned = false,
                Speed = 70,
            };
            _entityManager.SetComponentData(entity, entityECS);
            _entityManager.SetComponentData(entity, translation);
        }
    }

    private void OnApplicationQuit()
    {
        _blobAssetStore.Dispose();
    }
}

Secondly, applying the physics of linear momentum to the sphere is here:
P.S. There is also the code responsible for applying collisions to the cube

using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Extensions;

public class PhysicsECS : ComponentSystem
{
    protected override void OnUpdate()
    {
        Entities.ForEach
            (
        (ref PhysicsVelocity velocity, ref PhysicsMass physicsMass,ref BulletECS shoot) =>
        {
            if (!shoot.IsSpawned)
            {
                var forceVector = (float3)shoot.Direction * shoot.Speed;
                velocity.ApplyLinearImpulse(physicsMass, forceVector);
                shoot.IsSpawned = true;
            }
        });

        Entities.ForEach
           (
       (ref PhysicsVelocity velocity, ref PhysicsMass physicsMass, ref FragmentECS fragment) =>
       {
           if (fragment.IsDelected)
           {
               var forceVector = (float3)fragment.Direction * fragment.Speed;
               velocity.ApplyLinearImpulse(physicsMass, forceVector);
               fragment.IsDelected = false;
           }
       });
    }
}

Thirdly, these are the components that are on the sphere on the cube fragment:

using Unity.Entities;
using UnityEngine;
[GenerateAuthoringComponent]
public struct BulletECS : IComponentData
{
    public Vector3 Direction;
    public int Speed;
    public bool IsSpawned;
}
using Unity.Entities;
using UnityEngine;

[GenerateAuthoringComponent]
public struct FragmentECS : IComponentData
{
    public Vector3 Direction;
    public int Speed;
    public bool IsDelected;
}

At the output I get this result:

8418726--1113636--ezgif.com-gif-maker.gif

All I have to do is change the Motion Type on collision here:

using Unity.Burst;
using Unity.Entities;
using Unity.Jobs;
using Unity.Physics;
using Unity.Physics.Systems;
using UnityEngine;

public class CollisionECS : JobComponentSystem
{
    private BuildPhysicsWorld buildPhysicsWorldSystem;
    private StepPhysicsWorld stepPhysicsWorldSystem;
    private EndSimulationEntityCommandBufferSystem commandBufferSystem;

    protected override void OnCreate()
    {
        buildPhysicsWorldSystem = World.GetExistingSystem<BuildPhysicsWorld>();
        stepPhysicsWorldSystem = World.GetExistingSystem<StepPhysicsWorld>();
        commandBufferSystem = World.GetExistingSystem<EndSimulationEntityCommandBufferSystem>();
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var collision = new CollisionJob()
        {
            fragment = GetComponentDataFromEntity<FragmentECS>(),
            component = GetComponentDataFromEntity<BulletECS>(),
        };
        JobHandle jobHandle = collision.Schedule(
           stepPhysicsWorldSystem.Simulation,
           ref buildPhysicsWorldSystem.PhysicsWorld,
           inputDeps);
        commandBufferSystem.AddJobHandleForProducer(jobHandle);
        return jobHandle;
    }

    private struct CollisionJob : ICollisionEventsJob
    {
        public ComponentDataFromEntity<BulletECS> component;
        public ComponentDataFromEntity<FragmentECS> fragment;
        public void Execute(CollisionEvent collisionEvent)
        {
            if (component.HasComponent(collisionEvent.EntityB))
            {
                if (fragment.HasComponent(collisionEvent.EntityA))
                {
                    var fragmentUpdate = fragment[collisionEvent.EntityA];
                    var bullet = component[collisionEvent.EntityB];
                    fragmentUpdate.Direction = bullet.Direction;
                    fragmentUpdate.Speed = bullet.Speed;
                    fragmentUpdate.IsDelected = true;
                    fragment[collisionEvent.EntityA] = fragmentUpdate;
                    Debug.Log($"Collision between entities { collisionEvent.EntityA.Index } and { collisionEvent.EntityB.Index }");
                }
            }
        }
    }
}

How do I do that? If with a regular Rigidbody I could make isKinematic false?

Okay, since, as usual, no one knows the answers to my questions on this forum, I’ll tell you how I did it: After looking through what types of data hybrid rendering uses, I came across PhysicsGravityFactor and PhysicsMass.InverseMass, I forcibly change these parameters in the PhysicsECS class and it works, but not quite correctly as I would like because Kinematic body it has only a direction and is completely frozen, so now I’m going to try to redo it into layers to improve the result

using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Extensions;

public class PhysicsECS : ComponentSystem
{
    protected override void OnUpdate()
    {
        Entities.ForEach
            (
        (ref PhysicsVelocity velocity, ref PhysicsMass physicsMass,ref BulletECS shoot) =>
        {
            if (!shoot.IsSpawned)
            {
                var forceVector = (float3)shoot.Direction * shoot.Speed;
                velocity.ApplyLinearImpulse(physicsMass, forceVector);
                shoot.IsSpawned = true;
            }
        });

        Entities.ForEach
           (
       (ref PhysicsVelocity velocity, ref PhysicsMass physicsMass,ref PhysicsGravityFactor f, ref FragmentECS fragment) =>
       {
           if (fragment.IsDelected)
           {
               f.Value = 2.0f;
               physicsMass.InverseMass = 2.0f;
               var forceVector = (float3)fragment.Direction * fragment.Speed;
               velocity.ApplyLinearImpulse(physicsMass, forceVector);
               fragment.IsDelected = false;
           }
       });
    }
}

Where are these dedicated DOTS users when I need them so badly?

In general, I achieved the result I needed, I just needed to change the value of Iteria to unfreeze the objects, thanks to Vyacheslav for this post: From kinematic to dynamic after a collision
See my final version:

using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Extensions;

public class PhysicsECS : ComponentSystem
{
    protected override void OnUpdate()
    {
        Entities.ForEach
            (
        (ref PhysicsVelocity velocity, ref PhysicsMass physicsMass,ref BulletECS shoot) =>
        {
            if (!shoot.IsSpawned)
            {
                var forceVector = (float3)shoot.Direction * shoot.Speed;
                velocity.ApplyLinearImpulse(physicsMass, forceVector);
                shoot.IsSpawned = true;
            }
        });

        Entities.ForEach
           (
       (ref PhysicsVelocity velocity,ref PhysicsCollider physicsCollider,ref PhysicsGravityFactor f, ref PhysicsMass physicsMass, ref FragmentECS fragment) =>
       {
           if (fragment.IsDelected)
           {
               physicsMass.InverseMass = 3.0f;
               physicsMass.InverseInertia = 4.0f;
               f.Value = 5.0f;
               fragment.IsDelected = false;
           }
       });
    }
}

The only problem is that it will work the same way as in TearDown, that is, hanging objects may remain in the air