IsTouching() not working

I am trying to see if two GameObjects with a Box Collider 2D is touching/overlapping. Since I only need to worry about this when the user click, I decided that using OnCollisionEnters2D or other function based checking is not necessary, Hence I am trying to use IsTouching or IsTouchingLayers.

I version of the code I tried with IsTouching is:

var towers = GameObject.FindGameObjectsWithTag("Tower");
for (var tower : GameObject in towers) {
    if (GetComponent(Collider2D).IsTouching(tower.GetComponent(Collider2D))) {
        Debug.Log("Touch");
    }
}

And I tried with IsTouchingLayers:

var layer : LayerMask = LayerMask.GetMask("Towers");
if (GetComponent(Collider2D).IsTouchingLayers(layer)) {
    Debug.Log("Touch");
}

The objects I am trying to see if touching is tagged with “Tower” and in the layer “Towers”. However, both code never returned true even though they are clearly overlapping. I also tried switching “Is Trigger” on and off both the objects with no luck…

there are caveats on the API pages for those about how/when the value is updated being based off the “last physics step”… so I’m guessing timing might be involved or is there time between the last position update and the click?

I am not sure about the timing of the physics step, but none of the objects were moving. So unless physics isn’t running at all… or take over like 10 seconds to update? I don’t really think timing could be an issue.
Tower objects never moves, cause you know, they are towers, and the object this script is running on is linked to the mouse position.

default is 50 times a second…

Is there a rigidbody attached to something? (think that’s still a requirement in 2d, certainly is with 3d)

1 Like

Thanks, that was the problem, I needed a rigidbody attached, seem weird to require a rigidbody for something like this.

2 Likes

the physics engine deals with interaction within rigidbodies and between rigidbodies and colliders; no rigidbody involved, the physic engine doesn’t know anything happened.

My problem is that IsTouching returns false even when touching my object.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class appleSpawn : MonoBehaviour {

    public int appleID;
    public int colID;

    public System.Random generator = new System.Random();

    public GameObject redApple;
    public GameObject goldApple;
    public GameObject poisonApple;

    public GameObject redAppleInGame;
    public GameObject goldAppleInGame;
    public GameObject poisonAppleInGame;

    public GameObject playerSprite;

    public Collider2D playerCollision;
    public Collider2D redAppleCollision;
    public Collider2D goldenAppleCollision;
    public Collider2D poisonousAppleCollision;


    public int spawnLeastWait = 3;
    public int spawnMostWait = 8;

    public Vector3 spawnPOS;

    void Start()
    {
        StartCoroutine(Spawner());
    }

    void Update()
    {
        if (appleID == 0)
        {
            redAppleInGame.transform.Translate(0, -10, 0);
            if (redAppleInGame.transform.position.y < -9409)
            {
                Destroy(redAppleInGame);
            }
            else if (redAppleCollision.IsTouching(playerCollision))
            {
                Player.Player.RedApple(Player.Player.points, Player.Player.speed);
                Debug.Log("Touching");
                Destroy(redAppleInGame);
            }
        }

        if (appleID == 1)
        {
            goldAppleInGame.transform.Translate(0, -10, 0);
            if (goldAppleInGame.transform.position.y < -9409)
            {
                Destroy(goldAppleInGame);
            }
            else if (goldenAppleCollision.IsTouching(playerCollision))
            {
                Player.Player.GoldenApple(Player.Player.points, Player.Player.speed, Player.Player.health);
                Debug.Log("Touching");
                Destroy(goldAppleInGame);
            }
        }

        if (appleID == 2)
        {
            poisonAppleInGame.transform.Translate(0, -10, 0);
            if (poisonAppleInGame.transform.position.y < -9409)
            {
                Destroy(poisonAppleInGame);
            }
            else if (poisonousAppleCollision.IsTouching(playerCollision))
            {
                Player.Player.PoisonApple(Player.Player.points, Player.Player.speed, Player.Player.health);
                Debug.Log("Touching");
                Destroy(poisonAppleInGame);
            }
        }
    }

    IEnumerator Spawner() {
        appleID = generator.Next(0, 2);
        colID = generator.Next(0, 2);

        if (colID == 0)
        {
            spawnPOS = new Vector3(playerMovement.col1.x, 0, 2);
        }

        else if (colID == 1)
        {
            spawnPOS = new Vector3(playerMovement.col2.x, 0, 2);
        }

        else if (colID == 2)
        {
            spawnPOS = new Vector3(playerMovement.col3.x, 0, 2);
        }

        yield return new WaitForSeconds(2);

        if (appleID == 0)
        {
            redAppleInGame = Instantiate(redApple, spawnPOS, Quaternion.identity);
        }

        if (appleID == 1)
        {
            goldAppleInGame = Instantiate(goldApple, spawnPOS, Quaternion.identity);
        }

        if (appleID == 2)
        {
            poisonAppleInGame = Instantiate(poisonApple, spawnPOS, Quaternion.identity);
           
        }

    }
}

