OnTriggerEnter being called multiple times in succession?
Asked Answered
D

6

0

Hey all,

Basically, I have a box that the player has to be able to collect. When the player “collects” it, the box will actually just instantly move to another spawnpoint, and I’ll also execute scoring stuff. When the player object passes over a box, OnTriggerEnter(Collider hitObject) is called, and I do a check to make sure that the object I hit is actually a box that can be collected. If it is, I move the box to a different location to give the effect

The problem is that when my player object hits the box, OnTriggerEnter is called two or three times, which will undoubtedly cause issues for keeping track of the score. It’s my understanding that OnTriggerEnter is called once upon the initial collision with the object, so I’m not sure why it’s being called multiple times per collision.

Some of my code follows:

//From the player object's script

void OnTriggerEnter (Collider hitObject)
	{	
		if (hitObject.tag == "peep")
		{
			hitObject.transform.position = new Vector3(0,-100,0);
			Debug.Log("Collected");
			hitObject.transform.GetComponent<peepControl>().collect();
		}
	}

//From the peepControl script

public void collect()
	{
		int i = Random.Range(0,allSpawns.Length);
		while (allSpawns *== currentSpawn)*
  •  	i = Random.Range(0,allSpawns.Length);*
    

_ transform.position = allSpawns*.transform.position;_
_ currentSpawn = allSpawns;
}*
Through Debug.Log I found that the OnTriggerEnter function was testing true on its if statement three times before the object actually moved at all. Suggestions?_

Doehne answered 1/9, 2023 at 10:9 Comment(1)

Do you have multiple colliders on your player object? If so, OnTriggerEnter might get called for each collider separately?

Licentious
A
0

Is the collider on your player a Character Controller or a sphere collider or a capsule collider? Those being circular may have two (or more) contact points.

Just use a boolean to prevent multiple calls.

void OnTriggerEnter (Collider hitObject)
{
    if(isColliding) return;
    isColliding = true;
    // Rest of the code
}

void Update(){
    isColliding = false;
}

Even though your collider is not one of those I mentioned, this should work. If the boolean is true, quit the method, else set it to true and do the rest.

Since Physics is done all at once and before update in the same frame, if you have a second collision detected, nothing will happen since the first already set the boolean.

Update is just putting it back to false.

EDIT:
In order to remove the update, one can also do as such:

void OnTriggerEnter (Collider hitObject)
{
    if(isColliding) return;
    isColliding = true;
    // Rest of the code
    StartCoroutine(Reset());
}

IEnumerator Reset()
{
     yield return new WaitForEndOfFrame();
     isColliding = false;
}
Aircool answered 17/3 at 17:15 Comment(5)

My player object is just using a cube collider, but I get your idea and I was actually thinking of doing something similar. I just felt like maybe there was a function I didn't know about that could achieve the same effect more efficiently, so I might wait for a few other suggestions before marking this one as the answer. Thanks!

Doehne

I get this problem with a 2D box trigger collider colliding with another 2D box collider.

Alb

squares also can have 2 contacts points, just use the same process.

Aircool

OMG thank you!! thought I was going crazy, capsule collider was the issue for me.

Stimulate

I cant find this in the docs anywhere and it doesnt show up in the suggested codes in mono. Im thinking this is old....is there a newer version?? I cant seem to find one.

Spavined
J
0

For some reason, setting a boolean check for colliders can sometimes cause the boolean value to either flip, or to turn on/off the OnTriggerEnter/OnTriggerExit methods while remaining in the trigger area,
like opening a door and closing it repeatedly while in the trigger area, or flipping the boolean value so it closes when you approach and opens when you walk away.

using a simple variable iterator prevents the actual method from being called repeatedly, guaranteeing only one execution per collision.

//previous code in class
//using a door opening and closing as an example
[SerializeField] private GameObject device;
	private int i = 0;


	void OnTriggerEnter(Collider other){
		DoorScript door = device.GetComponent<DoorScript>();
		if (i == 0) {
			if (door != null) {
				door.Operate ();
				i++;
			}
		}

	}
	void OnTriggerExit(Collider other){
		DoorScript door = device.GetComponent<DoorScript>();
		if (i == 1) {
			if (door != null) {
				door.Operate ();
				i = 0;
			}
		}

	}
/* All DoorScript contains is a function Operate() and a boolean for if the door is open, and an if/else statement in Operate() for moving door to open if bool is false (set to closed) and moving door to closed if bool is true (set to open)
Jounce answered 24/7, 2023 at 18:17 Comment(0)
M
0

ontriggerenter should be on each “collectible” object. not on the player:

class Target
{
        private collected = false;
        void collect() {
          ....
          collected = true;
         }
       void OnTriggerEnter (Collider other)
       {   
           if (!collected && other.tag == "player")
           {
               transform.position = new Vector3(0,-100,0);
               Debug.Log(gameObject.name +" was Collected");
               collect();
         }
     }
Modification answered 6/6, 2023 at 2:18 Comment(1)

Why should it be on the object not the player?

Sosna
P
0

I know this is an old topic, but I wanted to share another solution just in case. I solved this issue by setting character Rigidbody’s IsKinematic to “true”. My guess is that when IsKinematic is false, the colliders would push the character back enough to trigger OnTriggerExist. This caused a trigger loop and caused it to run OnTriggerEnter and OnTriggerExit multiple times.

Plaza answered 22/7, 2023 at 22:44 Comment(3)

Your Solution works for me,thanks a lot !

Carnahan

This fixed my issue as well, thanks!

Bemused

Holy moly I spent so many hours on his and this was the issue. Marking isKinematic to true worked perfectly for me!

Mirthless
A
0

Having multiple colliders on your object can cause this to happen aswell
Ik old topic…

Autotomy answered 6/6, 2023 at 2:33 Comment(0)
Q
0

I know this is a super old thread but I ran into this problem today. I found a solution that was simple to implement and doesn’t add the overhead of a coroutine or adding code to update.

on the script attached to the item being picked up: (LootProperties.cs)

 public bool isPickedUp;

Then on the object with the OnTriggerEnter() (PlayerManager.cs)

 private void OnTriggerEnter(Collider other)
 {
            if (other.gameObject.CompareTag("LootItem"))
            {
                LootProperties lootProps = other.gameObject.GetComponent<LootProperties>();
    
                 if (!lootProps.isPickedUp)
                 {
                    lootProps.isPickedUp = true;
                    // Do stuff here
                  }
            }
 }
Quicksilver answered 11/11, 2022 at 16:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.