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.
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:
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