Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question "Continuous" collision does not give me the correct contact point

Discussion in 'Physics' started by Erenquin, Feb 8, 2023.

  1. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Hello,
    I'm trying to do a breakout game. Nothing too complicate ... in theory.

    I had everything seemingly working fine, until I wanted to accelerate the ball movement and noticed the contact is detected too late as you can see in the picture below.


    The ball has a size of 0.2, the brick has a Y size of 0.3.
    The collision is detected at Y position 0.14, so slightly above the bottom part which is at 0.15 (0.3 / 2).

    At first I setup the objects as triggers.
    When I noticed that problem I setup everything as colliders but the behavior is the same.

    I tested the different options for the Rigidbody setup, first activating "Full Kinematic Contacts", then switching "Collision detection" from discrete to continuous, then activating the "Interpolate" option. Same behavior.

    The ball and bricks are setup the same way:
    upload_2023-2-8_14-51-28.png

    According to the doc:
    Continuous: When the Collision Detection is set to Continuous, GameObjects with Rigidbody 2Ds and Collider 2Ds do not pass through each other during an update. Instead, Unity calculates the first impact point of any of the Collider 2Ds, and moves the GameObject there. Note that this takes more CPU time than Discrete.

    This is clearly not what I get.

    I could increase the ball hitbox or use some kind of epsilon to determine the Y collision (like 0.14 + epsilon > 0.15) but I would rather use the Unity physics engine.

    To be noted that at smaller speed of the ball I do not get this problem.
    In the past I remember I solved the same kind of collision issues by setting "Collision detection" to continuous, but it does not seem to work this time.

    [Edit]
    I setup back the objects (brick and ball) to Triggers and added an Epsilon half the size of the ball.
    While it works for higher speed, if I set some huge speed values, the behavior starts to be wrong again:
    at some speed the collision detection works for the bricks but not for the racket,
    At a higher speed the ball goes through some of the bricks and the trigger is register at like the 3rd row,
    and at even higher speed the ball goes through everything (all the bricks + the top part of the game area).
    Anyway it is working well enough for high enough speeds that I need, but I wonder how you could get bullets physics in a Unity games. I suppose we can't solely rely on the physics engine.

    Thanks for reading :)
     

    Attached Files:

    Last edited: Feb 8, 2023
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,100
    It's kinematic not dynamic so it won't stop/bounce and give you that kind of contact. Do you know that Kinematic doesn't have a collision response? You move it. Contacts are what it's overlapping when you ask for contacts. Your images doesn't really show anything TBH, it certainly doesn't show contacts. You can turn on contact display in physics settings.

    Intepolation has nothing to do with collision detection, it's visual only for the Transform. Continuous won't make any difference either unless you're contacting dynamic stuff because when you move a kinematic body, it moves there as it would using discrete. Again, no collision response.

    Why? Collision detection has been and always will be rock solid in 2D so there's no reasons not to trust it. :)

    There could be a number of things you're doing here such as modifying Transforms but TBH you need to provide more information such as how you're "moving" the Rigidbody2D, how you're getting contacts (etc) so we can figure out what's going on for you.
     
    ManuelRauber likes this.
  3. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Hello, thanks for the reply.

    Yes, I'm originally using triggers, no collisions and handling everything in the "OnTriggerEnter2D"

    I get the "hitposition" as such:
    Vector2 hitpos = new();
    hitpos = rb2D.position - new Vector2(collision.transform.position.x, collision.transform.position.y);

    To check wheter the ball is above (or below) the brick, I use this formula:
    if (Mathf.Abs(hitpos.y) > collision.transform.localScale.y / 2.0f)
    {
    Debug.Log("Top / bottom hit");
    velocity.y = -velocity.y;
    }

    But it is slightly too late:
    upload_2023-2-15_10-27-16.png

    As for the movement, it is in the Fixedupdate, nothing special:

    void FixedUpdate()
    {
    if (isMoving)
    {
    rb2D.MovePosition(rb2D.position + velocity * Time.fixedDeltaTime);
    }
    }

    By contacts physics, do you mean this option ?
    upload_2023-2-15_10-14-50.png

    The collider 2d shows "No contacts", not sure if it is related. This info is just at the time of trigger detection:
    upload_2023-2-15_10-31-30.png
     

    Attached Files:

  4. ManuelRauber

    ManuelRauber

    Joined:
    Apr 3, 2015
    Posts:
    115
    Well, you're still using Kinematic movement instead of dynamic movement. So everything @MelvMay wrote is true.
    Either use go the dynamic way, let the physics engine handle collision detection or you do kinematic movement and have to handle it on your own.
     
  5. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Thanks, yes indeed I did not mean he was wrong obviously he is not, but there is probably something I do not get.

    Does this mean that "Trigger" is also related to Dynamic way and wil not behave as I expect when using Kinematic ?
    That's probably the problem I have.

    Well I was thinking trying to use physics (dynamic) anyway. For a lot of things it will probably be easier.

    The only problem I have is that I wanted to control the speed (velocity) of the ball to set it to specific values (rather that using "add force").

    Also I wanted to control the direction of the ball when it hits the center of the racket with a delta so that the ball goes straight vertically.

    Finally as I will disable gravity (because the ball must keep its speed), I'm not sure how the whole thing will behave when the ball hits a brick and has to bounce back in the "down" direction.

    So those are reasons I originally used Kinematic.
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,100
    Yeah, you've got a bunch of misconceptions here. So the main thing is thst triggers don't calculate contact points, they're not needed because there's no collision response. Contract points are calculate for this reason alone.

    In simple terms though, Kinematic turns off all forces acting on the body including collision response, gravity, user-forcea etc. If you want this then you use a Kinematic body. it has nothing to do with any other requirements. By using triggers you don't get any contact points either but it looks like you want them so you should not be using triggers. As their name suggests, they're used to trigger an action when you overlap a collider only.

    Note though that this isn't a "hit position":
    Code (CSharp):
    1. hitpos = rb2D.position - new Vector2(collision.transform.position.x, collision.transform.position.y);
    collision.transform is just the transform component on the GameObject you're using, it's nothing to do with the collider.

    If you want actual contact points but no collision response then use a Kinemtatic Rigidbody2D for your ball and enable useFullKinematicContacts. Don't use triggers and this'll act like a collision with full contacts (it'll have contacts, will call OnCollisionEnter2D etc) but as a Kinematic body won't give you the point on the exterior of a collider, it doesn't stop there, it'll continue going through it and overlap because there's no collision response. This is why you always use physics queries to determine what it'll hit etc.
     
  7. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Thanks for all the insight and taking the time to answer :).

    I already tried in the past to use useFullKinematicContacts and colliders but I get similar result indeed.
    The collision callback which does this (I know we should not set velocity, it is only for trial):
    private void OnCollisionEnter2D(Collision2D collision)
    {
    Debug.Log("Brick collision start");
    if (collision.collider.tag == "Brick")
    {

    velocity.x = 0.0f;
    velocity.y = 0.0f;

    Is happening there:
    upload_2023-2-15_14-17-6.png

    But I see that I have a contact point now as well:
    upload_2023-2-15_14-17-49.png
     
    Last edited: Feb 15, 2023
  8. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    The reported contact point in Y is not as in my previous post, and, as you mentioned, not giving the exterior contact either.
    It is ultimately giving me the same result.

    Well I will try to use Dynamic physics and see what I can get.

    upload_2023-2-15_14-52-3.png
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,100
    But why? It's Kinematic, that's the whole point of it. For sure, doing this on a Dynamic body can have consequences if you do it without consideration but the physics engine won't ever modify the velocity of a Kinematic body so there's no reason not to; the opposite in-fact, it's how you can get it to move. I think you've not understood what Kinematic is and you've not understood what "no collision response" means because you seem to be indicating that the ball is overlapping and is not giving you the surface contact points. I would suggest you read up on Kinematic bodies or re-read what I said above. :)

    Really simply, you need to use physic queries if you need to determine when a Kinematic body/collider(s) will first hit something.

    You don't "try" it, you decide which body type to use based upon what you want as I described above. Use a Dynamic body if you want a coliison response and forces. You can change the velocity based upon the position you hit your paddle, that's not difficult and doesn't nessesitate using a Kinematic body.

    As I've said, if you're using Kinematic because you don't want a collision response then use physics queries such as Rigidbody2D.Cast. Plenty of tutorials around on 2D Kinematic motion, physics queries etc.

    Hope that helps to finally clear up your issue.
     
    ManuelRauber likes this.
  10. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Thanks for all the explanations and information.
     
    MelvMay likes this.