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. Dismiss Notice

Unity trigger compound colliders only once.

Discussion in 'Scripting' started by mrCharli3, Jun 26, 2018.

  1. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    956
    I am new to using several capsule colliders in children to create more "realistic" colliders. Usually I just attach one big one to the parent and call it a day.

    My problem is, I thought when you put a lot of colliders like this in children they would act like a compound collider. i.e several small ones act like one. But in my
    OnTriggerEnter()
    functions it counts each collider once, instead of just triggering once, which is causing a ton of issues.

    An example, I have an object with 5 capsule colliders, one in each child. making up head, neck, body, etc. I tagged them all as "AI". I then use this method, but it gets triggered more than once:

    Code (CSharp):
    1. private void OnTriggerEnter(Collider other)
    2.     {
    3.         if (other.CompareTag(Constants.TAG_AI))
    4.         {
    5.                 _aiInZone.Add(other.gameObject);
    6.         }
    7.     }
    What am I missing?
     
  2. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Have you got a single RigidBody on the parent, no RigidBody's on any of the children and the trigger script attached only to the parent? At least, that seemed to be the solution in 2015. So presumably it's still the case now. :)
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    So yeah, unfortunately unity though it will treat any physics impacted on a single collider grouped under a Rigidbody as impacting the entire Rigidbody.

    It does not group the enter/exit events. Those instead are on a per collider basis, and are only bubbled up to the Rigidbody. So if you have 3 child colliders, and they all are triggers, and something intersects all 3... you'll get 3 OnTriggerEnter events for the same object.

    Now in most cases I don't really care about the total intersection duration. I just care did it intersect, and then be done with it. For example a weapon... I might wait for an intersection and then place the thing that got struck into a HashSet so that way if I receive another event I just ignore it.

    But in situations where I need to know the full life... enter, stay, exit as if the colliders are all treated as one. Well I had to go and write this:
    https://github.com/lordofduct/space...cepuppyUnityFramework/Geom/CompoundTrigger.cs
    Note - it has a dependency on a an equality comparer which you don't actually need. And on a class called 'Messaging' which is really just my custom version of this from Unity and it can be used instead:
    https://docs.unity3d.com/Manual/MessagingSystem.html

    Yeah...

    So, this may look like quite a bit to get what you would hope would be fundamental to how colliders and rigidbody works.

    But unfortunately... nope... this is what I had to put together to get it.
     
    mrCharli3 likes this.
  4. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    956
    Thanks man, really good answer!
     
  5. SAMYTHEBIGJUICY

    SAMYTHEBIGJUICY

    Joined:
    Jul 12, 2023
    Posts:
    19
    Sorrry for the necropost but any idea if this is still the optimal solution to this?
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    "the optimal"... I couldn't say if it's the optimal.

    It's how I've done it, and still do it. There are other ways to do it as well.

    Furthermore, my approach there, as well as here in my most recent version of it:
    https://github.com/lordofduct/space...uppy.core/Runtime/src/Geom/CompoundTrigger.cs

    It's not exactly the "simplest" approach as it's got some broad generalizations/abstractions to allow it to be used in a large amount of scenarios. Such abstractions often bring in overhead. A more adhoc approach that targets your very specific needs can be better optimized as you can prune out the work that isn't necessary for you.

    Arguably you could just have a List<Collider> add entries onTriggerEnter, and remove them onTriggerExit on the Rigidbody. Assuming that these 2 events occur once per (for every enter, there will inevitably be an exit, per child Collider), you'll end up with duplicates of a given collider in the list for every child collider that exists and is intersected. But the downside here is that OnTriggerEnter/Exit aren't always guaranteed to fire. When you disable a child Collider it doesn't signal OnTriggerExit, and more annoyingly, when you enable it WILL trigger OnTriggerEnter. This will lead to doubling up because Enter/Exit aren't guaranteed to be called. (this goes for if the 'other' is disabled as well).

    But hey, if you know this will never happen, and that all colliders will always be active, then you could optimize to this simpler design. I couldn't make that guarantee in my generalized/abstract version as I had to cover ALL scenarios. So I had to add extra logic to account for those situations.
     
    Last edited: Aug 17, 2023
    SAMYTHEBIGJUICY likes this.