To make IsTouching() works you need to

  1. attach Rigidbody2D to the collider that goes in to the function
  2. check Is Trigger of that collider to true
3 Likes

Note that there is no requirement for it being attached to a Rigidbody2D nor does it need to be a trigger.

Please note the age of posts. This was posted nearly 6 years ago with the last reply being several years ago.

See Necro Posting in our Community Code of Conduct .

Sorry for “necroing” this again, but this thread is the third google result. There should be a proper answer, even if several years have passed.

Please tell me what I have to do to make IsTouching() working without attaching a RigidBody2D.

If you read the docs it clearly says: (emphasis is mine)

It is important to understand that checking whether colliders are touching or not is performed against the last physics system update; that is the state of touching colliders at that time. If you have just added a new Collider2D or have moved a Collider2D but a physics update has not yet taken place then the colliders will not be shown as touching. This function returns the same collision results as the physics collision or trigger callbacks.

This is important because as @MelvMay notes above, the RB2D does NOT have to be on the thing asking the question, just like in all collisions / collision callbacks.

But you MUST have an RB2D somewhere in the contacting colliders because … in Unity, 100% of ALL collisions and triggers are actually performed by the RB2D, not by something else.

As you can see, it is NOT performed by calling the method. The method is returning what has already been performed last physics update. If no collisions happened (for any reason, including no RB2D being involved), then no touching happened.

So, to answer the question now nine years later:

  • you need two (2) separate 2D colliders to ask the question .IsTouching()
  • at least one of them must have a Rigidbody2D set up to produce collisions
  • a physics update must have happened.

That’s it. It really works.

2 Likes

Hi @Kurt-Dekker
Thank you for answering so clearly and with in-depth information here and in many other threads!

All you write totally makes sense. I was expecting something like this after reading the documentation. But I was not aware that not everything needs a rigid body.

In my case, I don’t need phyiscs at all. I just need to check some collisions (and I don’t need to check collisions for every comnination of colliders). Is there a built-in way to execute the intersection-checks at the time I need them for the things I want to check, rather than running a phyics simulation in the background?

Using a Rigidbody2D, Collider2D, Contacts, Queries is using Physics. Physics isn’t simply a collision response.

Not adding a Rigidbody2D means a Collider2D is implicitly Static (non-moving) and is implicitly added to the static ground-body that lives at (0,0) with (0) rotation. This is simply a convenience. Colliders or more specifically the shapes they create are always attached to an underlying body. This doesn’t mean you don’t add a Rigidbody2D if you don’t want a collision response, that’s not correct at all, it means you don’t do that if you don’t intend for it to move.

A Rigidbody2D has a body-type which can be set to Static, Kinematic or Dynamic.

Static do not ever come into contact with other Static as that wouldn’t make sense, ever. They don’t move, they’re static. Two Static Collider2D overlapping do not produce contacts irrelevant of whether they’re implicitly Static (no Rigidbody2D) or whether you add a Rigidbody2D and set the body-type to Static.

If you want to move them then they should be Kinematic or Dynamic. If you also don’t want a collision response then you’d use Kinematic. It’s not a simple case of Rigidbody2D or no Rigidbody2D.

If you’re modifying the Transform thinking you’re “moving” a Collider2D then you’re mistaken. This causes, when the simulation runs, the colliders in question to be recreated from scratch which is extremely wasteful and totally unne0cessary. Only a Rigidbody2D (body) can be moved with Colliders and their shapes attached to them. The reason they are recreated is because you’ll be changing the Transform which means their position relative to the body they are attached to (the ground body) has changed so their geometry (shapes) needs recalculating. You should never do this. Move a body, not a collider.

So in short, if you don’t want a collision response, you use a Kinematic Rigidbody2D and drive the Rigidbody2D using its velocity, MovePosition etc. If you want Kinematic to contact other Static/Kinematic so you can check the contacts or indirectly by using “IsTouching” that queries the existing contacts then simply check the useFullKinematicContacts on the Rigidbody2D in the inspector.

1 Like

Look at the docs, there’s a whole host of queries allowing you to perform overlap and cast checks for rays/colliders on a specific collider or all of them on a Rigidbody2D.

To show a few: