After going back and forth on whether to use CharacterController or Rigidbody a couple times already, we have to move back to Rigidbody again due to some new technical requirements.
Because our character is rather fast-moving (can only reposition using a dash) we decided to use Continuous Dynamic collision detection on it.
This detection mode, however, produces rather weird results. It produces ghost collisions in a way that looks like theyâre caused by the Physics calculation assuming a faster movement than is actually happening or assuming a larger collider than is actually used. This means the character is no longer able to âfit throughâ places that it should easily be able to pass.
Has anyone encountered something like this before?
Iâve attached a video that illustrates this behavior with Continuous, Continuous Dynamic and Continuous Speculative detection. Using Discrete does not cause the problem, but skips collisions, which is precisely what weâre trying to avoid. (you can see the rigidbody and collider settings as well as the fixed time step in the video)
Some more info on this:
the rigidbody is moved using Rigidbody.MovePosition()
the behavior remains the same when reducing the capsule radius to 0
different interpolation settings do not change the behavior on any collision detection mode
I believe the 3D version of MovePosition is always using the discrete collision detection mode and teleports the rigidbody to its destination and so if your player is moving quickly then itâll step over any objects without being detected.
I suggest disabling isKinematic and switching to AddForce to move your player to its destination.
If you donât like using a non kinematic rigidbody because you want to have more control over the collision response then you can use modifiable contacts.
Thanks for the pointers. Iâll check out modifiable contacts.
Edit: To be honest, though, this really shouldnât be necessary. No collision detection mode should produce these kinds of erroneous collisions to begin with. It is absolutely possible this is due to user error, but I donât see how.
I want to stick to kinematic rigidbody because our intended behavior would be quite difficult to achieve much less control using AddForce et al.
MovePosition with a kinematic rigidbody should not be teleporting, though. As per the (admittedly still quite self-contradictory) documentation it âMoves the kinematic Rigidbody towards position.â
First you should check what the character is colliding with, in terms of contact normal, contact position, object name, etc.
Try to receive OnCollisionEnter and OnCollisionStay events and show them in the log or gizmo.
Also, SpeculativeCCD can theoretically cause ghost collisions.
From another perspective, if you just want to prevent tunneling, you do not necessarily need to use RigidBody; you can detect collisions with CapsuleCast, for example.
(Note that CapsuleCast cannot detect objects that are in contact at the start. So if you use CapsuleCast, I recommend that you double-check with a normal-sized capsule and a smaller one).
MovePosition doesnât work like the CharacterControllerâs move. MovePosition instantly teleports the rigidbody to the destination but it will interpolate the movement visually but not physically. Whereas setting rigidbody.position will teleport the rigidbody to the destination without any interpolation.
You can verify this by using MovePosition to instantly move a rigidbody capsule 10 meters with a wall between the source and destination position. The rigidbody wonât be blocked. Yet if you tried this with a CharacterController it would hit the wall and stop.
I believe the 2D version of MovePosition also works like a CharacterController.
I logged all that. It is colliding with the correct colliders, just at distances and angles that donât coincide with either collision detection Continuity the way itâs set up or the actual velocity/bounds of the player collider.
Also, we are not using speculative mode.
We need Continuous Dynamic collision for technical reasons to do with the damage system, unfortunately. Itâs a bit of a long story to get into here, but I already set up a system that checks along the movement for any skipped collisions (or hits) using a âdraggedâ capsule cast. Unfortunately, this doesnât suffice so that leaves us with having to re-incorporate the Unity physics again.
Hm. You are contradicting the documentation a bit so I donât know what to believe.
Iâve googled this a number of times before and everybody seems to have a different take on this.
What would you say is the best way to prevent skipped collisions between a fast-moving player and slow-moving enemy entities using a CharacterController?
As I wrote above, Iâve already implemented a âdraggedâ capsule sweep behind the player to pick up any missed hits, but I still need the Unity collisions for some cases and want to improve their responsiveness.
Yeah itâs confusing. And in your case youâre using a kinematic rigidbody and so it wonât be blocked regardless. Although Iâm guessing youâre trying to stop the player with your ExecuteHits function?.
I also see that youâre using âEnable Kinematic Pairsâ in the Physics settings which does seem to improve the collision detection when using MovePosition. So perhaps your issue is with how youâre handling the collision with ExecuteHitsâŚ
The collisions with static colliders are actually not part of ExecuteHits. They are caught in the PlayerMovement script and sent to the current active move (f.e. Dash). Every move can define its individual handling of collisions or just sent back that the player should be staggered. In this case, collisions with static colliders while dashing cancel the current move and start the Stagger move (which just takes the last velocity of the player, calculates a resulting stagger velocity and sends the player in the direction reflected from the collision normal).
TL;DR:
Collisions are handled by Unity Physics in the video. Nothing really special happening here.
I am quite sure this behavior is not due to anything particular I am doing. If you break it down, I lerp a kinematic rigidbody from point A to B, trying to catch all Kinematic-Static collision pairs along the path using Rigidbody.MovePosition() with Continuous Dynamic collision detection.
Iâll get back to it tomorrow. Test around with frame-stepping my Dash.