OnTriggerEnter is called too late (after Start)

I am creating a simple room-based level generator. On adding a room to the level, I check if the new room is touching any colliders (new room has trigger collider and kinematic-rigidbody, old rooms just have normal colliders).

The problem is that immediately after adding a room, when I check whether the room is overlapping another room, the new room’s OnTriggerEnter has not yet been called so it always returns as not triggered. How do I set up my code so that OnTriggerEnter has a chance to test the new room before I check whether OnTriggerEnter has been called?

Trigger code (on the new Room)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Room : MonoBehaviour {

    [HideInInspector] public bool isColliding = false;

    private void OnCollisionEnter(Collision collision) {
        //Debug.Log("Colliding");
        isColliding = true;
    }
    private void OnCollisionExit(Collision collision) {
        //Debug.Log("Not Colliding");
        isColliding = false;
    }


    private void OnTriggerEnter(Collider collision) {
        Debug.Log("Triggered");
        isColliding = true;
    }
    private void OnTriggerExit(Collider collision) {
        Debug.Log("Not triggered");
        isColliding = false;
    }

    // Use this for initialization
    void Start () {
        Debug.Log("ontrigger is: " + isColliding);
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

Check code (see line 39, it always logs “False”, even when it should be true. After it logs false, OnTriggerEnter is called and logs “Triggered”)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class levelGen : MonoBehaviour {

    public Room[] rooms;
    public int roomCount = 10;
    int currentRoomCount = 0;

    // Add a Room
    void AddRoom() {
        bool success = false;

        Room newRoom;
        GameObject newRoomObject;
        Door[] endDoors;
        Door endDoor;
        Door[] newDoors;
        Door newDoor;

        endDoors = ShuffleDoors(GetComponentsInChildren<Door>());

        while (!success) {
            newRoomObject = Instantiate(rooms[Random.Range(0, rooms.Length)].gameObject,new Vector3(100,100,100),transform.rotation) as GameObject;
            newRoom = newRoomObject.GetComponent<Room>();
            newDoors = ShuffleDoors(newRoom.GetComponentsInChildren<Door>());
            
            for (int i = 0; i < endDoors.Length && !success; i++) {
                endDoor = endDoors*;*

if (!endDoor.isConnected) {
for (int ii = 0; ii < newDoors.Length && !success; ii++) {
newDoor = newDoors[ii];
// place room at endDoor
newRoom.transform.SetPositionAndRotation(endDoor.transform.position - newDoor.transform.localPosition, endDoor.transform.rotation);
// rotate room to fit on endDoor
newRoom.transform.RotateAround(endDoor.transform.position, Vector3.up, 180 -Quaternion.Angle(Quaternion.Euler(Vector3.zero), newDoor.transform.localRotation));
// try to rotate in case the door is backkwards
Debug.Log(newRoom.isColliding);
if (newRoom.isColliding) {
Debug.Log(“Tried it the other way around (rotate 180d)”);
newRoom.transform.RotateAround(endDoor.transform.position, Vector3.up, 180);
}

if (!newRoom.isColliding) {
success = true;
currentRoomCount += 1;

//newRoomObject.transform.parent = gameObject.transform;
//newRoomObject.GetComponent().isTrigger = false;
//Destroy(newRoom.gameObject.GetComponent());
// ?
//endDoor.deadEnd = false;
//endDoor.isConnected = true;
//newDoor.deadEnd = false;
}

}
}
}
}
}

// Use this for initialization
void Start () {
for (int i = 0; i < roomCount; i++) {
AddRoom();
}
}

  • // Update is called once per frame*

  • void Update () {*

  • }*

//stuff
Door[] ShuffleDoors(Door[] arr) {
for (int i = 0; i < arr.Length; i++) {
int rnd = Random.Range(0, arr.Length);
Door tempGO = arr[rnd];
arr[rnd] = arr*;*
arr = tempGO;
}
return arr;
}
Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles) {
return Quaternion.Euler(angles) * (point - pivot) + pivot;
}
}

Set up AddRoom as a coroutine as you have done, but use WaitUntil instead of waitforfixedupdate. Additionally add a public variable bool HasEnteredTrigger in Room, and this is what the WaitUntil should check before proceeding.

e.g.

 public class Room : MonoBehaviour {
 
     [HideInInspector] public bool isColliding = false;
     [HideInInspector] public bool HasEnteredTrigger;
 

    // other code
 
     private void OnTriggerEnter(Collider collision) {
         Debug.Log("Triggered");
         isColliding = true;
         HasEnteredTrigger = true;  //levelGen should check this. before proceeding with checking isColliding
     }
     private void OnTriggerExit(Collider collision) {
         Debug.Log("Not triggered");
         isColliding = false;

        HasEnteredTrigger = false; //reset here, or wherever else you think is more appropriate
     }
 

 }

     Ienumerator AddRoom() {

     //existing code
 
         while (!success) {
             newRoomObject = Instantiate(rooms[Random.Range(0, rooms.Length)].gameObject,new Vector3(100,100,100),transform.rotation) as GameObject;
             newRoom = newRoomObject.GetComponent<Room>();
             newDoors = ShuffleDoors(newRoom.GetComponentsInChildren<Door>());
             
             for (int i = 0; i < endDoors.Length && !success; i++) {
                 endDoor = endDoors*;*

if (!endDoor.isConnected) {
for (int ii = 0; ii < newDoors.Length && !success; ii++) {
newDoor = newDoors[ii];
// place room at endDoor
newRoom.transform.SetPositionAndRotation(endDoor.transform.position - newDoor.transform.localPosition, endDoor.transform.rotation);
// rotate room to fit on endDoor
newRoom.transform.RotateAround(endDoor.transform.position, Vector3.up, 180 -Quaternion.Angle(Quaternion.Euler(Vector3.zero), newDoor.transform.localRotation));

yield return new WaitUntil(() => newRoom.HasEneteredTrigger);

// try to rotate in case the door is backkwards
Debug.Log(newRoom.isColliding);
if (newRoom.isColliding) {
Debug.Log(“Tried it the other way around (rotate 180d)”);
newRoom.transform.RotateAround(endDoor.transform.position, Vector3.up, 180);

// existing code
}

}
}
}
}
}

The alternate solution is to avoid using Unity’s physics entirely, and just test whether the bounding boxes of each room overlap with bounds.Intersects(). This is much faster and works (so far as I’ve tested, so long as you’re using box colliders).

// bounds check
bool checkForOverlap(Collider[] newBoxes, Collider[] boxes) {
    foreach (Collider newBox in newBoxes) {
        foreach (Collider box in boxes) {
            Debug.Log(box.transform.name);
            if (newBox.bounds.Intersects(box.bounds)) {
                return true;
            }
        }
    }
    return false;
}
// Function call looks like
if (!checkForOverlap(newRoom.GetComponents<Collider>(), transform.GetComponentsInChildren<Collider>())) {
    success = true;
}