2D collision detection too slow

My player is supposed to make a bump sound as soon as it hits a wall. Instead it does it about a second after it hits the wall. I have two things in my scene checking if the player hits the wall, an OnCollisionEnter2D in the player controller script, and an OverlapCircle in a script attached to the player’s child object.
The OverlapCircle is bigger than the player’s CircleCollider, but the OnCollisionEnter2D almost always goes off before the OverlapCircle detects the wall (I’ve seen the OverlapCircle detect the wall first a single time).
The player’s animations don’t affect its collisions at all and neither does its nose.

Here is a gif of this happening: (wall1 = OverlapCircle, wall2 = player collision)
BQEB0T8Wjj

Player collider:

OverlapCircle on the player’s child object:

Hierarchy:

Code from the player controller:

>     private void OnCollisionEnter2D(Collision2D collision) {
>         if(collision.gameObject.CompareTag("Wall")) {
>             soundManager.PlayClip(soundManager.WallBump, transform, 1);
>             Debug.Log("wall2");
>         }
>     }

Code from the player’s child object:

>     void FixedUpdate() {
>         touchingWall = Physics2D.OverlapCircle(transform.position, 1.05f, layerMask);
>         if(touchingWall && !touchedWall) {
>             soundManager.PlayClip(soundManager.WallBump, transform, 1);
>             Debug.Log("wall1");
>             touchedWall = true;
>         }
>         if(!touchingWall) {
>             touchedWall = false;
>         }
>     }

The SoundManager parts don’t matter, if I remove them it’s still delayed. I’ve also tried using a raycast, a second CircleCollider and OnTriggerEnter2D on the child object, a giant BoxCollider on the player, changing the physics timestep to make FixedUpdate go faster, and changing the child object’s code to use Update instead of FixedUpdate.
The player and the wall both have Rigidbody 2Ds with their collision detection set to continuous, and the player’s child object did too when I tried using a collider on it.

The debug messages are delayed, the problem has nothing to do with the sound, the sound just happens to be what’s supposed to happen when the player hits the wall.

Make sure the sound itself isn’t delayed. You can check this by selecting it and viewing its waveform. If there’s a flat line at the start then you can take it into an editor like Audacity and remove it.

Also, I see a 1 as a parameter for PlayClip. Is that a delay?.

1 is the volume, but the problem is with the collision, I’ve tried removing all the sound stuff and the debug.log is still delayed.

Make sure your monitor isn’t in some TV or movie mode where the signal is delayed.

It’s not, but it’s not just the sound that’s out of sync, the debug messages are too.

Try to isolate the problem:

  1. Is the same thing happening with only 1 cannonball?
  2. What if you remove the FixedUpdate and keep only the OnCollisionEnter?
  3. What if you do the reverse?

With that being said, by looking at your video, to me it doesn’t seem like the Debug.log messages are delayed they seem to happen at the exact moment when a collision happens, only that the bouncing of the cannonball delays.

Here are some suggestions to check out:

  • How are you moving those cannonballs? Maybe there are some forces applied that don’t change the moment the collision happens but only after a while so the object seems stuck for a second.

  • Maybe there is a Vector change of the movement because of the collision and another vector change because of the forces resulting for the speed vector to keep pointing towards the wall and that keeps the ball stuck for sometime.

Generally I would say try to debug this not by looking at your collisions but looking at how the rigidbody’s velocity vector reacts.

1 Like

Are you sure? Watching the GIF the logs seem spot on every time the object hits the wall.

So that would only leave the sound delayed. And then I suspect you may be using a compressed format such as mp3 which may incur a delay upon play due to streaming/buffering. You may want to show us your audio clip settings.

The callback happens after the simulation runs after the collision response, there can be no “delay” because that would have to be explicitly implemented to do such a thing and that obviously isn’t the case; there is no queue. As per the title of your post, the collision response isn’t delayed, you’re saying a callback is delayed yet you seem to be saying the audio is delayed.

The simulation runs during the fixed-update after all the scripts are called. You performing a query there is how the simulation state is at that point. When the simulation runs, contacts are created/updated then everything is moved/solved then callbacks happen. Rinse, repeat.

