Hi all,
I am trying to build a system where I can have a container object like a box that has its outside “shielded” with box colliders and in the inside, there is a trigger that detects objects that are thrown into the box. A script registers these objects in a List, waits until they don’t move anymore in Update() and makes them static and a parent of the box, so they can be carried around in the box.
The problem is when I throw the closed box onto another object, that object gets “collected” by the trigger and in now glued half inside half outside of the box. My only explanation is, that the object penetrates the outer colliders, enters the trigger, OnEnterTrigger gets called and after that the physics engine would normally “correct” the position of the object so that it stays outside of the colliders. But since the trigger makes the object kinematic, the physics engine won’t move it out.
So I was thinking to wait for a frame to give physics a chance to correct the penetration and then - if necessary - add the object to the List. The code below works but my trouble of understanding is, how long I should correctly wait for physics? Right now waiting 1 second is a huge safety margin, I tried WaitForFixedUpdate and WaitForEndOfFrame but those don’t work. So can someone enlighten me, how the timing of physics and OnTriggerEnter() play together? I know this image of execution order and that OnTriggerEnter relies on data from the start of FixedUpdate() but it is all a bit hazy for me.
Thanks a lot!
public class ItemCatcher : MonoBehaviour {
public List<GameObject> waitingList; //for objects where it is unclear if they are put in the box by "mistake" e.g. collision overlap etc.
public List<GameObject> itemsInContainer; //objects that are clearly put into the box and should be monitored until they can be made kinematic
void OnTriggerEnter(Collider other)
{
if (other.gameObject)
{
StartCoroutine(PutInContainer(other.gameObject));
}
}
//this is for delaying so physics has a chance to pull out penetrating objects
IEnumerator PutInContainer(GameObject relevantGameObject)
{
waitingList.Add(relevantGameObject);
yield return new WaitForSeconds(1f);
//if after waiting the object is still not pulled out of the trigger...
if (waitingList.Contains(relevantGameObject)) itemsInContainer.Add(relevantGameObject);
}
//if object gets pulled out of trigger then remove it from the waiting list
private void OnTriggerExit(Collider other)
{
if (other.gameObject)
{
waitingList.Remove(other.GameObject);
}
}
void Update()
{
for (int i=itemsInContainer.Count-1; i>=0; i--)
{
if (itemsInContainer[i].GetComponent<Rigidbody>().velocity.magnitude < 0.01f)
{
itemsInContainer[i].transform.parent = this.transform;
itemsInContainer[i].GetComponent<Rigidbody>().isKinematic = true;
foreach (Collider col in itemsInContainer[i].GetComponentsInChildren<Collider>())
{
col.isTrigger = true;
}
itemsInContainer.RemoveAt(i);
}
}
}