How to disable OnTriggerEnter() via script?


Júlio Rodrigues ·

You got your collision properly detected, but now you want to disable it, it's not necessary anymore. How could you achieve this? There are several ways in which this could be done, some are more appropriate than others depending upon your situation.

What kind of situations? It might be necessary to disable it only temporarily, or you might want to disable OnTriggerEnter()) on a whole set of objects. The following should cover most of the cases in which deactivating trigger detection is necessary.

Disabling it for a certain period of time only

If you need to disable the OnTriggerEnter() method for a set amount of time you'll need to control when it's coming back in mainly two ways:

1. Create a bool variable flag...

And do a check inside the OnTriggerEnter() method. If you're doing it this way, in reality, you're not disabling the OnTriggerEnter() method to be called, but in terms of mechanics implementation, it won't make any difference. There are differences in CPU and RAM use, though.

public class BoolFlagSample : MonoBehaviour {

    private bool collisionIsDisabled;

    private void OnTriggerEnter(Collider other) {
        if (triggerIsDisabled) return;
        // ...
    }

    // Update is called once per frame
    void Update () {
        // In a real game this probably won't need to be
        // part of the Update loop
        if (SomeGameLogicIsTrue()) {
            triggerIsDisabled = true;
        } else {
            triggerIsDisabled = false;
        }
    }

    private bool SomeGameLogicIsTrue() {
        // TODO: implement your game logic instead
        return true;
    }

}

2. Set the enable property of the collider to false

I'll spare you of the complete sample because it's really similar to the previous one, the two lines you'll need are:

GetComponent<Collider>().enabled = false;
GetComponent<Collider>().enabled = true;

Set it to true again whenever you see fit.

Someone would need to profile the difference in terms of performance for these two recommendations in a real game scenario to make a more definite.

Do NOT do this if your object doesn't contain a Rigidbody, as this would create a spike in CPU usage.

Knowing that you're trying to prevent OnTriggerEnter() to be called you're probably not doing this already, but it's always good to remember that static colliders (objects with colliders but no rigidbody) shouldn't be enabled/disabled, moved or scaled during gameplay since this would make the physics engine to recalculate its setup.

A more extreme way to do disable it

What you seek is not temporary disablement, you need to do it for good. To really disable it and also remove your object from the physics engine simulation you can destroy the rigidbody component.

Destroy(GetComponent<Rigidbody>());

You would need to add the Rigidbody component again if you need to re-enable it.

gameObject.AddComponent(typeof(Rigidbody));

Just be sure to not do it in the same frame you've destroyed the Rigidbody, otherwise, you'll get an error message like Can't add component 'Rigidbody' to Sphere because such a component is already added to the game object!

I haven't actually measured it but this is probably not a very good idea in terms of performance. To add and destroy the Rigidbody component repeatedly is likely to thrash the physics engine calculations set up.

Prevent OnTriggerEnter() to be called using the Layer Collision Matrix

If a whole category of objects in your game needs to ignore collisions you can change the layer collision matrix configuration. Before proceeding, keep in mind that this is not suited to ignore collisions that are already happening, that means that you might get your OnTriggerEnter() and OnTriggerExit() methods called again. Change these configurations on scene loads or in other more calm scenarios in your game.

This menu can be opened by going to Edit > Project Settings > Physics. Once you are in that menu you'll be able to select which layers should collide with which. In that specific case, we have disabled collisions between the monsters themselves and also the players with themselves. But players do collide with Crawling and Flying Monsters. All the other boxes are left the way the default Unity project is created by the editor.

Doing this using the editor is fine but how to do same in a script? This can be achieved using the Physics.IgnoreLayerCollision() and the Physics.IgnoreCollision() methods.

Physics.IgnoreLayerCollision() functions exactly like the options of the menu we just mentioned, let's see:

// Ignores collisions between objects of the layers 1 and 5
Physics.IgnoreLayerCollision(1, 5); // CONTAINS A MISTAKE

But using the layers' numbers directly is error prone, you should instead cache the index in some member variable to later use it in the final call

void Start() {
    crawlingMonstersLayerIndex = LayerMask.NameToLayer("Crawling Monsters")
    flyingMonstersLayerIndex = LayerMask.NameToLayer("Flying Monsters")
}

void someMethod() {
    Physics.IgnoreLayerCollision(crawlingMonstersLayerIndex, flyingMonstersLayerIndex);
}

To undo that you just need to pass a third parameter with a false value.

Physics.IgnoreLayerCollision(crawlingMonstersLayerIndex, flyingMonstersLayerIndex, false);

Now, if what you want is to disable the collision detection of only two specific objects, not whole layers, that can also be done

public class IgnoreCollisionSample : MonoBehaviour {

	private Collider collider;

	private void Start() {
		collider = GetComponent<Collider>();
	}

	private void OnTriggerEnter(Collider other) {
		Physics.IgnoreCollision(collider, other);
		print("just once");
	}

}

If you have a Kinematic Object, you can turn off Rigidbody.detectCollisions

I say that you should only do that on Kinematic objects since this property will also make the object to go through everything acting as if it has no collider. Unless, of course, you also want this behavior.

Turn off the detectCollisions property of the rigidbody component.

public class DisableTriggerSample : MonoBehaviour
{
    public Rigidbody rb;

    void Start()
    {
       rb = GetComponent<Rigidbody>();
    }

    void DisableTrigger()
    {
      rb.detectCollisions = false;
    }
}

Still a little confusing...

If anything that has been discussed here is confusing to you, please check out our practical troubleshooting guide on fixing collisions in unity, there's a big chance that we've covered your question in that guide.

Be sure to subscribe to our email list if you liked what you read here to get more like that in your inbox.

Detailed Unity Tutorials in your inbox

Subscribe if you want to receive articles and tutorials like this one right in your inbox. 
Classify in:
  • physics
  • trigger detection
  • unity
© Bladecast 2018. All rights reserved.