關於Unity 2019中的新物理系統相關

翻譯自: http://tsubakit1.hateblo.jp/ 此人是日本Unity的開發者, 經常分享Unity最新的技術。 

F:ID:tsubaki_t1:20190420231232克:平紋

         新的物理系統是什麼?

         Unity Physics是在ECS上運行物理的附加功能。這個物理操作並不完全是Unity過去使用過去和安全的PhysX,而是使用C#完全重建的物理操作。

物理學的作用如下。

  • 搜索空間以進行碰撞等(接觸判斷,射線判斷)
  • 實際上移動物體(重力,彈跳,摩擦等)

F:ID:tsubaki_t1:20190420215138j:平紋

         似乎可以使用Unity Physics和Havok Plugin切換內部行爲,以便像以前那樣使用狀態進行物理操作。Havok插件適用於管理複雜狀態。Havok插件尚未發佈。

F:ID:tsubaki_t1:20190420220552j:平紋

        目前基於PhysX的Collider(舊的物理系統)和Unity Physics Collider  (新的物理系統) 沒有任何聯繫。使用Unity Physics時,所有其他碰撞器都需要轉換爲Unity Physics。

事前準備

介紹環境就是 

  • Unity 2019.1f2
  • Unity Physics preview1 0.0.2
  • Hybrid Renderer preview10 0.0.1

F:ID:tsubaki_t1:20190420221316j:平紋

暫時準備場景

      如果是舊的物理, 球體上添加剛體 會向下面的圖一樣滾下斜坡

F:ID:tsubaki_t1:20190420222657克:平紋

遷移到Unity Physics

  • Convert To Entity添加到Spherer 。
  • Convert To Entity添加到Plane

這個與平面物體  從遊戲物體轉換成基於ECS-Unity Physics 

F:ID:tsubaki_t1:20190420222954j:平紋

F:ID:tsubaki_t1:20190420223148j:平紋

轉換後,它已轉換爲某些ComponentData,如下所示。請注意,在使用實體時,您需要引用下面的組件,而不是Rigidbody 。

F:ID:tsubaki_t1:20190420225154j:平紋

加載一些東西,很多碰撞判斷

  1. 加載場景
  2. 使遊戲對象序列化
  3. 使組件序列化
  4. 生成ComponentData
  5. 銷燬GameObject
  6. 重複轉換爲實體 

所以 將序列化作爲子場景。

  • 從“現在準備場景”開始
  • 選擇Spherer和Plane並右鍵單擊
  • 從Selection中選擇New SubScene
  • 按SubScene 組件上的  Close

這會將舞臺上的GameObject轉換爲實體,這樣您就可以在不插入的情況下加載反序列化

F:ID:tsubaki_t1:20190420224852克:平紋

我想使用新添加的設置

Unity Physics有一個使用SubScene和ConvertToEntity從GameObject的RigidObject轉換的流程,但也有自己的組件

首先,○○碰撞系統已將PhysicsShape集成到所有系統中。 

F:ID:tsubaki_t1:20190420225530p:平紋

Rigidbody `PhysicsBody將是。

F:ID:tsubaki_t1:20190420230215j:平紋

          視頻介紹: https://www.youtube.com/watch?v=yuqM-Z-NauU   

 

 

使用Unity Physics做碰撞檢測

F:ID:tsubaki_t1:20190425223640克:平紋

在Unity的物理(GameObject使用PhysX)中,您可以設置OnCollisionEnter和OnTriggerEnter,但UnityPhysics目前僅提供低級API,這需要更加繁瑣的處理。

 

使用環境

  • Unity 2019.1f2
  • Unity Physics preview1 0.0.2

設置

要接收事件,您需要使用Collider轉化爲PhysicsShape。最重要的是PhysicsShape > Advance > Raises Collision Event 

F:ID:tsubaki_t1:20190425224053j:平紋

         當被檢查實體另一個對象接觸時,將發出一個事件。之後,我們將準備一個系統來檢查已觸發事件的內容。

首先,按系統執行順序StepPhysicsWorld執行。

[UpdateAfter(typeof(StepPhysicsWorld))]
public class ItemGetSystem: ComponentSystem
{

接下來,用於接收 碰撞事件,BuildPhysicsWorld 和 StepPhysicsWorld將提供。

    private BuildPhysicsWorld buildPhysicsWorldSystem;
    private StepPhysicsWorld stepPhysicsWorldSystem;

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

它是處理實際內容的部分。

buildPhysicsWorldSystem從中獲取PhysicsWorld。這包括目前所有碰撞者的座標。

         類似的stepPhysicsWorldSystem從中來獲得TriggerEvents。在此存儲由引發碰撞事件啓用的對象發出的事件。

您所要做的就是讓對象與EventTrigger鍵接觸並處理事件。

   protected override void OnUpdate()
    {
        var physicsWorld = buildPhysicsWorldSystem.PhysicsWorld;
        var triggerEvents = stepPhysicsWorldSystem.Simulation.TriggerEvents;
        var items = GetComponentDataFromEntity<ItemTag>(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<BuildPhysicsWorld>();
        stepPhysicsWorldSystem = World.GetOrCreateSystem<StepPhysicsWorld>();
    }

    protected override void OnUpdate()
    {
        var physicsWorld = buildPhysicsWorldSystem.PhysicsWorld;
        var triggerEvents = stepPhysicsWorldSystem.Simulation.TriggerEvents;
        var items = GetComponentDataFromEntity<ItemTag>(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<ItemTag> items)
    {
        if( items.Exists(entity))
        {
            PostUpdateCommands.DestroyEntity(entity);
            UnityEngine.Debug.Log("you get item!");
        }
    }
}

應該注意的是,Unity Physics沒有狀態,因此似乎不能採取諸如“碰撞開始”,“ 碰撞中”和“ 碰撞結束”之類的事件。

        如果只想在特定對象之間執行碰撞事件,則可以確定在ComponentDataFromEntity中是否具有特定組件,如上面的代碼中所示,或者Custom Flag通過設置它BodyA.CustomData

F:ID:tsubaki_t1:20190425221913j:平紋

如果您不想簡單地觸摸,最好調整碰撞濾波器。這裏的界面是我希望你再做一點的地方。

F:ID:tsubaki_t1:20190425222055j:平紋

我想使用JobSystem

我嘗試使用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<BuildPhysicsWorld>();
        stepPhysicsWorldSystem = World.GetOrCreateSystem<StepPhysicsWorld>();
        bufferSystem = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem>();
    }

    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<ItemTag>(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<ItemTag> 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!");
        }
    }
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章