Search Issue Tracker
By Design
Votes
1
Found in
2018.4
2019.4
2020.1
2020.1.14f1
2020.2
2021.1
Issue ID
1298358
Regression
No
Rigidbody2D.IsTouching returns true for one frame when GameObject is no longer touching anything
How to reproduce:
1. Open the attached project's Scene labeled "Main"
2. In the Hierarchy, select the "Rigidbody" GameObject
3. In the Inspector, on the "RB Test" Component, under the "Toggle bounds history" header, enable "Draw is Touching"
4. Enter the Play Mode
5. Press the Space key
6. Observe the "Rigidbody" bounds drawn in yellow
Expected result: Rigidbody2D.IsTouching returns false when GameObject is no longer touching anything
Actual result: Rigidbody2D.IsTouching returns true for one frame when GameObject is no longer touching anything
Reproducible with: 2018.4.30f1, 2019.4.16f1, 2020.1.17f1, 2020.2.0f1, 2021.1.0a10
Add comment
All about bugs
View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.
Latest issues
- Crash on when D3D12RenderPass::SetupDeviceResources when opening FBX animation preview
- Serialization errors are thrown when "com.unity.render-pipelines.core" is added as a custom package and Graphics window is opened
- Character Joints unexpectedly rotate when a ragdoll is created using the Ragdoll Wizard
- Crash on GfxDeviceD3D11Base::DrawBuffersBatchMode when rendering the Scene view
- The shared EditorBuildSettings.asset file of symlinked projects is not updated when changing the order of the Scenes in Build Settings in one of the projects
Resolution Note:
Unity 2D Physics uses Box2D. Box2D calculates contacts (finds new ones and updates/deletes old ones) for the solver to use. The solver performs position/velocity integration and reaction to contacts. The final position therefore isn't at the contact point(s), those are used to direct the solver. This contacts->solver->write-back means contacts are where you started, not where you ended-up. To deal with that, you'd need to recalculate contacts again after the solver runs, something which by default, Box2D doesn't do. Note there is an exception here for Continuous collision mode when contacts are updated due to prematurely contacting something during the step but that isn't applicable here.
"IsTouching" is the same as "GetContacts" in that it simply looks at active contacts for that body/collider(s). These are Box2D contacts and are only calculated once per simulation step before anything else happens.
In the example scene, you are in contact with the ground. You apply a force then after fixed-update the simulation runs. Box2D calculates/updates contacts at that ground position then integrates the force into velocity and subsequently position so you get the upwards movement. The solver then does it work and the body is at the new upwards position. You then render the position at the ground because that's where it was when you asked prior to the simulation step. Note that this point, the original bounds are different than what the actual body/transform are because it's moved upwards so the bounds are prior to moving.
Next fixed-update you calculate the bounds again which are above the platform and query "IsTouching" but as stated in the last paragraph, the body has moved but contacts won't be calculated until the simulation runs which is after the FixedUpdate has run so it says it is touching. Getting Contacts will still return the same results; it's not a descrepancy between IsTouching/GetContacts etc.
Queries are immediately in that they perform actions without caching results there and then so based upon the current body position etc. Istouching/GetContacts don't calculate contacts, those are only produced once during the simulation.
In short, these are the steps taking Box2D into account:
Unity FixedUpdate Callback
Box2D Simulation runs:
> New/Update/Delete Contacts
> Integration Motions
> Solve
> Write-Back Rigidbody2D poses to Transforms
The Box2D world simulation step can be seen here: https://github.com/erincatto/box2d/blob/master/src/dynamics/b2_world.cpp#L935
In short, Unity isn't delaying anything. It's all about when contacts are updated.