- Home /
OnTriggerEnter being called multiple times in succession?
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[i] == currentSpawn)
i = Random.Range(0,allSpawns.Length);
transform.position = allSpawns[i].transform.position;
currentSpawn = allSpawns[i];
}
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?
Do you have multiple colliders on your player object? If so, OnTriggerEnter might get called for each collider separately?
Answer by fafase · Jul 02, 2014 at 12:36 AM
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;
}
$$anonymous$$y 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!
I get this problem with a 2D box trigger collider colliding with another 2D box collider.
squares also can have 2 contacts points, just use the same process.
O$$anonymous$$G thank you!! thought I was going crazy, capsule collider was the issue for me.
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.
Answer by shawnsi · Mar 28, 2019 at 03:18 PM
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.
Answer by DRsabadash · Mar 17, 2017 at 08:01 AM
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)
Answer by sisse008 · Mar 25, 2018 at 10:52 AM
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();
}
}
Why should it be on the object not the player?
Answer by MrSpiky · Feb 14, 2020 at 10:34 AM
Having multiple colliders on your object can cause this to happen aswell Ik old topic...