[UPDATE ] Collisions or triggers nog always working?

[Different problem that seems to have somethign to do with this occured, look bottom]

Hi,

When I jump onto a certain gameobject, my player penetrates the polygon collider. Also tried adding a small boxcollider to see if that made any difference but it didn’t.
Here’s a gif of the problem:

As you can see the problem isn’t alway occuring, whats more is that this is the only object that has the problem, all other ground objects seem to work as intended.

Here are my colider setups:

(EDITED: wrong rigidbody settings)

Thanks for the help guys!
Hope I provided you with enough information.

[NEW PROBLEM]

MelvMay, it seems my problem is re-occuring with my bullets.

I have 2 types of bullets and the problems are I think simular in solution but the effect is somewhat different.

My first bullet type is a fireball, it just moves in straight lines, when colliding with a player it is destroyed unless it’s the player who fired the bullet, if it collides with another bullet or object or ground it should be destroyed aswel.
Now for some reason 2 colliding bulelts arn’t always detected, 2/3 times they get destroyed, 1/3 they just continue.

I just noticed that if I try hard enough I can even pass through walls:

This is my collision matrix:


The code that sees if any trigger has been made:

using UnityEngine;
using System.Collections;

/// <summary>
/// Stef Geukens
///
/// This code will determine if the object it is attached to has triggered a overlap with a collider object.
/// If so, the object is destroyed. When the object hits another player then his own (set playernum to the correct player)
/// then a function is called (Hurt) in the ShotPlayer script so thaty script knows when the score in the scorescript has
/// to be updated and for what player.
/// </summary>

public class BulletTriggerDetection : MonoBehaviour {
    public static BulletTriggerDetection BTD;
    public int playerNum = 1;
    public bool destroyOnImpact = true;
    public bool destroyOnTimer = true;
    public bool destroyOnNumberOfCollides = false;
    public int maxNumberOfCollides = 6;
    private int numberOfCollides = 0;

    void Start()
    {
        BTD = gameObject.GetComponent<BulletTriggerDetection>(); ;
    }

