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. Dismiss Notice

Trouble with using Physics2D.BoxCast in order to make a game object collide with another game object

Discussion in 'Scripting' started by egonspengler_84, Jun 19, 2021.

  1. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153
    So I'm trying to figure out how to simulate gravity on a game object that has a Kinematic Rigidbody2D by using the Physics2D.BoxCast function but I'm finding it difficult to get the object to collide flush with the ground underneath it as it is falling. It seems to fall through the ground before it stops.

    Here is the code that I've written:
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class Simple2 : MonoBehaviour
    7. {
    8.  
    9.     public bool grounded;
    10.     public LayerMask _whatIsGround;
    11.     public Vector2 velocity;
    12.     private Rigidbody2D _rb;
    13.  
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.         _rb = GetComponent<Rigidbody2D>();
    18.     }
    19.  
    20.     // Update is called once per frame
    21.     void FixedUpdate()
    22.     {
    23.         RaycastHit2D boxResult;
    24.         boxResult = Physics2D.BoxCast(transform.position, new Vector2(1,0.5f),0f, new Vector2(0,-1),0.25f,_whatIsGround);
    25.  
    26.         if(boxResult.collider != null){
    27.  
    28.            grounded = true;
    29.        
    30.         }else{
    31.  
    32.            grounded = false;
    33.        
    34.         }
    35.  
    36.  
    37.         if(grounded == true){
    38.  
    39.             velocity.y = 0;
    40.  
    41.         }else if(grounded == false){
    42.  
    43.            velocity += Physics2D.gravity * Time.deltaTime;
    44.          
    45.  
    46.  
    47.         }
    48.          _rb.MovePosition(new Vector2(_rb.position.x,_rb.position.y + velocity.y * Time.deltaTime * 3));
    49.      
    50.     }
    51. }
    52.  
    53.  




    Here is a video of the issue:


    Could someone recommend a way to solve this problem that I'm having? If you think there's a better way of going about this without using Physics2D.BoxCast please let me know.

    Kind regards
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,756
    Around line 39 above, use the
    .point
    field of the returned
    RaycastHit2D
    to place your object at the correct altitude. Obviously if the lower edge of your character is not at its numeric center, you will need to vertically offset it appropriately.
     
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,529
    For starters, your sprite is showing this as a uniform box (equal length sides) but your cast is defining a box of size (1f, 0.5f) so it seems your visuals are not matching. Also, I don't understand the "grounded" logic. If you are within 0.25f distance then you consider this grounded; that doesn't seem correct.

    This is physics so don't use the Transform as the position/rotation authority, use the Rigidbody2D.position/rotation. This is especially true if using interpolation as they won't match.

    I presume this is a Kinematic Rigidbody2D? You could add a BoxCollider2D and then perform Collider2D.Cast or Rigidbody2D.Cast so you only have to provide the direction/distance to cast and not the shape(s) to cast.

    Also, assuming this is a Kinematic Rigidbody2D then you can turn on Rigidbody2D.useFullKinematicContacts (if not then you can ignore that step) and simply query if you're touching with Collider2D.IsTouching or Rigidbody2D.IsTouching with just a ContactFilter2D set to filter only ground-layers from below. You can even set that up in the inspector to be used by your controller script. The IsGrounded can then become as simple as this.

    You can see this here:


    Another example of Kinematic motion can be found here that uses queries to determine where something can move and also includes sliding along surfaces:


    You could easy add gravity to this which is just another form of movement "input".


    I'm curiously; I'm pretty sure I've seen you doing this for the last few months so did you have it working and you've now changed something and it stopped working?
     
  4. egonspengler_84

    egonspengler_84

    Joined:
    Jan 26, 2021
    Posts:
    153


    Yeah I've been at this for months and I am really frustrated by my lack of progress. I'm basically trying to figure out how to implement common 2D platformer physics and collisions using a Kinematic Rigidbody2D for the Player rather than relying on the "out of the box" Physics that Unity provides through using a Dynamic Rigidbody2D. So at the moment I'm focusing on the following:

    1. Making the Player stop flush against the ground beneath him once as he is falling(ground collision).
    2. Wall collisions

    Initially I thought to do this with using raycasts that fire from the bottom of the Player towards the ground and then once the distance of the raycast equals zero I make the value of gravity zero so that the Player will rest flush against the ground. However I had problems with this as I had to account for floating point imprecision(hit.distance will rarely be zero) and the way I got it to work in the end with code seemed very ungraceful and buggy.

    So recently I came across Rigidbody2D.Cast and Physics2D.BoxCast and I was hoping that using these things could provide a graceful and non-buggy way of creating the collisions that I want.

    You've suggested that I use either Collider2D.Cast or Rigidbody2D.Cast and I've been reading about Collider2D.Cast on Unity docs but I don't really understand how to actually implement it from reading what's on that page? Underneath the declaration heading it has the following:

    Code (CSharp):
    1. public int Cast(Vector2 direction, RaycastHit2D[] results, float distance = Mathf.Infinity, bool ignoreSiblingColliders = true);
    I don't understand what am I supposed to do with this information? It seems that I'm supposed to declare an int variable called Cast but I don't understand what I'm supposed to do with the parameters? Unity Docs seems to present information in quite an unpalatable way for a beginner such as myself.
     
    Last edited: Jun 20, 2021
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,529
    You are asking basic C# questions though here. The docs do clearly state that it returns how many results so I'm not sure of the value of me trying to reword that.

    Returns
    int The number of results returned.

    What else is confusing? Direction? Distance? Providing an array or list for results?

    That is only one of several overloads of that method.

    If you are struggling to understand these arguments then I would suggest trying to do full kinematic motion is a bit too much and you should try dynamic motion. When you do Kinematic, you're doing everything yourself.
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,529
    Also, did you look at the links I provided for you? They show you how to use it in code such as here. You don't have to understand the controller itself but it clearly shows you how you can use that cast call and how to provide arguments to it.