Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

isKinematic state change fire OnTrigger events

Discussion in 'Physics' started by Ryukai3, May 25, 2021.

  1. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Hi,
    like the title say, at the moment when I play with the variable isKinematic (setting it to false or true) the object attacched fire an OnTrigger event (Exit or Enter).

    Is there a way to not fire these OnTrigger events (for my environment useless and dangerous) when I change isKinematic state?
    If its not possible to disable this behaviour, how can I ignore these events?

    Thanks! :)
     
  2. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    777
    Hi,

    How about putting something like this code in the beginning of OnTriggerEnter(), and Exit() methods?
    Code (CSharp):
    1. If (I play with the variable isKinematic)
    2.     return;
     
  3. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Yes, but how can I know if the OnTrigger events is a legit one (triggered by a real trigger Exit/Enter in the game) or a non-legit one (triggered by isKinematic state changed true/false)?
     
  4. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    777
    Is the isKinematic state changed outside of your control?
     
  5. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    No , I change it in another method when certain conditions are met.
     
  6. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    777
    Have you tried to set a variable to true in the frame the isKinematic state is changed? And check that variable in the OnTrigger methods to know if it was just a "false alarm", or not.
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    I am not a 3D physics dev but know that changing the body-type like this isn't just a simple flag. It completely changes the behaviour of the underlying body. For existing contacts it might invalidate them if, for instance, the body was Dynamic (yes, non-kinematic is called Dynamic) and it was in contact with a Static body. If you change it to Kinematic then by default, those don't produce contacts.

    Expecting zero side-effects from a property change isn't always appropriate.
     
  8. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Yes, thanks for the reply !
    Thats why Im searching for a method for ignore some of the events I dont need in my script !
     
  9. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Yes, sort of:
    • In the method where i change the isKinematic state I save the current fixedupdate time frame (f0) and the next fixedupdate f1 = f0 + fixedDeltatime. f1 is useful because I think that the OnTrigger evets triggered by the isKinematic change is always it the next fixedupdate.
    • Then, in the OnTrigger event (Exit / Enter) method I check if the current fixedUpdate is f1. If so, return (ignore this event).
    This logic is 90-95% working, but sometime (5%) the return above ignore not only the "correct" trigger events due to isKinematic change, but also other "normal" onTrigger events.
     
  10. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    777
    Perhaps it's better to just count the frames instead of using fixedDeltatime?
     
  11. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Count the frames? Can you make an example?
     
  12. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    777
    Code (CSharp):
    1. int fc;
    2. void FixedUpdate ()
    3. {
    4.   fc++;
    5. }
    6.  
    7. void OnTriggerEnter ()
    8. {
    9.   if (fc == skipFrameNo)  // or (fc <= skipFrameNo)
    10.       return;
    11.  
    12.   // Do trigger event stuff
    13. }
    14.  
    Assuming all colliding objects is active and enabled at the same time in the game. (Haven't tested this though)

    Or just check a bool at the rigidbody object on collision. (Haven't tested this either...)
    Code (CSharp):
    1. void OnTriggerEnter (Collider other) {
    2.   if (Im_playing_with_isKinematic  || other.GetComponent<AScript>().Im_playing_with_isKinematic)
    3.    return;
    4.  
    5. // Do trigger event stuff
    6. }
    If both objects has a Rigidbody with changing isKinematic states.
     
    Last edited: May 28, 2021
  13. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Yes could be, but when do I reset the "Im_playing_with_isKinematic" to false?

    Assuming for example that I have a gameObject (go1) surrounded (touching) by other 4 gameObject (go2, go3, go4, go5). All the gameObject are isKinematic = true.
    When I change isKinematic= false on go1, these OnTriggerEvents will fire (tested):

    OnTriggerExit go1 vs go2
    OnTriggerExit go1 vs go3
    OnTriggerExit go1 vs go4
    OnTriggerExit go1 vs go5
    and of course the other couple:
    OnTriggerExit go2 vs go1
    OnTriggerExit go3 vs go1
    OnTriggerExit go4 vs go1
    OnTriggerExit go5 vs go1

    OnTriggerEnter go1 vs go2
    OnTriggerEnter go1 vs go3
    OnTriggerEnter go1 vs go4
    OnTriggerEnter go1 vs go5
    and of course the other couple:
    OnTriggerEnter go2 vs go1
    OnTriggerEnter go3 vs go1
    OnTriggerEnter go4 vs go1
    OnTriggerEnter go5 vs go1

    A total of 16 OnTriggerEvents (exit + enter) will fire only because I have changed isKinematic stat on false. For note, a onCollisionEnter will trigger also due to the isKinematic change, but im not interested in discarding that.

    If I set a bool (Im_playing_with_isKinematic) to true when I change the isKinematic, and use this code you suggested

    Code (CSharp):
    1. void OnTriggerExit (Collider other) {
    2.   if (Im_playing_with_isKinematic  || other.GetComponent<AScript>().Im_playing_with_isKinematic)
    3.    return;
    4. // Do trigger event stuff
    5. }
    All the 16 events will be correctly not considered.

    Lets now assume that go1 have returned to isKinematic=true subsequently during the game.
    "Im_playing_with_isKinematic" is still set to true from previous events.
    Now, go1 and go2 pull away for the game mechanics. So they fire a OnTriggerEvent (exit) event that I need to consider, but, due to the bool "Im_playing_with_isKinematic" still on true, this event will be discarded.

    So, in other words, I need to set "Im_playing_with_isKinematic" to false sometimes (when?)
     
    Last edited: Aug 23, 2021
  14. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    777
    How about waiting to the next frame?

    Code (CSharp):
    1. void PlayWithIsKinematic(bool newValue)
    2. {
    3.    // Safety check
    4.    if (newValue == rigidBody.isKinematic)
    5.       return;
    6.  
    7.    // Set the new value
    8.    Im_playing_with_isKinematic = true;
    9.    rigidBody.isKinematic = newValue;
    10.    StartCoroutine(StopPlaying());
    11. }
    12.  
    13. IEnumerator StopPlaying()
    14. {
    15.    yield return null;
    16.    Im_playing_with_isKinematic = false;
    17. }
     
  15. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Thank you,
    tested it (whit "yield return WaitForFixedUpdate" and not "yield return null" because im using it in physic calculation).

    Its a good option but sometimes a real OnTrigger events overlap a fake OnTrigger events (fake=generated by a isKinematic change).

    Example:
    I change the Kinematic state at 235,02 fixed time. So I set "Im_playing_with_isKinematic" to true.
    I expect that at 235,04 fixed time (235,02+0,02 fixed delta time) the nasty On Trigger Events will occur.
    So, at 235,04 fixed time the "Im_playing_with_isKinematic" is still set to true.

    At 235,04, the two colliding object exit each other, causing a real OnTriggerEvent (exit):
    "Im_playing_with_isKinematic" is still true and the real trigger event wont fire, together with the fake events.
     
  16. arfish

    arfish

    Joined:
    Jan 28, 2017
    Posts:
    777
    Perhaps using two flags to filter the trigger events even further? One for Im_setting_isKinematic_to_true, and one for Im_setting_isKinematic_to_false.

    Code (CSharp):
    1.     void OnTriggerEnter (Collider other) {
    2.       if (Im_setting_isKinematic_to_false  || other.GetComponent<AScript>().Im_setting_isKinematic_to_false)
    3.        return;
    4.  
    5.     // Do trigger event stuff
    6.     }
    , and

    Code (CSharp):
    1.     void OnTriggerExit (Collider other) {
    2.       if (Im_setting_isKinematic_to_true  || other.GetComponent<AScript>().Im_setting_isKinematic_to_true)
    3.        return;
    4.  
    5.     // Do trigger event stuff
    6.     }
    (Assuming the extra trigger events are only sent when entering, or leaving non kinematic mode. Not sure about that though.)

    Edit. Ah, saw in your first post the triggers always fires when changing the isKinematic state. So this probably doesn't solves it completely either. Think the only solution is for someone to fix the RigidBody to not reinitialize the trigger stuff when just switching state between isKinematic to not Kinematic mode then.

    Or, handle it like any other not so uncommon double firing of trigger events?
     
    Last edited: Aug 29, 2021
    Ryukai3 likes this.
  17. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Yes,
    not firing the trigger exit/enter when isKinematic is changed would be the best choice.

    Im now testing a solution based also on position (check if the position changed).