Search Unity

Since when did Changing isKinematic fire OnTriggerExit?

Discussion in 'Physics' started by Antony-Blackett, Dec 8, 2019.

  1. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    I think this is about the 4th time in the history of me using Unity that this has changed,

    Unity 3.x did not trigger OnTriggerEnter or OnTriggerExit when changing isKinematic.
    Unity 4.x then changed it to triggering OnTriggerEnter or OnTriggerExit when changing isKinematic.
    Unity 2017 then changed it to not triggering OnTriggerEnter or OnTriggerExit when changing isKinematic.

    and now Unity 2019.3 has made it so that changing isKinematic will fire OnTriggerEnter and OnTriggerExit.

    Seriously, pick one and stick to it, Unity!

    This change has serious implications on how we implement gameplay code. It's a real pain to not be able to reply on when trigger events are fired, in fact I'd say it makes trigger events almost useless if you plan on supporting a game for a long time.

    So tell me, is this a bug that is going to change back, yet again? Or is this the intended behaviour? If it is intended, will it change again in future? i.e. in Unity Physics when it is out of preview?

    Note: I'm using standard physics currently.
     
  2. darman77

    darman77

    Joined:
    Jun 14, 2015
    Posts:
    17
    Report bug. IMHO changing isKinematic shouldn't trigger OnTriggerEnter or OnTriggerExit.
     
  3. TDUMicrobe

    TDUMicrobe

    Joined:
    Jun 21, 2017
    Posts:
    2
    IgnoreCollision triggers fire OnTriggerEnter or Exit to !
    So, It’s very hard to workaround and mute all the messages we don’t need !!
    Create an option in project settings please !!!
     
  4. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    That's what i would have thought but when they updated physx the blog post said it was intentional.
     
  5. JohnnyFactor

    JohnnyFactor

    Joined:
    May 18, 2018
    Posts:
    343
    I was forced to upgrade my project to 2019 and among the hundreds of things that broke, this was one of them. Now I face updating many, many scripts for no reason other than someones passing fancy that may or may not change again.

    I really wish UT would rein in devs ability to change whatever they feel like whenever they feel like it. Unity 3D is one of the most complex and fragile software products around. You can't just go mucking around in it without consequences.
     
  6. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Yeah, in one of my projects triggers are all safe guarded with Time.frameCount == lastFrame checks to make sure it's not a false positive trigger. super ugly. super flaky
     
  7. JohnnyFactor

    JohnnyFactor

    Joined:
    May 18, 2018
    Posts:
    343
    I wrapped the code in an IF statement. Works well enough since the project isn't resource heavy.

    Code (CSharp):
    1. void OnTriggerExit(Collider collider)
    2. {
    3.     if (GetComponent<Rigidbody>().isKinematic == false)
    4.     {
    5.         GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
    6.         GetComponent<Rigidbody>().angularVelocity = new Vector3(0, 0, 0);
    7.         transform.position = new Vector3(0, 0.09f, -0.183f);
    8.     }
    9. }
     
  8. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Yeah, that didn’t work for me as sometimes I’d want triggers to fire when moving kinematic objects
     
  9. ChrisVMC

    ChrisVMC

    Joined:
    Jun 22, 2020
    Posts:
    16
    What pisses me off is that there is no mention of this huge breaking change in the upgrade notes for going to 2019.3 or the release notes! It's only a one liner on the end of a blog post I found via this thread by googling the problem.
     
  10. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Yep, it was only luck i read the blog post before updating.
     
  11. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Hi,
    is this problem solved or reported in issue tracker? Im experiencing it too !
     
  12. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    As far as I’m aware, unity did it by design so it won’t be fixed unless they change their mind
     
  13. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Thank you! During this time did you came up with some sort of workaroud to not fire (or ignore) the OnTriggerExit/Enter events when isTrigger is set false or true?
     
  14. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    It happens on the same frame so i just had an int that recorded Time.frameCount to try and detect it. If you have specific times when rigidbodys change in code then you could also record the frame when setting isKinematic in anticipation of a trigger event firing.

    that’s how I converted old projects and it worked ok.

    with new projects i have a separate trigger object and attach that to the rigidbody. That way the trigger object never changes iskinematic
     
    Last edited: Nov 17, 2020
    toyhunter and Ryukai3 like this.
  15. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Thank you for your clever hints!!

    I Will try for a solution similar to the first one (due to my game setup I think its difficult to use the second one).

    In my script I set isKinematic in a coroutine, so I think that I cant use time.framecount because the frame when I set isKinematic Is different from the frame when the ontrigger events fire.
    What do you think?
     
  16. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    I think I figured it out.

    Due to the fact that the in my script isKinematic is set during a coroutine with "yield return new WaitForFixedUpdate()", instead of recording Time.frameCount I record Time.fixedTime + Time.fixedDeltaTime:
    so im expecting that the OnTriggerEvent will fire on the next fixedupdate after the switch of the isKinematic flag.

    Im testing this but for now its working.
     
  17. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Yeah. I remember it being a trail and error process to get what is essentially a large hack to work right. Unfortunately there was no other way besides a complete rewrite of all the trigger systems in my game.
     
  18. atrivedi7

    atrivedi7

    Joined:
    Jul 25, 2013
    Posts:
    92
    Add 1 to the casualty list...

    This is incredibly frustrating!
     
  19. patrykszylindev

    patrykszylindev

    Joined:
    Oct 28, 2019
    Posts:
    23
    upload_2020-11-19_16-6-11.png

    Have you played with these settings?
     
  20. cihad_unity

    cihad_unity

    Joined:
    Dec 27, 2019
    Posts:
    35
    @patrykszylindev it works. I don't know how much it affects performance.
    I developer hypercasual games so they are not resource heavy, but I believe it impact other games.
     
  21. Overcast

    Overcast

    Joined:
    May 16, 2013
    Posts:
    29
    I just spent two hours getting to this point. Not fun Unity.fundamentally reversing core systems is a a breaking change, please call out breaking changes in your code warnings at the very least.

    Because of how core I assumed the trigger system was, it took a long time to look here for the issue, which manifested well downstream and inside a third party asset.
     
  22. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    My guess is that they didn’t realise they changed it so they didn’t list it as a change. Everywhere I’ve told then about the change I’m totally ignored. I just hope it doesn’t reverse again for a third time.
     
  23. atrivedi7

    atrivedi7

    Joined:
    Jul 25, 2013
    Posts:
    92
    They did make a statement about it but in a blog post: https://blogs.unity3d.com/2019/10/22/physics-updates-in-unity-2019-3/

    When a kinematic Rigidbody is turned into a non-kinematic one, the physics engine will now re-insert it into the broad-phase structures for the purposes of collision detection. This will cause an extra OnTriggerEnter event.​

    I honestly didn't quite understand it at first. I think they could have done a better job explaining the implication - though looking back on it now is super obvious.

    Still, not a change I agree with
     
  24. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    They mentioned it in the blog post but not the official change notes
     
  25. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    This change is absolutely stupid. Change it back, Unity.
     
    Ryukai3 likes this.
  26. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
  27. franziskawestermeier

    franziskawestermeier

    Joined:
    Jan 29, 2022
    Posts:
    1
    I ran into the same problem.

    What solved it for me was to disable the collider component, then set isKinematic to true/false and enable the collider again (also does not matter which collider you enable/disable)

    Code (CSharp):
    1. GetComponent<Collider>().enabled = false;
    2. transform.GetComponent<Rigidbody>().isKinematic = true;
    3. GetComponent<Collider>().enabled = true;
     
  28. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    This seem to prevent only one trigger exit but not the ontrigger enter event.
     
  29. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    A solution I wound up using was to defer the handling of OnTriggerX. Instead, it'd keep track of which bodies enter and exit. Then, in a "LateFixedUpdate" (which can be used via a Coroutine with a WaitForFixedUpdate yield) - which happens AFTER collision and trigger message handling, I look through the lists of enter/exit calls and remove ones that cancel each other out. Then the list is cleared and reused for the next round of OnTriggerEnter/Exit calls.

    The false trigger handling that occurs when switching to/from isKinematic will happen between Physics updating and WaitForFixedUpdate and deferring the handling until WatiForFixedUpdate lets you effectively filter out the erronious trigger messages.
     
    Antony-Blackett likes this.
  30. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    Frankly, trigger enter and exit events in Unity are so full of little quirks I end up implementing custom solutions and events for the more critical/complex cases, by having a component which checks every fixed update which colliders are currently overlapping, compare that with the last of overlaps from the previous frame, and dispatch enter/exit events accordingly.
     
  31. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    Hmm, as far as I know, the solution I came up with doesn't have any issues detecting collider-trigger intersections in the way one would expect.
    Perhaps the only thing I could think of is the lack of a message for exiting or entering the trigger when it is created or destroyed, activated/deactivated, enabled/disabled...
    I suppose it only is able to detect intersections that are present immediately prior to Physics.Update, so if you move an object in and out within the same fixed update cycle, it'd not be detected.
    Writing your own intersection code seems like it'd be overkill and likely a lot less optimized than the stuff nVidia came up with.
     
  32. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    One of my problem is exactly the lack of messages when objects are destroyed/disabled/enabled.

    And we do use the physics APIs to detect the intersections. I'm just querying manually instead of hoping it will fire enter/exit events when I need it.
     
  33. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Hi Antony!
    Could you clarify this quote?
    Thank you!
    (Still struggling with on Trigger events)
     
  34. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    You can use a seperate collider under the rigidbody in the hierarchy and use that as the trigger... I can't remember now but i think you need to add a rigidbody to it as well so that it doesn't get effected by kinematic changes of the parent rigidbody.

    Alternatively you can set the trigger object to the position of the rigidbody and keep it as a sibling in the hierarchy. it depends on how your project is setup.
     
    toyhunter and Ryukai3 like this.
  35. Ryukai3

    Ryukai3

    Joined:
    Mar 30, 2017
    Posts:
    30
    Thank you!
    I solved using this solution, it worked!
    Both parent and child must have a rigidbody.
     
  36. toyhunter

    toyhunter

    Joined:
    Mar 5, 2018
    Posts:
    76
    Last edited: Apr 28, 2022
    Antony-Blackett likes this.
  37. chantey

    chantey

    Joined:
    Mar 5, 2017
    Posts:
    49
    For those looking for an in-code solution, the Trigger events occur either on the same fixedTime frame as when kinematic was toggled, or on the following one. I'm using this logic, with a 1.5 scalar to safely handle floating point equality:

    Code (CSharp):
    1.  
    2. public class KinematicTriggerEventListener : MonoBehaviour
    3. {
    4.     float ignoreFixedFrame = -1;
    5.  
    6.     void SetKinematic(bool value)
    7.     {
    8.         ignoreFixedFrame = Time.fixedTime + Time.fixedDeltaTime * 1.5f;
    9.         GetComponent<Rigidbody>().isKinematic = value;
    10.     }
    11.  
    12.     void OnTriggerEnter(Collider other)
    13.     {
    14.         if (Time.fixedTime < ignoreFixedFrame)
    15.             return;
    16.         //ok
    17.     }
    18.  
    19.     void OnTriggerExit(Collider other)
    20.     {
    21.         if (Time.fixedTime < ignoreFixedFrame)
    22.             return;
    23.         //ok
    24.     }
    25. }
     
    Last edited: Jun 3, 2022
  38. Fressbrett

    Fressbrett

    Joined:
    Apr 11, 2018
    Posts:
    97
    Just stumbled on this. My character controller is briefly set to kinematic during some moves and for some reason my trigger colliders fired OnTriggerEnter and Exit events on other Colliders my character stood within.
    Very odd und unintuitive behavior...

    I ended up moving the trigger collider outisde of my character controller hierarchy so that it's no longer a child of the Rigidbody that gets its Kinematic state toggled and set the transform position of my collider to the transform position of my character controller during Update().
     
  39. gotiobg

    gotiobg

    Joined:
    May 10, 2017
    Posts:
    19
    Instead of changing the value of Rigidbody's "isKinematic", change the constraints.

    When you want to set "isKinematic" to "true", set constraints to "RigidbodyConstraints.FreezeAll".
    If you want "isKinematic" to be "false", set the constraints to "RigidbodyConstraints.None".
    If you already have constraints, save them in a member variable, and instead of "RigidbodyConstraints.None" just set them back to the previous value.

    I have a feeling this is the intended way of stopping/starting a Rigidbody after the trigger change.
     
    toyhunter and rmon222 like this.
  40. EnokV

    EnokV

    Joined:
    Apr 14, 2016
    Posts:
    56
    This is a pretty old feature(by now) which was implemented for cases where you want the OnCollisionXX / OnTriggerXX methods to fire without the physics engine actually resolving collisions but kinematic/static pairs shouldn't be enabled per default. For 2D you can do the same but rather than a global setting it's a rigidbody property.
     
  41. rmon222

    rmon222

    Joined:
    Oct 24, 2018
    Posts:
    77
    This worked like a charm. Thank you.
     
    gotiobg likes this.
  42. unity_wvdBsmlMTIpFOQ

    unity_wvdBsmlMTIpFOQ

    Joined:
    May 22, 2019
    Posts:
    3
    I thought so too, but it seems that Frozen objects still conducts Force though not moving. Example: have laying cylinder with capsule collider, with Gravity and Frozen, lay box on top of it so that it won't fall - take some object, which collides with cylinder and struck cylinder- it is still, and the box is in stratosphere... In case of isKinematic it does't happen...