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.

Question Physic Ignore Collision not working specifically with CircleCollider2d

Discussion in 'Physics' started by Icy_Ghost, Sep 4, 2023.

  1. Icy_Ghost

    Icy_Ghost

    Joined:
    Jul 2, 2023
    Posts:
    6
    Hello, I'm pretty new to unity so I hope you will help me get this right.

    So I faced a problem with Physic2d.ignoreCollision on my environment and I managed to reproduce the same problem on a smaller scale so here it is.

    I have a surface (ground) and a ball, the ball has a rigidbody2d and a CircleCollider2d so that it can roll on the surface, but it also has a trigger collider in a child component that I need for other purposes. So I want to disable the collision between the ball and surface when the child component is triggered. For that purpose I'm running this code in the child component.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class fallThrough : MonoBehaviour
    6. {
    7.     BoxCollider2D groundCollider;
    8.  
    9.     bool isCollision = true;
    10.  
    11.     private void OnTriggerEnter2D(Collider2D collision)
    12.     {
    13.         // setting the collider object
    14.         groundCollider = collision.gameObject.GetComponent<BoxCollider2D>();
    15.         Debug.Log("ground collider set up to : " + collision.gameObject.name);
    16.         DisableCollisionGround();
    17.     }
    18.  
    19.     private void OnTriggerExit2D(Collider2D collision)
    20.     {
    21.        
    22.     }
    23.  
    24.     void DisableCollisionGround()
    25.     {
    26.         if (isCollision)
    27.         {
    28.             CircleCollider2D playerCollider = gameObject.GetComponentInParent<CircleCollider2D>();
    29.             Physics2D.IgnoreCollision(groundCollider, playerCollider, true);
    30.             Debug.Log("collision disabled with : " + groundCollider);
    31.             isCollision = false;
    32.         }
    33.     }
    34.  
    35.     void EnableCollisionGround()
    36.     {
    37.         if (!isCollision)
    38.         {
    39.             Collider2D playerCollider = gameObject.GetComponentInParent<Collider2D>();
    40.             Physics2D.IgnoreCollision(groundCollider, playerCollider, false);
    41.             isCollision = true;
    42.         }
    43.     }
    44. }
    45.  
    So the code didn't work at all, I have all the Debug messages saying that the collision has been disabled but still the ball was rolling on the ground.

    So I just tried changing the collider of the child element from CircleCollider2d to BoxCollider2d and it worked perfectly, same thing for CapsuleCollider. Matter of fact, I didn't have to change anything in the code, just changing the collider seems to fix the problem.

    But I don't really understand, because the child component collider shouldn't have anything to do with it since it is only used as a trigger, only the Collider of the parent element should matter, besides why does specifically the CircleCollider2d struggle to make it work. Does it mean it is bad practice to have the same type of collider on both a parent and child component ?

    I would really appreciate any answer, I could just use the BoxCollider2d and call it a day, but I don't really want to run into another problem like that and be stuck just trying different thing randomly.

    Thank You !
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,801
    The post title isn't possible and the problem will be in your script, not the physics system as individual collider types don't deal with this differently so it cannot just fail on a specific collider type. Indeed, this works at a physics shape level so way, way below anything related to colliders.

    Parent/Children and the Transform hierarchy or how many components are nothing to do with the physics system at this point.

    This is dangerous:
    Code (CSharp):
    1. groundCollider = collision.gameObject.GetComponent<BoxCollider2D>();
    The collider you hit is passed to you yet you ignore that, get the GameObject that specific Collider is one and fetch a BoxCollider2D on it. This is prone to error unless you have exactly one collider on the same GameObject of the collider you hit. Just use the one you hit that is passes to you!

    If the ground collider is the only trigger then you do:
    Code (CSharp):
    1. groundCollider = collision;
    The first thought shouldn't be that Unity is not working. ;)
     
  3. Icy_Ghost

    Icy_Ghost

    Joined:
    Jul 2, 2023
    Posts:
    6
    Thank You for your reply.
    I'm not really assuming that unity is not working that's why I'm asking these questions because I believe there must be some time of underlying property causing this, that's what I really want to understand in order to interact correctly with the engine in the future.


    [LIST=1]
    [*]groundCollider = collision.gameObject.GetComponent<BoxCollider2D>();
    [/LIST]

    The main reason why I had this line of code, is that I was so desperate for it to work that I had thought maybe it would work if I pass the exact type of Collider2d as an argument to the function.

    I changed it back to just :

    [LIST=1]
    [*]groundCollider = collision;
    [/LIST]

    But it still doesn't seem to work with the CIrcleCollider2d, it works perfectly with the other Collider still.

    I understand what you are saying about it not having anything to do with the Collider type hence my confusion as to why I'm getting this behavior.

    Do you need more details about the environment, I made it as simple as possible just to be able to reproduce the problem.

    Thank You !
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,801
    I was going on the title alone which states that IgnoreCollision isn't working on a specific collider.

    In the end, I cannot debug this for you as it'll be a logic problem or misunderstanding on your end and I don't know what that is.

    All you've really said is that it "isn't working" and whilst that means a lot to you, it could mean anything to me. I don't even follow the logic above; empty OnTriggerExit2D, EnableCollisionGround not called anywhere, what debug stuff is being output, have you limited what can contact what with the layer-collision-matrix etc.

    Bare minimum is:
    • What are the components/hierarchy (sort of done).
    • Appropriate script(s) - Done.
    • What do you expect to happen (specifically)
    • What is actually happening (specifically)
     
  5. Icy_Ghost

    Icy_Ghost

    Joined:
    Jul 2, 2023
    Posts:
    6
    So I have attached images of the component of the environment to this post but basically since I'm just replicating the problem, that's why I'm not using everything in the code, but I will make it even more simpler. T
    here are only three components :
    The ground which has a BoxCollider2d
    The Ball which has a rigidbody2d and a Circle Collider 2d in order to interact with the ground
    A Child Component Attached to the ball which has a trigger collider attached to it in order to trigger an event.

    In this case the event is when the Child Component is triggered to disable the collision between the ball and the ground.

    When the child Component trigger collider is set to Circle Collider 2d, it doesn't work hence the ball keeps rolling on the ground.

    When the child component trigger collider is set to anything else, it does work as expected and ball just go right through the ground (desired behavior).

    My question is why does not disable the collision when it is a CIrcle Collider 2d.
    All the debug messages saying the collision have been disabled appear, but still no changes.

    Here is the code for the environment.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class fallThrough : MonoBehaviour
    6. {
    7.     // Start is called before the first frame update
    8.     Collider2D groundCollider;
    9.  
    10.     bool isCollision = true;
    11.  
    12.     private void OnTriggerEnter2D(Collider2D collision)
    13.     {
    14.         // setting the collider object
    15.         groundCollider = collision;
    16.         Debug.Log("ground collider set up to : " + collision.gameObject.name);
    17.         DisableCollisionGround();
    18.     }
    19.  
    20.  
    21.  
    22.     void DisableCollisionGround()
    23.     {
    24.         if (isCollision)
    25.         {
    26.             // getting the parent collider
    27.             CircleCollider2D playerCollider = gameObject.GetComponentInParent<CircleCollider2D>();
    28.            
    29.             // disabling collision
    30.             Physics2D.IgnoreCollision(groundCollider, playerCollider, true);
    31.  
    32.             Debug.Log("collision disabled with : " + groundCollider);
    33.            
    34.             isCollision = false;
    35.         }
    36.     }
    37.  
    38. }
    39.  
    Hope this summarize the problem a little bit more.
    Thank You !
     

    Attached Files:

  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,801
    Yeah, that doesn't make sense. Note that you're also not disabling the trigger collider ever.

    If you can package up the project above and send it me I could take a look? Delete the library folder first though to reduce the size.

    Note that because you're using a later Unity version, you can Layer Overrides which are much better. For instance, given a "ground" layer, you could Exclude that layer on the ball. You can also do this for the Rigidbody2D so it affects all the colliders or per-collider.

    https://docs.unity3d.com/ScriptReference/Collider2D-excludeLayers.html
    https://docs.unity3d.com/ScriptReference/Rigidbody2D-excludeLayers.html
     
  7. Icy_Ghost

    Icy_Ghost

    Joined:
    Jul 2, 2023
    Posts:
    6
    I kind of need the trigger Collider so that I know the event as triggered, this setup seems pretty messy but it is this way because I just want to emphasize on the actual problem, otherwise I'm not really planning to leave things this way in a bigger environment.

    I had thought about using that solution of excluding the layers, but I can't really use that in my real project, because I need the "ball" to interact with other elements of the "ground" layer, that's why I keep track of groundCollider in a variable so that I can later enable it back.

    I have the project attached to this post, let me know how it worked for you, Thank You !
     

    Attached Files:

  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,801
    I'll take a look at this ASAP (it's evening time here).

    Fair enough. Note that if it suited you could instead stop that Ground object interacting with the "Player" layer too so it's specific to that ground collider.
     
  9. Icy_Ghost

    Icy_Ghost

    Joined:
    Jul 2, 2023
    Posts:
    6
    Thank you for the suggestion, I could try that, but I know already know a sort of work around this behavior, in order to get a circular shape, I can just alter a little bit the shape of the capsule collider and it will work as expected.

    It's not so much about getting a specific solution in particular to this problem, I already have that figured out, it's more about why this behavior is there, and is it intended or is it simply a bug. If you tell me it is a bug, it will simply put my mind at ease and I won't worry too much about it, but if it's not, I sort of feel like I'm missing a key component and I have something to learn here if that makes sense.

    Thank you...
     
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,801
    Actually, looking at your code again I think the problem is this line:
    Code (CSharp):
    1. CircleCollider2D playerCollider = gameObject.GetComponentInParent<CircleCollider2D>();
    https://docs.unity3d.com/ScriptReference/GameObject.GetComponentInParent.html

    This gets the component on the GameObject or the Parent so this'll be why. This will just get the CircleCollider2D trigger which explains why it works when you don't use a CircleCollider2D as it'll then find the parent one.

    I personally think it's an odd behaviour given its name but it is what it is. :)

    Best thing is to just reference the parent Collider2D in the script then just ignore that. Saves time finding it too.

    In theory this will fix it too:
    Code (CSharp):
    1. CircleCollider2D playerCollider = transform.parent.GetComponent<CircleCollider2D>();
     
  11. Icy_Ghost

    Icy_Ghost

    Joined:
    Jul 2, 2023
    Posts:
    6
    Tha
    Thanks so much, that's exactly it, seems like I was a little confused by the name. It works perfectly and in all cases now.

    Thanks again for taking the time to help.
     
    MelvMay likes this.
  12. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,801
    I've discovered this behaviour myself, forgot it, got stung, rediscovered it! I feel your pain and you're not alone!

    Anyway, glad it got you moving forward and good luck.