Predicted Rigidbody (2D & 3D)
PredictedRigidbody and PredictedRigidbody2D capture Unity body state into prediction history, restore it for reconciliation, and expose familiar force and movement APIs for tick simulation.
Unity physics is not guaranteed to produce bit-identical results across machines. These components make it rollback-compatible; authoritative frames and reconciliation still correct divergence. Use deterministic identities and deterministic math when exact cross-platform simulation is required.
Setup
For 3D:
- Add a
Rigidbody,PredictedTransform, andPredictedRigidbodyto the same GameObject. - Enable Physics 3D under the Prediction Manager's Built In Systems.
- Enable Unity Physics 3D in Physics Provider.
For 2D, use Rigidbody2D and PredictedRigidbody2D, then enable the corresponding 2D settings.
PurrDiction advances enabled physics scenes during its tick. Put gameplay forces and movement in Simulate, not FixedUpdate:
protected override void Simulate(PlayerInput input, ref PlayerState state, float delta)
{
predictedRigidbody.AddForce(input.move * acceleration, ForceMode.Acceleration);
if (input.jump)
predictedRigidbody.AddForce(Vector3.up * jumpImpulse, ForceMode.Impulse);
}The 3D wrapper exposes AddForce, AddTorque, relative-force variants, explosion force, MovePosition, MoveRotation, pose and velocity properties, gravity, and kinematic state. The 2D wrapper provides the equivalent Rigidbody2D operations.
Torque follows Unity's own semantics. AddTorque and AddRelativeTorque on the 3D wrapper apply the body's world-space inverse inertia tensor for Force and Impulse modes; locked or zero inertia axes receive no angular velocity, and Acceleration or VelocityChange bypass mass and inertia. The 2D wrapper divides by the body's moment of inertia and works in degrees per second. The 3D relative variants rotate the vector by the body's rotation only, so object scale does not distort applied forces, and AddForceAtPosition derives its torque from the lever arm about the center of mass in both 2D and 3D.
Always drive the body through the wrapper inside Simulate, never through the raw Unity Rigidbody. On clients where the resolved policy is ServerRelay, the body is forced kinematic and posed from verified state; the 3D wrapper's velocity setters, which every force method routes through, silently do nothing on a kinematic body, and the 2D wrapper skips static bodies. The same Simulate code therefore runs on every peer without fighting the relayed pose; writing to the raw component bypasses these guards.
Settings and policies
PredictedRigidbody exposes Float Accuracy for packed 3D body state and an Event Mask for selecting collision and trigger callbacks. Both body types expose Soft Velocity Correction Rate for SoftCorrection.
Policy behavior is specialized for physics:
FullPredictionsimulates the body and rewinds it during replay.ServerRelaykeeps the body kinematic on clients and poses it from verified state.SoftCorrectionfreezes the body during replay, then blends verified pose and velocity error into the live body.PredictedIfOwneduses full prediction for the local owner and server relay elsewhere.PredictedIfOwnedWithSoftFallbackuses full prediction for the local owner and soft correction elsewhere, so remote bodies keep simulating and converge without rollback.
See Prediction Policies before mixing different policy types in the same collision scene.
Collision and trigger events
Subscribe to the component's prediction-aware events instead of treating ordinary Unity callbacks as final gameplay notifications:
private void OnEnable()
{
predictedRigidbody.onCollisionEnter += OnPredictedCollision;
}
private void OnDisable()
{
predictedRigidbody.onCollisionEnter -= OnPredictedCollision;
}
private void OnPredictedCollision(GameObject other, PhysicsCollision collision)
{
// Mutate predicted state here. Gate one-shot VFX/audio separately.
}PhysicsCollision contains predicted contact data, relative velocity, and impulse. The 2D event supplies a DisposableList<Physics2DContactPoint> that is owned by PurrDiction; consume it during the callback and do not retain it.
For one-shot presentation, use PredictedEvent, predictionManager.isVerifiedView, or defer the effect to view code so catch-up and replay do not duplicate it.