翻译自: http://tsubakit1.hateblo.jp/ 此人是日本Unity的开发者, 经常分享Unity最新的技术。
新的物理系统是什么?
Unity Physics是在ECS上运行物理的附加功能。这个物理操作并不完全是Unity过去使用的过去和安全的PhysX,而是使用C#完全重建的物理操作。
物理学的作用如下。
似乎可以使用Unity Physics和Havok Plugin切换内部行为,以便像以前那样使用状态进行物理操作。Havok插件适用于管理复杂状态。Havok插件尚未发布。
目前基于PhysX的Collider(旧的物理系统)和Unity Physics Collider (新的物理系统) 没有任何联系。使用Unity Physics时,所有其他碰撞器都需要转换为Unity Physics。
介绍环境就是
如果是旧的物理, 球体上添加刚体 会向下面的图一样滚下斜坡
Convert To Entity
添加到Spherer 。Convert To Entity
添加到Plane这个球与平面物体 从游戏物体转换成基于ECS-Unity Physics 。
转换后,它已转换为某些ComponentData,如下所示。请注意,在使用实体时,您需要引用下面的组件,而不是Rigidbody 。
所以 将序列化作为子场景。
这会将舞台上的GameObject转换为实体,这样您就可以在不插入的情况下加载反序列化。
Unity Physics有一个使用SubScene和ConvertToEntity从GameObject的RigidObject转换的流程,但也有自己的组件。
首先,○○碰撞系统已将PhysicsShape
集成到所有系统中。
Rigidbody `PhysicsBody
将是。
视频介绍: https://www.youtube.com/watch?v=yuqM-Z-NauU
在Unity的物理(GameObject使用PhysX)中,您可以设置OnCollisionEnter和OnTriggerEnter,但UnityPhysics目前仅提供低级API,这需要更加繁琐的处理。
要接收事件,您需要使用Collider
转化为PhysicsShape
。最重要的是PhysicsShape > Advance > Raises Collision Event
。
当被检查实体与另一个对象接触时,将发出一个事件。之后,我们将准备一个系统来检查已触发事件的内容。
首先,按系统执行顺序StepPhysicsWorld
执行。
[UpdateAfter(typeof(StepPhysicsWorld))] public class ItemGetSystem: ComponentSystem {
接下来,用于接收 碰撞事件,BuildPhysicsWorld 和
StepPhysicsWorld
将提供。
private BuildPhysicsWorld buildPhysicsWorldSystem; private StepPhysicsWorld stepPhysicsWorldSystem; protected override void OnCreate() { buildPhysicsWorldSystem = World.GetOrCreateSystem(); stepPhysicsWorldSystem = World.GetOrCreateSystem (); }
它是处理实际内容的部分。
buildPhysicsWorldSystem
从中获取PhysicsWorld。这包括目前所有碰撞者的坐标。
类似的stepPhysicsWorldSystem
从中来获得TriggerEvents
。在此存储由引发碰撞事件启用的对象发出的事件。
您所要做的就是让对象与EventTrigger键接触并处理事件。
protected override void OnUpdate() { var physicsWorld = buildPhysicsWorldSystem.PhysicsWorld; var triggerEvents = stepPhysicsWorldSystem.Simulation.TriggerEvents; var items = GetComponentDataFromEntity(true); foreach (var triggerEvent in triggerEvents) { // PhysicsWorld包含一个适用于所有物理操作的实体。 // //在triggerEvents中,为“引发碰撞事件”Raises Collision Event启用的对象存储触摸事件 //如果清洗了TriggerEvent的内容,则可以进行触摸判断 var bodyA = physicsWorld.Bodies[triggerEvent.BodyIndices.BodyAIndex]; var bodyB = physicsWorld.Bodies[triggerEvent.BodyIndices.BodyBIndex]; Process(bodyA.Entity, items); Process(bodyB.Entity, items); } }
全文代码在这里
using Unity.Entities;
using Unity.Physics.Systems;
[UpdateAfter(typeof(StepPhysicsWorld))]
public class ItemGetSystem: ComponentSystem
{
private BuildPhysicsWorld buildPhysicsWorldSystem;
private StepPhysicsWorld stepPhysicsWorldSystem;
protected override void OnCreate()
{
buildPhysicsWorldSystem = World.GetOrCreateSystem();
stepPhysicsWorldSystem = World.GetOrCreateSystem();
}
protected override void OnUpdate()
{
var physicsWorld = buildPhysicsWorldSystem.PhysicsWorld;
var triggerEvents = stepPhysicsWorldSystem.Simulation.TriggerEvents;
var items = GetComponentDataFromEntity(true);
foreach (var triggerEvent in triggerEvents)
{
// PhysicsWorld包含一个适用于所有物理操作的实体。
// //在triggerEvents中,为“引发碰撞事件”Raises Collision Event启用的对象存储触摸事件
//如果清洗了TriggerEvent的内容,则可以进行触摸判断
var bodyA = physicsWorld.Bodies[triggerEvent.BodyIndices.BodyAIndex];
var bodyB = physicsWorld.Bodies[triggerEvent.BodyIndices.BodyBIndex];
Process(bodyA.Entity, items);
Process(bodyB.Entity, items);
}
}
void Process(Entity entity, ComponentDataFromEntity items)
{
if( items.Exists(entity))
{
PostUpdateCommands.DestroyEntity(entity);
UnityEngine.Debug.Log("you get item!");
}
}
}
应该注意的是,Unity Physics没有状态,因此似乎不能采取诸如“碰撞开始”,“ 碰撞中”和“ 碰撞结束”之类的事件。
如果只想在特定对象之间执行碰撞事件,则可以确定在ComponentDataFromEntity中是否具有特定组件,如上面的代码中所示,或者Custom Flag
通过设置它BodyA.CustomData
。
如果您不想简单地触摸,最好调整碰撞滤波器。这里的界面是我希望你再做一点的地方。
我尝试使用JobSystem运行上述过程。
关键是要设置处理依赖性。UnityPhysics使用ECS但不适用于ECS,因此它不会自动解决处理依赖性。你需要从系统中带来它。
inputDeps = JobHandle.CombineDependencies(
inputDeps,
buildPhysicsWorldSystem.FinalJobHandle,
stepPhysicsWorldSystem.FinalSimulationJobHandle);
整个文本看起来像这样。
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Systems;
[UpdateAfter(typeof(StepPhysicsWorld)), UpdateBefore(typeof(EndFramePhysicsSystem))]
public class ItemGetSystem : JobComponentSystem
{
BuildPhysicsWorld buildPhysicsWorldSystem;
StepPhysicsWorld stepPhysicsWorldSystem;
EntityCommandBufferSystem bufferSystem;
protected override void OnCreate()
{
buildPhysicsWorldSystem = World.GetOrCreateSystem();
stepPhysicsWorldSystem = World.GetOrCreateSystem();
bufferSystem = World.GetOrCreateSystem();
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
inputDeps = JobHandle.CombineDependencies(
inputDeps,
buildPhysicsWorldSystem.FinalJobHandle,
stepPhysicsWorldSystem.FinalSimulationJobHandle);
inputDeps = new HitAndDestroyJob {
World = buildPhysicsWorldSystem.PhysicsWorld,
TriggerEvents = stepPhysicsWorldSystem.Simulation.TriggerEvents,
items = GetComponentDataFromEntity(true),
commandBuffer = bufferSystem.CreateCommandBuffer(),
}.Schedule(1, 1, inputDeps);
bufferSystem.AddJobHandleForProducer(inputDeps);
return inputDeps;
}
struct HitAndDestroyJob : IJobParallelFor
{
[ReadOnly] public PhysicsWorld World;
[ReadOnly] public TriggerEvents TriggerEvents;
[ReadOnly] public ComponentDataFromEntity items;
[ReadOnly] public EntityCommandBuffer commandBuffer;
public void Execute(int index)
{
foreach (var triggerEvent in TriggerEvents)
{
GetItem(World.Bodies[triggerEvent.BodyIndices.BodyAIndex].Entity);
GetItem(World.Bodies[triggerEvent.BodyIndices.BodyBIndex].Entity);
}
}
void GetItem(Entity entity)
{
if (items.Exists(entity) == false)
return;
commandBuffer.DestroyEntity(entity);
UnityEngine.Debug.Log("you get item!");
}
}
}