Search code examples
unity-game-engine2draycastingcollider

Physics2D.Raycast Works On Some Objects But Doesn't Work On Others


So I'm trying to make a clone of Super Mario Bros for practice. I was creating the World 1-1. Everything was working great: I could move, enemies can move and be killed, and blocks can be interacted just like expected. But at this time I was using colliders and they were causing some problems here and there, also I couldn't find a way to make the enemies move in the opposite direction when they are faced with a collider. So I looked at some other people and saw that they were using raycasting. Then decided to try it myself. There was no problem on the enemy script.

Enemy Script

private void RayCast()
{
    // Getting the max distance by using the size of the collider and creating the ray itself
    float rayMaxDistance = GetComponent<BoxCollider2D>().bounds.size.x/2;
    Ray2D ray = new Ray2D(transform.position, Vector2.right);
    
    // This way ray will be casted in the direction the enemy goes.
    if (rb.velocity.x > 0)
    {
        RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, rayMaxDistance);

        if (hit.collider != null)
        {
            if (hit.collider.gameObject.tag != "Player")
            {
                // Moving in the opposite direction
                rb.velocity = Vector2.zero;
                rb.AddForce(-movementVector, ForceMode2D.Impulse);
            }
        }
        //Debug.DrawRay(ray.origin, ray.direction, Color.red);
        
    }
    // This way ray will be casted in the direction the enemy goes.
    else if (rb.velocity.x < 0)
    {
        ray.direction = Vector3.left;
        RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, rayMaxDistance);

        if (hit.collider != null)
        {
            if (hit.collider.gameObject.tag != "Player")
            {
                // Moving in the opposite direction
                rb.velocity = Vector2.zero;
                rb.AddForce(movementVector, ForceMode2D.Impulse);
            }
        }
        //Debug.DrawRay(ray.origin, ray.direction, Color.red);

It worked as intended, but when I tried to use it on Mario, it didn't work somehow.

The part in character script. (It's not completed because it doesn't even work now)

private void ActivateLuckyBlock()
{
    float maxRayDistance = GetComponent<BoxCollider2D>().bounds.size.y/2;
    Ray2D ray = new Ray2D(transform.position, Vector2.up);

    RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxRayDistance);

    if (hit.collider != null)
    {
        Debug.Log("There is something");  
    }
}
  • This code outputs "There is something" even if there is nothing above the player. So it never returns null, that should mean it hits something every time right?
  • I thought that maybe it was somehow colliding with the player's collider, but it doesn't happen with the enemy even though they are the same.
  • I've tested multiple distances including infinite.
  • Also checked if there was anything in the scene that I didn't see in the first place, but couldn't find it.
  • I've tried calling the method on both Update and FixedUpdate; neither of them worked as intended.
  • Ray origin and direction also works while testing with Debug.DrawRay().

I've been looking through the internet for any kind of answer, but couldn't find anything about it. I don't know what I'm doing wrong. It's not even a full implementation, just wanted to test. Still, it doesn't work. Please help me before I go insane.


Solution

  • The ray origin should be the centre of the bounds and try to add a little extra space for maxRayDistance, (bounds.extents is equal to bounds.size/2:documentation for bounds.extent)

    float maxRayDistance = GetComponent<BoxCollider2D>().bounds.extents.y + 0.001f;
    Ray2D ray = new Ray2D(GetComponent<BoxCollider2D>().bounds.center, Vector2.up);
    

    Try changing the Debug.Log, this will allow you to know what the name of the object the ray cast is hitting:

    Debug.Log("Raycast hit:" + hit.collider.name);
    

    If you're still having issues, make a public layerMask variable, create and add a layer for the object you want to ray cast at:

    RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxRayDistance, layerMask);
    

    Call the function through the Update or Fixed Update:

    It should look something like this:

    public LayerMask luckyBlockMask;
        void Update()
        {
            ActivateLuckyBlock();
        }
        private void ActivateLuckyBlock()
        {
            float maxRayDistance = GetComponent<BoxCollider2D>().bounds.extents.y + 0.1f;
            Ray2D ray = new Ray2D(GetComponent<BoxCollider2D>().bounds.center, Vector2.up);
    
            RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxRayDistance,
            luckyBlockMask);
    
            if (hit.collider != null)
            {
                Debug.Log("Raycast hit:" + hit.collider.name);
            }
        }