Collider on child game object triggers parent game object collider?

Hello,

I have a character game object with body CapsuleCollider2D and RigidBody2D on it.
There is also a child game object with weapon and CapsuleCollider2D.

I’m getting some behavior that doesn’t feel right for me.
When child weapon collider is triggered in OnTriggerEnter2D - parent collider is also getting triggered. Even though it’s not connecting to the triggerer.

Child-Parent-Colliders.png

Is there a way to avoid this behavior?

What makes you think the “parent is triggered”?

You always get a callback on the GO the collider is on and the GO the Rigidbody2D is on if it’s a different GO than the collider.

If you were to debug this and simply disable the parent collider you’d see this. That said, there’s no reason to think a collider that isn’t a trigger would, well, act as a trigger.

BOTH those colliders are created on the same Rigidbody2D. Physics doesn’t care or know about GOs.

I did debug this before posting question.
Either I don’t understand how it works or some details in my setup is creating this behavior.

This is how scene looks at the moment both parent and child OnTriggerEnter2D are triggered.
I’ll post the code below.

Code on parent game object:

private void OnTriggerEnter2D(Collider2D otherObject) {
    
        Debug.Log($"{gameObject.name}");
    
        // Check for Player for touch damage
        IDamageable HitObject = otherObject.GetComponent<IDamageable>();
    
        if (HitObject != null) {
        
            // If Player touches the enemy - apply touch damage
            if (otherObject.CompareTag("Player")) {
                HitObject.Damage(TouchDamage, transform.position);
            }
        }
    }

Code on child game object:

private void OnTriggerEnter2D(Collider2D otherObject) {
    
        Debug.Log($"{gameObject.name}");

        // If weapon hits Player
        IDamageable HitObject = otherObject.GetComponent<IDamageable>();
    
        if (HitObject != null && otherObject.CompareTag("Player")) {

            HitObject.Damage(DamageValue, transform.position);
        }
    }

In the console at the moment on screenshot above I see that both functions were triggered.
I see 2 messages in console and the player receives damage 2 times (touch damage from touching enemy body and enemy melee weapon damage).

9426359--1321340--Console-output.png

Did you read what I wrote about where a trigger contact is reported? It’s explained there.

The child trigger hits, the trigger is reported as I said in my previous post.

Also, your diagram that says no rigidbody indicates you don’t understand that it’s created using the rb on the parent. This is why it moves, only RB move in physics.

Wait. So does that mean there is no physical way to have two different colllider logic on one rigidbody?
That’s kinda bummer.
Feels like I’ll need to write crotches to make it work or use another method that is not colliders.

There is at least solution with OverlapCircleAll() but…
The nice thing with collider is that I can animate it.

MelyMay, let me reiterate if I understand correctly.
All the colliders that I have under single rigidbody simply behave like a single composite collider?

That’s not what they said.

They said:

Ergo, the message gets sent up to the rigidbody game object as well. Unity’s always worked like this. 2D and 3D.

If you want distinct colliders, make them siblings rather than children, and give them their own rigidbodies. Then you can use joints to move multiple rigidbodies together.

Thank you spiney199.

So the solution as I see is to have two children:

  • A dynamic rigidbody for body physics.
  • And a kinematic rigidbody for weapon.

The only thing I need to resolve now is how to move the character.
I was using Rigidbody.MovePosition().
And since Body rigidbody will become child - I won’t be able to move whole character this way. :frowning:

You will need some mechanism to move them together. Such as joints as I mentioned earlier, or even just coding one rigidbody to follow another.

Not in the same way as a composite collider no. You’re making this too complex. They are separate colliders unlike the composite collider which is a single collider with the other collider geometry merged together.

Each collider gets its own callback but as a “covenience”, it’ll also perform the same callback on the RB as I said above (that’s all); you’re confusing this helper callback as if it’s from the one on the RB. If you have two colliders you want to have their own callback so you know it’s always from that specific collider then simply place each collider as a child of the parent as siblings.

