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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

compound colliders registering multiple collisions, want only one

Discussion in 'Editor & General Support' started by TGKG, Mar 28, 2017.

  1. TGKG

    TGKG

    Joined:
    Dec 31, 2014
    Posts:
    180
    I have searched thru the forums without a consistent answer. My apologies if I missed something.

    I have a 2D gameObject (plane) that is made from several primitive 2D BoxColliders. When the plane gets hit by a bomb (bomb is intended to pierce thru the plane and continue to hit other targets) and the plane is to take damage, how do I prevent a single bomb from registering multiple collisions and thus registering multiple damage from the one hit. I just want the bomb to register ONE hit from the bomb.
    Plane has:
    Plane parent object has a Rigidbody2D.
    4 - 2D BoxColliders (set as Triggers) for the body, Tail section, wing section &
    1 - 2D BoxCollider (set as a Collider) for the wheels (so the plane can sit on the ground).
    (See image for 4 - 2D BoxTriggers & 1 - 2D BoxCollider on the plane).
    Bomb is made from 1 - 2D BoxCollider

    upload_2017-3-27_23-27-53.png
    upload_2017-3-27_23-32-23.png

    As can be seen the bomb may hit a single collider, however it could also hit the plane at the wing and pass thru up to 3 colliders. (Wing, body and wheel)

    I have tried various OnTriggerEnter ideas, but nothing is even close to working, hence no point in me showing any code. In reality I have no idea even how to start on this.

    Maybe I am not using the colliders / triggers correctly or maybe there is a better way of setting these colliders up.

    Can anyone help please!
     
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,201
    The 2D docs are a lot less clear than the 3D docs on what exactly a compound collider does, but you should only be getting one if I'm reading them right.

    If you put the script with the OnTriggerEnter2D call on the rigidbody, are you getting several of those messages from one hit?
     
  3. TGKG

    TGKG

    Joined:
    Dec 31, 2014
    Posts:
    180
    Yes, The script with the OnTriggerEnter is on the plane parent object (also has a rigidbody2D attached to the parent). The colliders are all on the children objects.
    There is definitely an OnTriggereEnter event that is registered for each collision with each of the colliders. There is also definitely an OnTriggerExit event registered for each collider exit.

    If I remove the rigidBody from the parent, then NO collisions are registered by the OnTriggereEnter()

    Example: If the bomb passes thru the plane Wing, plane body and hits the plane wheel, there are 3 different onTriggerEnter events registered by the code.

    Code (CSharp):
    1. //Attach this script to the plane parent
    2. void OnTriggerEnter2D(Collider2D col)
    3.     {
    4.         print("TrigEnter " + col + ", colliderTag= " + col.tag + ", colliderName= " + col.name);      
    5.      
    6.     }
    I am not sure how to convert this into only ONE collision so that I can give the plane only one hit of damage.
     
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,201
    You could just do it in code - keep a list of all bombs that has hit the plane, and check if the bomb has already hit the plane before you apply damage.
     
    unity_6ZMJlhFpaWH3QA likes this.
  5. TGKG

    TGKG

    Joined:
    Dec 31, 2014
    Posts:
    180
    Thank you for taking the time to think about this problem.
    Not sure exactly what you mean. My problem is that the one bomb hits each of the plane colliders and triggers an OnTrigger event with each collider it hits.

    I guess what I need is a way to keep track of when the bomb hits the first collider and then when the same bomb hits the second collider on the plane it knows about the first collision and ignores that second collision, and when that same bomb then hits the third collider on the plane it knows about the first and second collision and ignores that third collision. Thus I only apply damage to the plane the one time. Not sure how to do what I just described. If you have any ides that would be great.

    Also, is the way I am using the colliders the "normal" or "proper" method? ie: is using multiple colliders in this situation proper or is there a different way of doing collisions like this?
     
  6. Moonjump

    Moonjump

    Joined:
    Apr 15, 2010
    Posts:
    2,572
    I haven't used compound colliders for a while (and I have only done it in 3D), so I may be wrong, but hopefully these are options that might work, or at least worth trying.

    Does the plane parent object have a collider? It was explained to me as having a rigidBody and collider on the parent object, and a collider on each child. That way the child colliders are treated as part of the parent collider. Your description makes me think you only have the child colliders.

    If that doesn't work, try changing all the colliders to Triggers. It might be the mix that is the issue. If it is the problem, you could set up separate colliders to allow it to sit on the ground.
     
  7. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,201
    For 2D, you can use polygon colliders to draw an outline of your model. It's probably just as fast as the compound solution.

    My idea is exactly what I said, keep a list:

    Code (csharp):
    1. private List<Bomb> alreadyHitBy = new List<Bomb>();
    2.  
    3. void OnTriggerEnter2D(Collider2D other) {
    4.  
    5.     Bomb bomb = other.GetComponent<Bomb>();
    6.  
    7.     if(bomb != null && !alreadyHitBy.Contains(bomb) {
    8.         alreadyHitBy.Add(bomb);
    9.         GetDamagedBy(bomb);
    10.     }
    11. }
    If your logic is inverse - ie. the bomb deals damage instead of the planes checking for damage - your TakeDamage function on the planes needs to take the bomb as a parameter and then do the same thing.
     
  8. TGKG

    TGKG

    Joined:
    Dec 31, 2014
    Posts:
    180
    The plane parent object does not have a trigger or collider. All of the triggers and collider are on children objects. I will try changing the one collider to a trigger and see what happens.

    Hmm, Your comment about setting up a separate collider to have the plane sit on the ground is interesting. Are you suggesting that I could somehow have a separate collider NOT part of the plane that would make the plane sit on the ground. How would that be possible? or am I misunderstanding.

    Polygon collider, that sounds very very good. Is the performance using a polygon collider the same as using a primitive box or circle collider? I read somewhere that using a mesh collider was quite expensive on the CPU. Not sure if the polygon colliders fall into the same category as a mesh collider?

    I see where you are going with this code snippet. Let me wrap my head around this and try something.

    Thank you to both of you for the ideas.
     
  9. TGKG

    TGKG

    Joined:
    Dec 31, 2014
    Posts:
    180
    Changing the one collider to a trigger (now all are triggers) did not change anything. I still get multiple collisions occurring.
     
  10. bigChris

    bigChris

    Joined:
    Jul 5, 2017
    Posts:
    8
    Late to the party here, but if this issue can't be resolved with the preferred "layer" matrix methods provided by the Unity Game Engine, and you can tolerate the comparison, try:

    Code (CSharp):
    1. private int objectGUID;
    2.  
    3. void Start(){
    4.    objectGUID = 0;
    5. }
    6.  
    7.     void OnTriggerEnter(Collider other) {
    8.         if(other.CompareTag("someHazard")){
    9.             int temp = other.GetInstanceID();
    10.             if (temp == objectGUID)
    11.                 return;
    12.             objectGUID = temp;   // Thus the next collider OnTriggerEnter event from your
    13.                                // compound collider will early return.
    14.             // ... further processing as needed.
    15.     }
    Now of course, if the exact same object tagged "someHazard" comes around and hits your object again, you'll get an unwanted early return. To combat that issue, using either Invoke() or StartCoroutine() methods to reset int ObjectGUID back to "0" in as short a time as is needed.
     
    Last edited: Nov 14, 2019
  11. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,201
    Why on earth would you convert the instance id to a string, instead of keeping it as an integer?
     
  12. TGKG

    TGKG

    Joined:
    Dec 31, 2014
    Posts:
    180
    Thank you for taking the time to answer this problem.

    I thought I noticed in an update release that Unity now has the ability to combine multiple colliders to act as one common collider. I have not gone investigating this yet.
     
  13. bigChris

    bigChris

    Joined:
    Jul 5, 2017
    Posts:
    8
    I think you're correct - I was uncertain how large a number InstanceID returns, but further looking / testing says Int32 is fine as a data type. Coming from C, take nothing for granted. Thank you!

    However, on second thought, can GetInstanceID() ever return zero? Since you cant null an int in C#, and you're worried about the 1 in ( 2,147,483,648 x 2 +1) chance that it does, then the string version would be your best bet as we can use the empty string "" as a reset value...
     
    Last edited: Nov 16, 2019