Unity physics API: When do colliders actually update their position?

Hello,

I’m having an interesting problem here and hoping someone has the expertise to help me out. I’m building a custom character controller for Unity, doing all of the physics collisions myself, detecting when objects collide by using the Physics.OverlapSphere method (using 3 or more of them to simulate a capsule shape) in the Update() call. This has worked well for colliding with static objects, but I’m starting to run into trouble now that I’m trying to implement moving objects (mostly moving platforms). Basically, you have two steps, both run in Update() methods of separate MonoBehaviors. A moving object has it’s transform.position updated, and the player character runs OverlapSphere to detect collisions. Let’s assume that the moving object is updated first (since this is desirable behavior and is easy to accomplish in theory by having a controller order all your objects Update calls).

The moving object is translated X units. We’ll also assume that before being translated, it is NOT colliding with the player, and after being translated, it IS. Now the player will run his OverlapSphere call, and in theory detect the moving object and run collision resolution and everything will be working correctly. The problem is this doesn’t actually work, since it seems that in Unity, a collider’s position isn’t actually updated until the physics are updated (?). OverlapSphere is kind of an odd function in that it lets you detect collisions outside of the main physics loop, so I’m not sure how it actually works. Either way, I wrote a quick script to test this:

using UnityEngine;
using System.Collections;

public class CollisionTest : MonoBehaviour {

    public float Radius = 2.0f;
    public Transform target;

    void Start () {
   
    }

    Vector3 cache;

    void Update () {

        cache = target.position;

        MoveTo();

        DetectCollision();

        target.position = cache;
    }

    void MoveTo()
    {
        Vector3 direction = transform.position - target.position;
        target.position += direction;
    }

    void DetectCollision()
    {
        Collider[] cols = Physics.OverlapSphere(transform.position, Radius);

        foreach (var col in cols)
        {
            Debug.Log(col.name);
        }
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, Radius);
    }
}

Target should be any object with a collider that is not touching the OverlapSphere before running. The target is moved on top of the sphere, collisions are run, and then it’s reset. Unfortunately no collisions are ever detected. Weirdly enough if you run it in Start it does detect collisions.

Is there any way to force the collider positions to update in the Update() call, before the physics timestep? Or any other solution to this problem?

Thanks,
Erik

Collision detection should not be done in Update, only in FixedUpdate, which is when the physics engine is updated. Update is when the screen is redrawn and doesn’t have anything to do with physics.

–Eric

The problem is that I want to manually do collision detection, but it doesn’t seem Unity has any Update calls that allow for that. If you change my code to work in FixedUpdate with rigidbodies, it still doesn’t work:

using UnityEngine;
using System.Collections;

public class CollisionTest : MonoBehaviour {

    public float Radius = 2.0f;
    public Transform target;

    void Start () {
        //Vector3 cache = target.position;

        //MoveTo();

        //target.position = cache;
    }

    Vector3 cache;

    void FixedUpdate () {

        cache = target.rigidbody.position;

        MoveTo();

        DetectCollision();

        target.rigidbody.position = cache;
    }

    void MoveTo()
    {
        Vector3 direction = transform.position - target.rigidbody.position;
        target.rigidbody.MovePosition(target.rigidbody.position + direction);
    }

    void DetectCollision()
    {
        Collider[] cols = Physics.OverlapSphere(transform.position, Radius);

        foreach (var col in cols)
        {
            Debug.Log(col.name);
        }
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, Radius);
    }
}

Because I’m assuming Unity doesn’t actually update the physics until the Internal Physics Update section of the diagram in the page I linked. I suppose what I want to do is update the position of an object, have Unity update all the object positions, and then run OverlapSphere. It seems the only way to do this would be to put all the moving object code in the FixedUpdate and ensure that the physics timestep is greater than or equal to the framerate (so that they’re in sync, since modifying object positions directly in FixedUpdate can lead to stuttering). This way, the internal physics are run in between Fixed and regular Updates.