Nothing changes here in terms of movement, only a Rigidbody2D moves in physics. Colliders that are “attached” to them always live alongside it, they don’t move themselves. You don’t need to change your movement code.

The only time you’d need a separate RB on the “weapon” would be if you want it to move independently. Nothing about callbacks means you have to use a separate RB.

It’s 100% clear now.
Thank you very much spiney199!

Thank you! I’ll try this.
I thought if RB will be on child object it will not move parent and all the siblings.

I tried above solutions and it didn’t resolve the issue I have.

  1. I tried placing RB on parent and two colliders (body and weapon) on children. Both OnTriggerEnter2D() are fired when collider only on weapon touches the player (as on above images).
    Is there a way to get information which collider triggered collision?
    Is both OnTriggerEnter2D are fired because weapon collider “Is Trigger” (just throwing any ideas into the air)?

  2. About the second part that it won’t require to change movement code.
    I tried placing two RBs on children (RB + Collider on body, RB + Collider on weapon) + additional RB on parent and connect with body with joint.
    The code started working but I’m getting weird sliding behavior (as if physics affect parent game object) soooo…

I give up at this point.
If there is no way to tell which collider triggered OnTriggerEnter2D() - it’s becoming overly complicated to get “cool dynamic collider that will follow weapon path and form” ™.
I’ll just use Physics2D.OverlapCircleAll().

I’m almost going dizzy at the misunderstanding here. I keep thinking I’m just not following what you want but then reread and I’m sure I do understand.

You have a parent GO with a Rigidbody2D for movement? You have two children (one “body” and one "weapon)? Each child has a single collider and a script with OnTriggerEnter2D to detect “body” or “weapon”? OnTriggerEnter2D is called when that trigger collider on that specific GO triggers and you get a callback. Isn’t this what you want? I’m confused. This will only be called for that collider if it’s the only collider.

I have no idea why you’re messing with adding Rigidbody2D.
9429602--1322015--TriggerChildren.png

Hi MelvMay.

Wow! That awesome picture and it with description shows exact setup that I have.
Trust me - I’m not trolling you. It’s probably difference in knowledge and understanding.

Everything in setup is as you describe.
OnTriggerEnter2D() for Weapon and Body are also different scripts/classes.

What I see in reality - both OnTriggerEnter2D (Enemy Weapon and Body) are called when only 1 collider (Enemy Weapon) touches the Player collider.
This really confuses me since from my expectations only Enemy Weapon OnTriggerEnter2D should fire.
If it’s actually expected behavior (only Weapon OnTriggerEnter2D should be called) and what I’m describing (that both OnTriggerEnter2D are called) - I’ll double check this on clean project. Maybe something outside of my setup (some 3rd party code) is creating this behavior.

I tried two solutions - one of them was having separate RB for body and weapon. And a variation of this with 3rd RB on parent connected with joint to body.
I would prefer not to do this honestly. I didn’t feel normal. :slight_smile:
Actual setup (and the one I really prefer to use) is the one you described above.

Something else is going on there then because there’s absolutely no way that it would call both sibling colliders if only one were actually triggering; that would cause chaos.

I presume you’re actually ensuring that only these sibling colliders have that script (not on the parent other anywhere else) to make sure you’re not confusing it with a script somewhere else? That should be a quick test.

I believe at this point you should put together a simple reproduction and send it to me either here or in a DM.

No other OnTriggerEnter2D() - I double checked this just in case. Also the messages and values are different - this is how I first understood that both functions are triggered.
Two different classes, two different game objects, no other OnTriggerEnter2D on any of enemy parts.

I tested on clean project (just to be safe) and looks like the culprit is 3rd party Player controller. Clean project without it shown behavior as you described.
This player controller has a lot of stuff going on there to simulate Celeste-like physics. So I assume there is some logic that triggers second collision.

I’ll keep digging into this direction.

Thank you MelvMay for clearing it up.
At some point I though that there is some under the hood logic I don’t know and it triggers second collision (e.g. because two enemy colliders intersect).