Check for "OnTrigger" constantly?

So I got a script, where it checks if the player is inside a trigger. If he is, then if he presses E, a door opens or closes (based on whether it’s already open or not) and plays a sound.

The thing is, I want the player to be able to spam E and open/close the door each time.

But I think the way it works normally is:
OnTriggerEnter checks once when the player enters the trigger.
OnTriggerStay checks once or a few times after the initial check would’ve (or did) happened.
OnTriggerExit checks once when the player leaves the trigger.

Is there any way to combine Update and either OnTriggerEnter or OnTriggerStay, so that once the player enters the trigger, it loops through that check until the player leaves the trigger?

I’m thinking of calling “OnTriggerStay” from OnTriggerEnter" and calling “OnTriggerEtner” from OnTriggerStay. So that even after those checks are made, they will continue to happen since they both call each other. But I’m not sure if that will work.

2 Likes

OnTriggerStay should fire once per frame for every colliders that are touching the trigger. Perhaps your trigger is attached to the door and the trigger moves away from the collider when you open it?

1 Like

Unfortunately that’s not the case. Even before I wrote the script for the door, I had gizmos turned on in Play Mode, and the trigger never moves.

When I spam E while entering the trigger, I am able to affect the door 5 times, and then it stops responding to the input.

1 Like

If you Debug.Log OnTriggerStay, does it keep firing?
Is OnTriggerExit called when you’re still in the trigger zone?
Are you doing anything with the player’s rigidbody while he’s in the trigger zone?
Edit: Can you post the door code also please

1 Like

It does fire every frame, but stops at around 30, when I stop moving.
I’m not using OnTriggerExit at all for this.
The movement script I have, uses the rigidbody’s velocity to move the player. When I keep moving inside the trigger, it keeps firing, but if I stand still, it stops after around 30 logs (as stated above).

Here’s the script:

public class Door : MonoBehaviour {

    bool doorIsOpen;
    public SpriteRenderer thisRenderer;
    public Sprite doorClosed;
    public Sprite doorOpen;

    public BoxCollider2D doorCollider;

    public AudioSource thisSource;

    void OnTriggerStay2D () {

        //If the door uses the doorClosed sprite.
        if (thisRenderer.sprite == doorClosed) {
                doorIsOpen = false;

            //If player presses E, and door is closed.
            if (Input.GetKeyDown (KeyCode.E) && doorIsOpen == false) {

                //Change door sprite to doorOpen.
                thisRenderer.sprite = doorOpen;
                    doorIsOpen = true;
                doorCollider.enabled = false;
                thisSource.Play();
            }
        }

        else {
            doorIsOpen = true;

            //If player presses E, and door is open.
            if (Input.GetKeyDown (KeyCode.E) && doorIsOpen == true) {
       
                //Change door sprite to doorClosed.
                thisRenderer.sprite = doorClosed;
                doorIsOpen = false;
                doorCollider.enabled = true;
                thisSource.Play();
            }
        }
    }
}

(If anyone wants to use this for any purposes (even commercial), feel free. Just don’t licence it.)

The BoxCollider2D in this script is the collider for the actual door (not the trigger), which stops the player from going through it.

And just fyi, the trigger is also on the door object, it’s not a child or anything.

1 Like

Solved it, just had to set my player’s rigidbody to “Never Sleep”.

9 Likes

Yes, you can

  • take a boolean flag
  • set this flag to ‘true’ when you enter a trigger/collision
  • process logic in Update as long as the flag is set to true
  • set this flag to false when you exit the trigger/collision

That’ll be an endless cycle and freeze your app if you just do it as it’s written there.
Also, I’d generally avoid calling Unity’s callback manually. I cannot think of any bugs that may occur, but it looks unprofessional. Just use your own methods for that.

Even though you’ve already solved the issue, here are a few other things:

Never query Input in the physics-cycle (FixedUpdate, OnTriggerXYZ, OnCollisionXYZ …), it’ll introduce bugs for sure.
Instead, use a pattern that remembers Input in Update and consumes it later in the physics-method.

Also, the boolean checks of doorIsOpen are not needed, they’re redundant.

If you’re curious, the code could as well be written as:

private void OnTriggerStay2D(Collider2D collider)
{
    // querying the input should be done in Update (!)
    if (Input.GetKeyDown(KeyCode.E))
    {
        doorCollider.enabled = doorIsOpen;
        doorIsOpen = !doorIsOpen;
        thisRenderer.sprite = doorIsOpen ? _doorOpenedImage : _doorClosedImage;
        thisSource.Play();
    }
}
2 Likes

how do i do this if i’m not using rigidbody?

If it’s not a rigidbody, it will never sleep

In order for trigger events to be sent at all, at least one of the objects (either the trigger or the collider or both) needs to have a Rigidbody attached to it. If you don’t want physics associated with the Rigidbody but you still want trigger events, set the Rigidbody to be Kinematic instead of Dynamic.

Check out the handy chart at the end of this page: https://docs.unity3d.com/Manual/CollidersOverview.html

I was getting strange behavior until I saw this thread and correlated that my tilemap composite colliders (set to Trigger) were using outline rather than polygon. I thought rigidbody sleep was the issue but it turns out it was not.

1 Like