Is there a way to deny an exit (and therefore OnTriggerExit)

I would like to be able to tell when one object is trying to exit the collider of another and possibly block the motion that would cause the exit.

I have a system in which objects are sometimes able to be physically interacted with (stood on, bumped into, etc.) and sometimes not (when not, they can still be interacted with via other code, but not by physics), so the isTrigger property of some objects changes dynamically. My problem is actually that colliders sometimes do a isTrigger = false while a rigidbody is inside them which causes bugs. Generally, what causes other nearby objects to change state is entering/exiting a separate object.

So basically, entering object 1 causes objects 2 through N to change, like so…

void OnTriggerEnter2D(Collider2D other)
{
    foreach(GameObject o in specialInteractionItems)
        o.GetComponent<BoxCollider2D>().isTrigger = true;
}

void OnTriggerExit2D(Collider2D other)
{
    foreach(GameObject o in specialInteractionItems)
        o.GetComponent<BoxCollider2D>().isTrigger = false;
}

Some of these “special interaction items” are inside the collider of this, some of them are outside, and some of them overlap (part in, part out). If OnTriggerExit2D() is called while the player is currently overlapping (or even entirely within) a specialInteractionItem when that item gets isTrigger = true, that is the problem, as I then have my player (with its rigidbody) inside some other object which it normally cannot move into - the physics would normally have been disallowing this if not for the special interaction state.

It would be wonderful if Unity had some kind of bool OnAttemptedEnter() and bool OnAttemptedExit() which would disallow the translation if false is returned. If this exists, I want to disallow the above-mentioned exit, forcing the player to remain in a state where it is colliding with the other object. I have used other development environments which have this, and it is very useful. Does Unity have anything like this?

If Unity does not have this built in, I think I need to set up such a thing myself, but I would not know where to start doing this in Unity. Google was not much help, as it found plenty of results which had nothing to do with this.

Does anyone know how to do this, or does anyone have any recommendations or other ideas?

Unfortunately, there are no such functions as you describe. Controlling entering an object is best done with collisions (achievable by toggling layer collisions on and off, disabling individual colliders, marking individual colliders as triggers, etc.), and controlling exiting an object is tricky.

To “deny exiting”, there could be an EdgeCollider2D that starts disabled and is edited to have the same perimeter as the trigger; it could then be enabled when the player needs to be contained in the trigger.

What I ended up doing was to keep track of the object’s previous x/y every frame and move the object back if necessary.

I gave the mobile object which is to be disallowed from exiting a list of objects that it is currently overlapping. In its OnTriggerEnter/Stay/Exit I add/remove other. Let’s call this list collisions.

The special object, the one which the mode ends when you exit it: let’s call it Special.

In Special, I gave it a list of what the player will not normally be allowed to move through. This list needs to be populated with the objects that would normally block movement but which are currently not blocking movement due to the special mode. Let’s call this list passThrough.

In Special’s OnTriggerEnter I set player = other.gameObject; and a boolean exit = false; and for each object in passThrough I set it’s isTrigger = true.

In Special’s OnTriggerStay I have _x = other.gameObject.transform.position.x; _y = other.gameObject.transform.position.y;

In Special’s OnTriggerExit I do exit = true and a foreach(GameObject o in collisions) and set a boolean block to true if I want to block the exit. Then, if(!block) I loop through passThrough again and put each object back to normal and set player = null.

In Special’s FixedUpdate, I check if exit and player are set, and if both are then I just set player’s RigidBody’s location to the previous x,y that was updated in OnTriggerStay.

This does cause the game to constantly call Enter/Exit over and over again as it keeps the object in, but the player does not know that and it works well for my case.

Sorry for the sporadic code-bits instead of doing larger blocks of code. I have a bunch of related logic in mine which would have been extra baggage, so I didn’t copy/paste. I might edit the answer to fix that if I have time after work; gotta run. Enjoy!