    void OnTriggerEnter2D(Collider2D  col)
    {
      Debug.Log(gameObject.name + " has collided with " + col.gameObject.name);
      Debug.Log("My layer: " + gameObject.layer);
      Debug.Log("Number of Impacts: " + numberOfCollides);

        if (playerNum == 1)
        {
       
                if (col.gameObject.tag == ("Player2") || col.gameObject.tag == ("Player3") || col.gameObject.tag == ("Player4"))
                {
                    col.gameObject.GetComponent<ShotPlayer>().Hurt(col.gameObject.tag, playerNum);
                    // Debug.Log("Player" + playerNum + " just shot " + col.gameObject.tag);
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player1") && destroyOnImpact)
                {
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player1"))
                {
                    numberOfCollides += 1;
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }


        }
        else if (playerNum == 2)
        {

                if (col.gameObject.tag == ("Player1") || col.gameObject.tag == ("Player3") || col.gameObject.tag == ("Player4"))
                {
                    Debug.Log("State1");
                    col.gameObject.GetComponent<ShotPlayer>().Hurt(col.gameObject.tag, playerNum);
                    // Debug.Log("Player" + playerNum + " just shot " + col.gameObject.tag);
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player2") && destroyOnImpact)
                {
                    Debug.Log("State2");
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player2"))
                {
                    Debug.Log("State3");
                    numberOfCollides += 1;
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }

        }
        else if (playerNum == 3)
        {


                if (col.gameObject.tag == ("Player1") || col.gameObject.tag == ("Player2") || col.gameObject.tag == ("Player4"))
                {
                    col.gameObject.GetComponent<ShotPlayer>().Hurt(col.gameObject.tag, playerNum);
                    // Debug.Log("Player" + playerNum + " just shot " + col.gameObject.tag);
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player3") && destroyOnImpact)
                {
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player3"))
                {
                    numberOfCollides += 1;
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }

        }
        else if (playerNum == 4)
        {


                if (col.gameObject.tag == ("Player1") || col.gameObject.tag == ("Player2") || col.gameObject.tag == ("Player3"))
                {
                    col.gameObject.GetComponent<ShotPlayer>().Hurt(col.gameObject.tag, playerNum);
                    // Debug.Log("Player" + playerNum + " just shot " + col.gameObject.tag);
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player4") && destroyOnImpact)
                {
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player4"))
                {
                    numberOfCollides += 1;
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }

      }
    }


    public static void destroyBullet(GameObject objectInNeedOfDestruction, float destroyTimer, bool hit, bool exDestroyOnTimer, bool exDestroyOnCollide)
    {
        Vector3 position = objectInNeedOfDestruction.transform.position;
        Quaternion rotation = objectInNeedOfDestruction.transform.rotation;
        if (BTD.destroyOnTimer && exDestroyOnTimer)
        {
            Destroy(objectInNeedOfDestruction, destroyTimer);
            BTD.showBulletAnimation(position, rotation, hit);
        }
        else if (BTD.destroyOnNumberOfCollides && BTD.numberOfCollides >= BTD.maxNumberOfCollides)
        {
            Destroy(objectInNeedOfDestruction, 0);
            BTD.showBulletAnimation(position, rotation, hit);
        }
    }


    public Transform hitPrefab;
    void showBulletAnimation(Vector3 position, Quaternion rotation, bool hit)
    {
        if (hit)
        {
            Transform hitParticleClone = Instantiate(hitPrefab, position, rotation) as Transform;
            Destroy(hitParticleClone.gameObject, 2f);
        }

    }
}

gameobject settings (rigidbody is set to continues):

The second type of bullet is a rubber ball, effected by gravity and it should bounce of objects and ground, and get destroyed by other bullets or hitting and killing a player.


As you can see this parent has been set as a trigger as to be destroyed by a player or another bullet, the child has been set as collider:


With very low speeds the rubber ball seems to work a bit beter but thats not what I want.

Thanks for looking in to it!

You need to provide information on how you’re moving the Rigidbody2D. Something is causing it to overlap other colliders which is typically because the position is being driven directly via the Transform or that Discrete collision-detection mode is being used on objects moving fast.

Hi MelvMay, euhm it’s code started from a tutorial from Brackeys, here’s my move code:

       public void Move(float move, bool crouch, bool jump, bool grab)
        {
            if (GetComponent<Rigidbody2D>().velocity.y < -maxFallSpeed)
            {
                GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, -maxFallSpeed);
            }

            //  Debug.Log("Grab: " + grab + " - Overlap: " + Physics2D.OverlapCircle(grabCheck.position, grabRadius, whatIsGround) + " - Grounded:" + grounded + " - Velocity: " + (GetComponent<Rigidbody2D>().velocity.y < wallSlideSpeedUpwardsDetection) + " - Times: " + (grabTimes < 1));
            if (grab && Physics2D.OverlapCircle(grabCheck.position, grabRadius, whatIsGround) && !grounded && GetComponent<Rigidbody2D>().velocity.y < wallSlideSpeedUpwardsDetection && grabTimes < maxOneSideGrap)
            {
                wallSliding = true;
                wallJumpAvailable = true; //so we can jump of the walls
                doubleJumpAvailable = false; //but we don't want another doublejump
            }
            else if (wallSliding == true)
            {
                grabTimes += 1;

                if (grabTimes > maxOneSideGrap - 1)
                {
                    //Debug.Log("Grab: " + grabTimes);
                    //ADD A WARNING ANIMATION HERE (is dit nodig?)
                }

                wallSliding = false;
            }
            else if (!(GetComponent<Rigidbody2D>().velocity.y < wallSlideSpeedUpwardsDetection))
            {
                wallSliding = false;
                wallJumpAvailable = false;
            }

            if ( wallSliding == true)
            {
                if (GetComponent<Rigidbody2D>().velocity.y < wallSlideSpeedUpwardsDetection)
                 {
                     GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, -wallSlideSpeedMax);
                 }
            else
                {

                }
            }


            // If the character has a ceiling preventing them from standing up, keep them crouching
            if (Physics2D.OverlapCircle(ceilingCheck.position, ceilingRadius, whatIsGround) && grounded)
                crouch = true;

            // If crouching, check to see if the character can stand up
            if (!crouch && anim.GetBool("Crouch"))
            {
                // If the character has a ceiling preventing them from standing up, keep them crouching
                if (Physics2D.OverlapCircle(ceilingCheck.position, ceilingRadius, whatIsGround))
                    crouch = true;
            }

            // Set whether or not the character is crouching in the animator
            anim.SetBool("Crouch", crouch);

            if (grounded)
            {  
                //when grounded again,reset grabTimes
                grabTimes = 0;
            }  

            //only control the player if grounded or airControl is turned on
            if (grounded || airControl)
            {
                // Reduce the speed if crouching by the crouchSpeed multiplier
                move = (crouch ? move*crouchSpeed : move);

                // The Speed animator parameter is set to the absolute value of the horizontal input.
                anim.SetFloat("Speed", Mathf.Abs(move));

                // Move the character
                GetComponent<Rigidbody2D>().velocity = new Vector2(move*maxSpeed, GetComponent<Rigidbody2D>().velocity.y);

                // If the input is moving the player right and the player is facing left...
                if (move > 0 && !facingRight)
                {
                    // ... flip the player.
                    Flip();
                    grabTimes = 0; //reset grabtimes so you can walljump from side to side
                    Debug.Log("Grab: " + grabTimes);
                }
                // Otherwise if the input is moving the player left and the player is facing right...
                else if (move < 0 && facingRight)
                {
                    // ... flip the player.
                    Flip();
                    grabTimes = 0; //reset grabtimes so you can walljump from side to side
                    Debug.Log("Grab: " + grabTimes);
                }
            }
            // If the player should jump...
            if (jump)
            {
                if (grounded && anim.GetBool("Ground"))
                {
                    // Add a vertical force to the player.
                    grounded = false;
                    anim.SetBool("Ground", false);
                    doubleJumpAvailable = true;
                    wallJumpAvailable = false;
                    GetComponent<Rigidbody2D>().velocity = new Vector2(0f, 0f);
                    GetComponent<Rigidbody2D>().AddForce(new Vector2(0f, jumpForce));
                }
                else if (doubleJumpAvailable)
                {
                    // Add a vertical force to the player. But less strong then starting from ground
                    grounded = false;
                    anim.SetBool("Ground", false);
                    doubleJumpAvailable = false;
                    wallJumpAvailable = false;
                    GetComponent<Rigidbody2D>().velocity = new Vector2(0f, 0f);
                    GetComponent<Rigidbody2D>().AddForce(new Vector2(0f, (jumpForceModifierDoubleJump * jumpForce)));
                }
                else if (wallJumpAvailable)
                {
                    // Add a vertical force to the player. But less strong then starting from ground
                    grounded = false;
                    anim.SetBool("Ground", false);
                    wallJumpAvailable = false;
                    GetComponent<Rigidbody2D>().velocity = new Vector2(0f, 0f);
                    GetComponent<Rigidbody2D>().AddForce(new Vector2(0f, (jumpForceModifierWallJump * jumpForce)));
                }
            }
        }

Thanks

From what you’ve posted, it seems you’re only moving via velocity/forces. If you are getting overlaps then it’ll be because you’re using Discrete collision detection mode. Try setting Continuous on the Rigidbody2D component.

Know that a PolygonCollider2D isn’t a single collider; it’s just a way to turn a (potentially) concave outline into multiple convex polygons. Box2D will only solve overlaps to each convex polygon individually so the solution doesn’t always move it away from the outline itself. This is why using continous mode is important as it can stop overlaps in the first place.

Solved, thank you very much for your help!

1 Like

MelvMay, it seems my problem is re-occuring with my bullets.

I have 2 types of bullets and the problems are I think simular in solution but the effect is somewhat different.

My first bullet type is a fireball, it just moves in straight lines, when colliding with a player it is destroyed unless it’s the player who fired the bullet, if it collides with another bullet or object or ground it should be destroyed aswel.
Now for some reason 2 colliding bulelts arn’t always detected, 2/3 times they get destroyed, 1/3 they just continue.

I just noticed that if I try hard enough I can even pass through walls:

This is my collision matrix:


The code that sees if any trigger has been made:

using UnityEngine;
using System.Collections;

/// <summary>
/// Stef Geukens
///
/// This code will determine if the object it is attached to has triggered a overlap with a collider object.
/// If so, the object is destroyed. When the object hits another player then his own (set playernum to the correct player)
/// then a function is called (Hurt) in the ShotPlayer script so thaty script knows when the score in the scorescript has
/// to be updated and for what player.
/// </summary>

public class BulletTriggerDetection : MonoBehaviour {
    public static BulletTriggerDetection BTD;
    public int playerNum = 1;
    public bool destroyOnImpact = true;
    public bool destroyOnTimer = true;
    public bool destroyOnNumberOfCollides = false;
    public int maxNumberOfCollides = 6;
    private int numberOfCollides = 0;

    void Start()
    {
        BTD = gameObject.GetComponent<BulletTriggerDetection>(); ;
    }

    void OnTriggerEnter2D(Collider2D  col)
    {
      Debug.Log(gameObject.name + " has collided with " + col.gameObject.name);
      Debug.Log("My layer: " + gameObject.layer);
      Debug.Log("Number of Impacts: " + numberOfCollides);

        if (playerNum == 1)
        {
        
                if (col.gameObject.tag == ("Player2") || col.gameObject.tag == ("Player3") || col.gameObject.tag == ("Player4"))
                {
                    col.gameObject.GetComponent<ShotPlayer>().Hurt(col.gameObject.tag, playerNum);
                    // Debug.Log("Player" + playerNum + " just shot " + col.gameObject.tag);
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player1") && destroyOnImpact)
                {
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player1"))
                {
                    numberOfCollides += 1;
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }


        }
        else if (playerNum == 2)
        {

                if (col.gameObject.tag == ("Player1") || col.gameObject.tag == ("Player3") || col.gameObject.tag == ("Player4"))
                {
                    Debug.Log("State1");
                    col.gameObject.GetComponent<ShotPlayer>().Hurt(col.gameObject.tag, playerNum);
                    // Debug.Log("Player" + playerNum + " just shot " + col.gameObject.tag);
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player2") && destroyOnImpact)
                {
                    Debug.Log("State2");
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player2"))
                {
                    Debug.Log("State3");
                    numberOfCollides += 1;
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }

        }
        else if (playerNum == 3)
        {


                if (col.gameObject.tag == ("Player1") || col.gameObject.tag == ("Player2") || col.gameObject.tag == ("Player4"))
                {
                    col.gameObject.GetComponent<ShotPlayer>().Hurt(col.gameObject.tag, playerNum);
                    // Debug.Log("Player" + playerNum + " just shot " + col.gameObject.tag);
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player3") && destroyOnImpact)
                {
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player3"))
                {
                    numberOfCollides += 1;
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }

        }
        else if (playerNum == 4)
        {


                if (col.gameObject.tag == ("Player1") || col.gameObject.tag == ("Player2") || col.gameObject.tag == ("Player3"))
                {
                    col.gameObject.GetComponent<ShotPlayer>().Hurt(col.gameObject.tag, playerNum);
                    // Debug.Log("Player" + playerNum + " just shot " + col.gameObject.tag);
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player4") && destroyOnImpact)
                {
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }
                else if (col.gameObject.tag != ("Player4"))
                {
                    numberOfCollides += 1;
                    destroyBullet(gameObject, 0, true, destroyOnTimer, destroyOnNumberOfCollides);
                }

      }
    }


    public static void destroyBullet(GameObject objectInNeedOfDestruction, float destroyTimer, bool hit, bool exDestroyOnTimer, bool exDestroyOnCollide)
    {
        Vector3 position = objectInNeedOfDestruction.transform.position;
        Quaternion rotation = objectInNeedOfDestruction.transform.rotation;
        if (BTD.destroyOnTimer && exDestroyOnTimer)
        {
            Destroy(objectInNeedOfDestruction, destroyTimer);
            BTD.showBulletAnimation(position, rotation, hit);
        }
        else if (BTD.destroyOnNumberOfCollides && BTD.numberOfCollides >= BTD.maxNumberOfCollides)
        {
            Destroy(objectInNeedOfDestruction, 0);
            BTD.showBulletAnimation(position, rotation, hit);
        } 
    }


    public Transform hitPrefab;
    void showBulletAnimation(Vector3 position, Quaternion rotation, bool hit)
    {
        if (hit)
        {
            Transform hitParticleClone = Instantiate(hitPrefab, position, rotation) as Transform;
            Destroy(hitParticleClone.gameObject, 2f);
        }
  
    }
}

gameobject settings (rigidbody is set to continues):

The second type of bullet is a rubber ball, effected by gravity and it should bounce of objects and ground, and get destroyed by other bullets or hitting and killing a player.


As you can see this parent has been set as a trigger as to be destroyed by a player or another bullet, the child has been set as collider:


With very low speeds the rubber ball seems to work a bit beter but thats not what I want.

Thanks for looking in to it!

Continuous won’t make any difference if it’s a trigger. You can completely tunnel through a trigger if the colliders are moving fast enough. Continuous only works when contacting non-triggers because it stops the collider at the point of contact whereas with triggers, this obviously isn’t the case.

All I can say is that Box2D has extremely robust continuous detection but this requires non-triggers. I can only presume as well that because you’re using Kinematic bodies, you’re moving them with forces/MovePosition. Also note that Kinematic won’t collide with Static colliders (the level colliders) and will only work as triggers which again, don’t work with continuous.

BTW: For this reason, fast-moving objects that need to touch triggers tend to use raycasts.

Still not sure how I can fix it. I will look in to the raycasts, thanks for the help!

If you can create a simple reproduction case that I could download then I wouldn’t mind taking a look at it.

Simple is ussually hard for me hehe. Thank you, I’m gonna try to fix it with raycasts like you said, if it doesn’t work out I will create a simple projectfile that you could look at.

Thanks allot!

Hey sorry to revive an old thread, but is there any way this information could be added to the documentation? The only mention of CCD in the manual is in the 3D physics section, and it has no mention of the impact on triggers. Some clarity here would have been very helpful. https://docs.unity3d.com/Manual/ContinuousCollisionDetection.html

1 Like

FYI: Work has begun on completely redoing the 2D physics manual so this will definately be content in the Rigidbody2D section. It’ll also be completely independent of the 3D physics content.

That’s great to hear. I was quite confused that the manual says that 2D is just “flattened” 3D, but I had understood that the 2D physics engine was a port of Box2D. Hopefully this will be clarified too. It’s one of those things where detailed, authoritative information is essential.

Thanks for the response. :slight_smile:

Honestly, the manuals all over the place have these kinds of statements which are designed to help think about how something works conceptually but some take it literally to mean implementation which of course it isn’t.

Yeah, I figured that was the case, but when you’re looking for what’s going on in the physics system (which is essentially a black box) these vague high level statements end up being all you have to go on. In any case I’m happy that it’s getting some love. Hopefully it will demystify some of these concepts for more experienced users and be a bit more thoughtful and specific in its use of language.

For what it’s worth that CCD page is actually an awesome explanation for 3D.