Dead Reckoning Passive Entities

We have changed the cannon.js physics controlled characters and cars, where the car or character replicate the remote users position and orientation, but when i hit the character or car controlled by other users i pass right through it. How do we make the remote users to solid again?

url: #Threeviewer Virtual Experience

“Passing through” almost always means there’s no contact pair being generated at all — not that a contact is generated but resolved wrong. Two things worth checking, in order:

Is there actually a CANNON.Body for each remote entity, or only a mesh? A lot of dead-reckoning setups only ever write the network snapshot onto the Object3D transform for rendering — which is exactly what dead reckoning is for (extrapolating a visual position between snapshots). If that’s the case here, there’s nothing in world.bodies for your local dynamic body to hit, and no amount of collision tuning fixes it. Fix: add a CANNON.Body with type = CANNON.Body.KINEMATIC and collisionResponse = true per remote entity, drive that from the network state, and read the mesh transform back off the body.

If there is a kinematic body — is it snapped or moved? cannon.js (and cannon-es) has no continuous collision detection — no CCD, it’s purely discrete, position-sampled each world.step(). If you set body.position.copy(target) once per network packet instead of advancing it every physics tick, the body sits still in the solver’s eyes for several steps, then teleports. If your local dynamic body’s path happens to cross that jump, there’s never an intermediate frame where the two shapes overlap, so no contact is ever generated — the exact shape of “pass right through,” and it’ll look intermittent (sometimes catches, sometimes doesn’t) depending on speed and body size, which is a good way to tell this apart from case one. Fix: interpolate/advance the kinematic body’s position every world.step() between snapshots instead of snapping it, so the broadphase actually sees it sweep through the space in between.

Which of the two is it right now — does the remote entity have its own CANNON.Body, and if so, is that body’s position set once per network update or advanced every physics step?

There’s a similarly constrained interactive system — spatial constraints on mid-range Android, not physics networking, but the same “external state has to keep the collider honest” shape — linked from my thread in Jobs: [For Hire] Three.js / R3F — parametric product configurators, design + code (Belgrade, UTC+2)

do u mean i should add cannon body to the car, we just removed the cannon out of the dead reckoning entities

Yes — that’s exactly it, and your own sentence confirms the diagnosis: if the cannon body was removed, there is nothing in world.bodies for your local car to collide with. The mesh is only what you see; the solver never knows it exists.

Add one CANNON.Body per remote entity, type: CANNON.Body.KINEMATIC, with the same shape you use locally. Kinematic is the right type here: it pushes dynamic bodies but is not itself pushed by them, which is what you want for something whose position comes from the network rather than from physics.

The part that catches people next: drive that body every physics tick, not on packet arrival.

If you write body.position.copy(networkPos) when a snapshot lands, the body stands still for several world.step() calls and then teleports. cannon-es has no continuous collision detection — contacts are found by sampling overlap at each step. If your car’s path crosses the gap the remote body jumped over, there is never a step where the two shapes overlap, so no contact is generated. That reads as “sometimes it collides, sometimes it passes through”, which is usually blamed on the network.

So keep doing what dead reckoning already does for the mesh — extrapolate a target from the last snapshot plus velocity — but apply it to the body instead:

// each physics tick
const t = extrapolate(lastSnapshot, now);          // what you already compute
body.position.lerp(t.position, 1);                 // or set velocity toward t
body.quaternion.slerp(t.quaternion, 1, body.quaternion);

Then read the mesh off the body, not the other way round:

mesh.position.copy(body.position);
mesh.quaternion.copy(body.quaternion);

Two things worth checking once it’s in: that the remote bodies are in the same collision group and mask as your local car, and that body.collisionResponse is true — a kinematic body with response off will report contacts in collide events but let everything pass through, which looks identical to having no body at all.

If the jumps between snapshots are large — high latency or low send rate — you may also want to cap how far the body is allowed to move in a single tick, so it never crosses a whole car width between steps. That is the one case where the teleport problem comes back even with per-tick driving.

so it means that all the effort we have done shifting from cannon physics to dead reckoning was meaningless, and even worst, we will have to add cannon bodies back anyways, the very reason of shifting.