Search Unity

Resolved RaiseTriggerEvents works but CollideRaiseCollisionEvents don't?

Discussion in 'Physics for ECS' started by Antypodish, Feb 28, 2021.

  1. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    So I try to collect events.
    I can do so, using RaiseTriggerEvents.
    But not, if using CollideRaiseCollisionEvents.

    upload_2021-2-28_17-28-25.png

    In my Entities.ForEach job I got
    Code (CSharp):
    1. DynamicBuffer <Unity.Physics.Stateful.StatefulTriggerEvent> a_triggerEvents
    and further

    Code (CSharp):
    1. for ( int i = 0; i < a_triggerEvents.Length; i++)
    2.                 {
    3.                  
    4.                     Unity.Physics.Stateful.StatefulTriggerEvent triggerEvent = a_triggerEvents [i];
    5.                     Entity otherEntity                                       = triggerEvent.GetOtherEntity ( entity ) ;
    6.                  
    7.                     if ( triggerEvent.State == Unity.Physics.Stateful.EventOverlapState.Enter )
    8.                     {                      
    9.                         Debug.LogWarning ( string.Format ( "Hovercraft {0} hit {1}.", entity, otherEntity ) ) ;
    10.                    }
    11.                 }
    12.  
    13.                 if ( a_triggerEvents.Length > 0 ) Debug.LogError ( a_triggerEvents.Length ) ;
    I know system executes fine.
    But debug log returns > 0 only, if I have set object as RaiseTriggerEvents.

    I am also using
    DynamicBufferTriggerEventAuthoring
    script, from one of samples:

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Jobs;
    3. using Unity.Physics;
    4. using Unity.Physics.Systems;
    5. using UnityEngine;
    6. using Unity.Collections;
    7. using Unity.Burst;
    8. using System;
    9. using Unity.Assertions;
    10. using Unity.Mathematics;
    11.  
    12. /// <summary>
    13. /// Copied from Unity samples.
    14. /// 2. Setup > 2d. Events > 2d1. Triggers > Scripts > DynamicBufferTriggerEventAuthoring
    15. /// 2021 Feb 05.
    16. /// </summary>
    17. namespace Unity.Physics.Stateful
    18. {
    19.     // Describes the overlap state.
    20.     // OverlapState in StatefulTriggerEvent is set to:
    21.     //    1) EventOverlapState.Enter, when 2 bodies are overlapping in the current frame,
    22.     //    but they did not overlap in the previous frame
    23.     //    2) EventOverlapState.Stay, when 2 bodies are overlapping in the current frame,
    24.     //    and they did overlap in the previous frame
    25.     //    3) EventOverlapState.Exit, when 2 bodies are NOT overlapping in the current frame,
    26.     //    but they did overlap in the previous frame
    27.     public enum EventOverlapState : byte
    28.     {
    29.         Enter,
    30.         Stay,
    31.         Exit
    32.     }
    33.  
    34.     // Trigger Event that is stored inside a DynamicBuffer
    35.     public struct StatefulTriggerEvent : IBufferElementData, IComparable<StatefulTriggerEvent>
    36.     {
    37.         internal EntityPair Entities;
    38.         internal BodyIndexPair BodyIndices;
    39.         internal ColliderKeyPair ColliderKeys;
    40.  
    41.         public EventOverlapState State;
    42.         public Entity EntityA => Entities.EntityA;
    43.         public Entity EntityB => Entities.EntityB;
    44.         public int BodyIndexA => BodyIndices.BodyIndexA;
    45.         public int BodyIndexB => BodyIndices.BodyIndexB;
    46.         public ColliderKey ColliderKeyA => ColliderKeys.ColliderKeyA;
    47.         public ColliderKey ColliderKeyB => ColliderKeys.ColliderKeyB;
    48.  
    49.         public StatefulTriggerEvent(Entity entityA, Entity entityB, int bodyIndexA, int bodyIndexB,
    50.                                     ColliderKey colliderKeyA, ColliderKey colliderKeyB)
    51.         {
    52.             Entities = new EntityPair
    53.             {
    54.                 EntityA = entityA,
    55.                 EntityB = entityB
    56.             };
    57.             BodyIndices = new BodyIndexPair
    58.             {
    59.                 BodyIndexA = bodyIndexA,
    60.                 BodyIndexB = bodyIndexB
    61.             };
    62.             ColliderKeys = new ColliderKeyPair
    63.             {
    64.                 ColliderKeyA = colliderKeyA,
    65.                 ColliderKeyB = colliderKeyB
    66.             };
    67.             State = default;
    68.         }
    69.  
    70.         // Returns other entity in EntityPair, if provided with one
    71.         public Entity GetOtherEntity(Entity entity)
    72.         {
    73.             Assert.IsTrue((entity == EntityA) || (entity == EntityB));
    74.             int2 indexAndVersion = math.select(new int2(EntityB.Index, EntityB.Version),
    75.                 new int2(EntityA.Index, EntityA.Version), entity == EntityB);
    76.             return new Entity
    77.             {
    78.                 Index = indexAndVersion[0],
    79.                 Version = indexAndVersion[1]
    80.             };
    81.         }
    82.  
    83.         public int CompareTo(StatefulTriggerEvent other)
    84.         {
    85.             var cmpResult = EntityA.CompareTo(other.EntityA);
    86.             if (cmpResult != 0)
    87.             {
    88.                 return cmpResult;
    89.             }
    90.  
    91.             cmpResult = EntityB.CompareTo(other.EntityB);
    92.             if (cmpResult != 0)
    93.             {
    94.                 return cmpResult;
    95.             }
    96.  
    97.             if (ColliderKeyA.Value != other.ColliderKeyA.Value)
    98.             {
    99.                 return ColliderKeyA.Value < other.ColliderKeyA.Value ? -1 : 1;
    100.             }
    101.  
    102.             if (ColliderKeyB.Value != other.ColliderKeyB.Value)
    103.             {
    104.                 return ColliderKeyB.Value < other.ColliderKeyB.Value ? -1 : 1;
    105.             }
    106.  
    107.             return 0;
    108.         }
    109.     }
    110.  
    111.     // If this component is added to an entity, trigger events won't be added to dynamic buffer
    112.     // of that entity by TriggerEventConversionSystem. This component is by default added to
    113.     // CharacterController entity, so that CharacterControllerSystem can add trigger events to
    114.     // CharacterController on its own, without TriggerEventConversionSystem interference.
    115.     public struct ExcludeFromTriggerEventConversion : IComponentData {}
    116.  
    117.     // This system converts stream of TriggerEvents to StatefulTriggerEvents that are stored in a Dynamic Buffer.
    118.     // In order for TriggerEvents to be transformed to StatefulTriggerEvents and stored in a Dynamic Buffer, it is required to:
    119.     //    1) Tick IsTrigger on PhysicsShapeAuthoring on the entity that should raise trigger events
    120.     //    2) Add a DynamicBufferTriggerEventAuthoring component to that entity
    121.     //    3) If this is desired on a Character Controller, tick RaiseTriggerEvents on CharacterControllerAuthoring (skip 1) and 2)),
    122.     //    note that Character Controller will not become a trigger, it will raise events when overlapping with one
    123.     [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    124.     [UpdateAfter(typeof(StepPhysicsWorld))]
    125.     [UpdateBefore(typeof(EndFramePhysicsSystem))]
    126.     public class TriggerEventConversionSystem : SystemBase
    127.     {
    128.         public JobHandle OutDependency => Dependency;
    129.  
    130.         private StepPhysicsWorld m_StepPhysicsWorld = default;
    131.         private BuildPhysicsWorld m_BuildPhysicsWorld = default;
    132.         private EndFramePhysicsSystem m_EndFramePhysicsSystem = default;
    133.         private EntityQuery m_Query = default;
    134.  
    135.         private NativeList<StatefulTriggerEvent> m_PreviousFrameTriggerEvents;
    136.         private NativeList<StatefulTriggerEvent> m_CurrentFrameTriggerEvents;
    137.  
    138.         protected override void OnCreate()
    139.         {
    140.             m_StepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
    141.             m_BuildPhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>();
    142.             m_EndFramePhysicsSystem = World.GetOrCreateSystem<EndFramePhysicsSystem>();
    143.             m_Query = GetEntityQuery(new EntityQueryDesc
    144.             {
    145.                 All = new ComponentType[]
    146.                 {
    147.                     typeof(StatefulTriggerEvent)
    148.                 },
    149.                 None = new ComponentType[]
    150.                 {
    151.                     typeof(ExcludeFromTriggerEventConversion)
    152.                 }
    153.             });
    154.  
    155.             m_PreviousFrameTriggerEvents = new NativeList<StatefulTriggerEvent>(Allocator.Persistent);
    156.             m_CurrentFrameTriggerEvents = new NativeList<StatefulTriggerEvent>(Allocator.Persistent);
    157.         }
    158.  
    159.         protected override void OnDestroy()
    160.         {
    161.             m_PreviousFrameTriggerEvents.Dispose();
    162.             m_CurrentFrameTriggerEvents.Dispose();
    163.         }
    164.  
    165.         protected void SwapTriggerEventStates()
    166.         {
    167.             var tmp = m_PreviousFrameTriggerEvents;
    168.             m_PreviousFrameTriggerEvents = m_CurrentFrameTriggerEvents;
    169.             m_CurrentFrameTriggerEvents = tmp;
    170.             m_CurrentFrameTriggerEvents.Clear();
    171.         }
    172.  
    173.         protected static void AddTriggerEventsToDynamicBuffers(NativeList<StatefulTriggerEvent> triggerEventList,
    174.             ref BufferFromEntity<StatefulTriggerEvent> bufferFromEntity, NativeHashMap<Entity, byte> entitiesWithTriggerBuffers)
    175.         {
    176.             for (int i = 0; i < triggerEventList.Length; i++)
    177.             {
    178.                 var triggerEvent = triggerEventList[i];
    179.                 if (entitiesWithTriggerBuffers.ContainsKey(triggerEvent.EntityA))
    180.                 {
    181.                     bufferFromEntity[triggerEvent.EntityA].Add(triggerEvent);
    182.                 }
    183.                 if (entitiesWithTriggerBuffers.ContainsKey(triggerEvent.EntityB))
    184.                 {
    185.                     bufferFromEntity[triggerEvent.EntityB].Add(triggerEvent);
    186.                 }
    187.             }
    188.         }
    189.  
    190.         public static void UpdateTriggerEventState(NativeList<StatefulTriggerEvent> previousFrameTriggerEvents, NativeList<StatefulTriggerEvent> currentFrameTriggerEvents,
    191.             NativeList<StatefulTriggerEvent> resultList)
    192.         {
    193.             int i = 0;
    194.             int j = 0;
    195.  
    196.             while (i < currentFrameTriggerEvents.Length && j < previousFrameTriggerEvents.Length)
    197.             {
    198.                 var currentFrameTriggerEvent = currentFrameTriggerEvents[i];
    199.                 var previousFrameTriggerEvent = previousFrameTriggerEvents[j];
    200.  
    201.                 int cmpResult = currentFrameTriggerEvent.CompareTo(previousFrameTriggerEvent);
    202.  
    203.                 // Appears in previous, and current frame, mark it as Stay
    204.                 if (cmpResult == 0)
    205.                 {
    206.                     currentFrameTriggerEvent.State = EventOverlapState.Stay;
    207.                     resultList.Add(currentFrameTriggerEvent);
    208.                     i++;
    209.                     j++;
    210.                 }
    211.                 else if (cmpResult < 0)
    212.                 {
    213.                     // Appears in current, but not in previous, mark it as Enter
    214.                     currentFrameTriggerEvent.State = EventOverlapState.Enter;
    215.                     resultList.Add(currentFrameTriggerEvent);
    216.                     i++;
    217.                 }
    218.                 else
    219.                 {
    220.                     // Appears in previous, but not in current, mark it as Exit
    221.                     previousFrameTriggerEvent.State = EventOverlapState.Exit;
    222.                     resultList.Add(previousFrameTriggerEvent);
    223.                     j++;
    224.                 }
    225.             }
    226.  
    227.             if (i == currentFrameTriggerEvents.Length)
    228.             {
    229.                 while (j < previousFrameTriggerEvents.Length)
    230.                 {
    231.                     var triggerEvent = previousFrameTriggerEvents[j++];
    232.                     triggerEvent.State = EventOverlapState.Exit;
    233.                     resultList.Add(triggerEvent);
    234.                 }
    235.             }
    236.             else if (j == previousFrameTriggerEvents.Length)
    237.             {
    238.                 while (i < currentFrameTriggerEvents.Length)
    239.                 {
    240.                     var triggerEvent = currentFrameTriggerEvents[i++];
    241.                     triggerEvent.State = EventOverlapState.Enter;
    242.                     resultList.Add(triggerEvent);
    243.                 }
    244.             }
    245.         }
    246.  
    247.         protected override void OnUpdate()
    248.         {
    249.             if (m_Query.CalculateEntityCount() == 0)
    250.             {
    251.                 return;
    252.             }
    253.  
    254.             Dependency = JobHandle.CombineDependencies(m_StepPhysicsWorld.FinalSimulationJobHandle, Dependency);
    255.  
    256.             Entities
    257.                 .WithName("ClearTriggerEventDynamicBuffersJobParallel")
    258.                 .WithBurst()
    259.                 .WithNone<ExcludeFromTriggerEventConversion>()
    260.                 .ForEach((ref DynamicBuffer<StatefulTriggerEvent> buffer) =>
    261.                 {
    262.                     buffer.Clear();
    263.                 }).ScheduleParallel();
    264.  
    265.             SwapTriggerEventStates();
    266.  
    267.             var currentFrameTriggerEvents = m_CurrentFrameTriggerEvents;
    268.             var previousFrameTriggerEvents = m_PreviousFrameTriggerEvents;
    269.  
    270.             var triggerEventBufferFromEntity = GetBufferFromEntity<StatefulTriggerEvent>();
    271.             var physicsWorld = m_BuildPhysicsWorld.PhysicsWorld;
    272.  
    273.             var collectTriggerEventsJob = new CollectTriggerEventsJob
    274.             {
    275.                 TriggerEvents = currentFrameTriggerEvents
    276.             };
    277.  
    278.             var collectJobHandle = collectTriggerEventsJob.Schedule(m_StepPhysicsWorld.Simulation, ref physicsWorld, Dependency);
    279.  
    280.             // Using HashMap since HashSet doesn't exist
    281.             // Setting value type to byte to minimize memory waste
    282.             NativeHashMap<Entity, byte> entitiesWithBuffersMap = new NativeHashMap<Entity, byte>(0, Allocator.TempJob);
    283.  
    284.             var collectTriggerBuffersHandle = Entities
    285.                 .WithName("CollectTriggerBufferJob")
    286.                 .WithBurst()
    287.                 .WithNone<ExcludeFromTriggerEventConversion>()
    288.                 .ForEach((Entity e, ref DynamicBuffer<StatefulTriggerEvent> buffer) =>
    289.                 {
    290.                     entitiesWithBuffersMap.Add(e, 0);
    291.                 }).Schedule(Dependency);
    292.  
    293.             Dependency = JobHandle.CombineDependencies(collectJobHandle, collectTriggerBuffersHandle);
    294.  
    295.             Job
    296.                 .WithName("ConvertTriggerEventStreamToDynamicBufferJob")
    297.                 .WithBurst()
    298.                 .WithCode(() =>
    299.                 {
    300.                     currentFrameTriggerEvents.Sort();
    301.  
    302.                     var triggerEventsWithStates = new NativeList<StatefulTriggerEvent>(currentFrameTriggerEvents.Length, Allocator.Temp);
    303.  
    304.                     UpdateTriggerEventState(previousFrameTriggerEvents, currentFrameTriggerEvents, triggerEventsWithStates);
    305.                     AddTriggerEventsToDynamicBuffers(triggerEventsWithStates, ref triggerEventBufferFromEntity, entitiesWithBuffersMap);
    306.                 }).Schedule();
    307.  
    308.             m_EndFramePhysicsSystem.AddInputDependency(Dependency);
    309.             entitiesWithBuffersMap.Dispose(Dependency);
    310.         }
    311.  
    312.         [BurstCompile]
    313.         public struct CollectTriggerEventsJob : ITriggerEventsJob
    314.         {
    315.             public NativeList<StatefulTriggerEvent> TriggerEvents;
    316.  
    317.             public void Execute(TriggerEvent triggerEvent)
    318.             {
    319.                 TriggerEvents.Add(new StatefulTriggerEvent(
    320.                     triggerEvent.EntityA, triggerEvent.EntityB, triggerEvent.BodyIndexA, triggerEvent.BodyIndexB,
    321.                     triggerEvent.ColliderKeyA, triggerEvent.ColliderKeyB));
    322.             }
    323.         }
    324.     }
    325.  
    326.     public class DynamicBufferTriggerEventAuthoring : MonoBehaviour, IConvertGameObjectToEntity
    327.     {
    328.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    329.         {
    330.             dstManager.AddBuffer<StatefulTriggerEvent>(entity);
    331.         }
    332.     }
    333. }
    334.  

    I have seen two post regarding similar issue.
    https://forum.unity.com/search/3874...nEvents&t=post&o=date&c[node]=147+583+422+425
    Any thoughts?
     
  2. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    A Trigger Event (I'm inside a particular volume) is different from a Collision Event (I'm colliding with another shape).
    You need to be looking at the
    StatefulCollisionEvent
    if you want to process Collision Events.
     
    Antypodish likes this.
  3. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Thx bunch.

    I looked again into samples
    https://github.com/Unity-Technologi...mos/2. Setup/2d. Events/2d2. Collision Events

    Initially I modified my jobs, to accommodate collisions, similar as per trigger, which earlier worked as I stated in OP post. But then I had no collision event rise.

    Not until I removed StatefulCollisionEvent buffer creation via script and instead, I added authoring component to the Game Object.

    A bit weirdly, as this worked when I added StatefulTriggerEvent buffer to entity via script. But similarly don't seems work for StatefulCollisionEvent.
     
  4. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Hi @Antypodish , our samples often use authoring components to denote entities for which some things should be done or to skip updating a system if no entities contain the component.

    Physics engine will create collision and trigger event streams you can read from ITriggerEventsJob/ICollisionEventsJob for every body whose material indicates raising a trigger or collision event. Authoring components control the stuff that is built on top of this, like stateful events (note that StatefulTriggerEvent and StatefulCollisionEvent are in the samples, not in the core engine which needs to be "stateless").

    Please let us know if you have any further questions.
     
    Antypodish likes this.