You should know that Transform.position isn’t necessarily where a Rigidbody2D is if you’re using interpolation which is why you should always refer to the Rigidbody2D.position/rotation.

Also, you’re comparing a Physics2D.OverlapCircle with a radius of 1.05 at the Transform position to a CircleCollider2D with a radius of 0.9165132 (and potentially some Transform scaling) at the Rigidbody2D.position that is offset by (0.01831031, -0.01831031)! How are these two things the same?

If you want to use a collider in a query then use the dedicated Collider2D.Overlap or Collider2D.Cast rather than interpreting what you think the collider geometry and its position is.

Finally, it’s unclear if you’re performing actual physics-based movement of the Rigidbody2D here or if you’re stomping on the Transform.

1 Like

As I’ve said, the callbacks are not delayed and cannot be. Sure, I know it’s easy to just blame Unity if something is happening that you don’t understand but I wrote all this stuff inside Unity so you have to believe me, there cannot be a delay.

I already stated how/when things happen so you should read that and see how it affects your test including, as I said above, not using Transform.position as the authority on position, it isn’t the same as the Rigidbody2D.position if you’re using interpolation. If you’re not then they will be the same but it’s fragile to use it. You can simply output the Rigidbody2D.position and Transform.position to check if you want.

Feel free to create a simple reproduction and zip it up and I’ll be happy to take a look at it and tell you what is going wrong.

1 Like

idk how notifications work here and I accidentally replied to the wrong post so I’m reposting this

Looking at this footage the delay is a lot shorter than I said it was in the original post (still extremely noticeable when you attach a sound to the collision). The original gif also had a low framerate so it was harder to see the delay.

Video

Reproduction:

Just the assets folder (low file size):
Assets.rar (4.0 KB)

I definitely see the delay in the video. Could you please post the relevant collision detection & logging code in your post? Can’t be that much.

PS: if you want someone to look at your project, upload it to github or similar so we can browse the code online. Downloading an opening an archive is a lot to ask already, much less if you are providing it as a .rar archive that few have compatible programs for.

That’s just the redraw of the Editor, specifically the console and nothing to do with when the callback happens. AFAIK the console redraws/updates periodically as a performance thing, not always per-frame. If you single-step, it appears when the contact appears. Therefore I think you’re associating the redraw of the Editor with when you get the callback and discounting that your audio isn’t playing instantly.

To prove that, if you do the following:

public class DetectCollisions : MonoBehaviour {
    private void OnCollisionEnter2D(Collision2D collision) {
        GetComponent<SpriteRenderer>().color = Color.yellow;
        Debug.DrawRay(collision.GetContact(0).point, Vector3.up * 100f, Color.red, 5f);
        Debug.Log("hit floor");
    }
}

… then you’d expect to see that sprite change color instantly as well as draw a vertical line from the detected impact point which you do indeed see: Screen capture - 70c34ebc3a8eb2d38e0ff44ef7a04f38 - Gyazo

The console update is slightly later but that makes no difference to drawing/audio and it’s nothing to do with physics so your audio delay is likely because of the reasons stated previously.

Alternately do:

Debug.Break();

… or go full hack and force a repaint of the console (this should work in theory):

using System;
using UnityEditor;
using UnityEngine;

public class DetectCollisions : MonoBehaviour
{
    private EditorWindow m_ConsoleWindow;
    
    private void Start()
    {
        var consoleWindows = Resources.FindObjectsOfTypeAll(Type.GetType("UnityEditor.ConsoleWindow,UnityEditor"));
        m_ConsoleWindow = consoleWindows[0] as EditorWindow;
    }

    private void OnCollisionEnter2D(Collision2D collision) {
        GetComponent<SpriteRenderer>().color = Color.yellow;
        Debug.DrawRay(collision.GetContact(0).point, Vector3.up * 100f, Color.red, 5f);
        Debug.Log("hit floor");
        
        m_ConsoleWindow.Repaint();
    }
}

NOTE: I thought the project you’d provide would be related to your original question which was the difference between the collision and your query but it wasn’t.

1 Like