Fish-Net NetworkTransform and Rigidbody Synchronization for Smooth Multiplayer Physics in Unity IO Games
IO games live or die on how physics feels when the arena is packed. One stuttery rigidbody, one desynced projectile, and the session stops feeling fair. Fish-Net gives you the tools—NetworkTransform, PredictionV2, interest management—but the mistake most projects make is treating every networked body the same way.
The fix is a tiered entity strategy. Passive scenery and collectibles ride lightweight NetworkTransform with careful interpolation. Player-controlled actors and high-agency objects use PredictionV2 rigidbodies so input feels instant under server authority. Hazards, zones, and one-way movers stay kinematic and driven, never fighting the solver. That split is what keeps bandwidth and CPU under control when player counts climb from dozens toward hundreds, while still delivering the client-side snap IO players expect.
This article walks through that tiering end to end: how to configure NetworkTransform for position, rotation, and scale at IO densities; how to stand up PredictionV2 rigidbodies the way current Fish-Net expects; where ownership, tick rate, and collider setup commonly desync you; and how pooling plus URP-friendly rendering keep the whole stack viable on WebGL and dedicated hosts. Start with the tiers—everything else hangs off that decision.
Why Blanket Physics Sync Collapses at IO Scale
Tiering is the decision you make before you ever open a NetworkTransform or PredictionV2 inspector. IO and fat browser titles routinely field large swarms of dynamic entities at once—player orbs, food pellets, debris, hazards, cosmetics. If every one of those carries a full rigidbody state across the wire each tick, snapshot size and server simulation cost climb in lockstep. Bandwidth that should have been spent on the bodies players actually touch gets eaten by remote pellets nobody is steering.
Players only need predicted authority on the bodies they control or collide with at close range. Remote food, background debris, and cosmetic floaters almost never justify PredictionV2; a lightweight NetworkTransform with sensible interpolation keeps them visually continuous without the reconciliation traffic. Treating every rigidbody as equal is the fastest way to drown a WebGL client or a modest dedicated host.
Smoothness itself is a split goal. Local input feel wants client-side prediction and immediate response. Remote visual continuity wants interpolation and occasional extrapolation so other players do not stutter. Server authority wants the final word on collisions and scoring. Optimising only one of those axes—say, cranking prediction on everything for “buttery” local feel—creates desync and rubber-banding on the other two. Fish-Net’s bandwidth-minded design already supports large player counts from dozens to hundreds, ships built-in client prediction and latency compensation, and imposes no CCU caps or paywalls with free LTS. That freedom still requires you to choose what not to simulate on the wire; the stack will not make the tiering decision for you.
Get the classification wrong and every later setting—send rates, ownership, collider layers, pooling—fights an uphill battle. Get it right and NetworkTransform can stay cheap for the passive majority while PredictionV2 rigidbodies stay sharp for the few actors that matter.
Tier Entities by Interaction Role Before You Add a Component
Walk every networked object in the project and ask what role it actually plays in the match: does the player control it, does it only need to look continuous from a distance, or does it merely sell the illusion of physics? The answer puts it into one of three tiers. Get the tier right and every later Fish-Net setting becomes a refinement instead of a rescue operation.
Three tiers, three different contracts with the wire
Tier A covers the passive majority—food pellets, static props, distant scenery pieces, anything the server simply moves or leaves idle. These objects ride a plain NetworkTransform with light interpolation, no client-side prediction, aggressive rigidbody sleep, and tight interest management so they drop off the wire the moment they leave a client’s relevant area. Tier B is reserved for the handful of actors that must feel immediate: player avatars, contested pickups, anything the local client collides with or steers. Those get PredictionV2 rigidbodies, full reconciliation, and a hard cap on how many any single client is allowed to predict at once. Tier C sits between them—kinematic hazards, impulse-driven projectiles, or breakable props that look physical but never run a predicted simulation on the clients; the server applies the impulse once and the NetworkTransform carries the result.
| Tier | Role | Component stack | Client cost |
|---|---|---|---|
| A – Passive | Server-moved or ambient | NetworkTransform only | Interpolation + culling |
| B – Actor | Player-controlled or contested | PredictionV2 Rigidbody | Full reconcile, limited count |
| C – Hazard / Impulse | Looks physical, never predicted | Kinematic + NetworkTransform | One-shot state, no sim |
Fish-Net’s feature set is built for exactly this split. Its client-side prediction, scene management, and bandwidth-conscious defaults let you treat the three tiers as an architecture choice rather than a single checkbox you flip on every prefab. The library is gaining traction for that feature-rich, bandwidth-efficient, open-source approach—use the tools it already gives you to keep Tier A cheap, Tier B sharp, and Tier C honest about how little simulation it really needs.
NetworkTransform Settings That Keep Tier A Cheap
Give Tier A only the replication it needs. For the pellets, coins, food orbs, and scenery props that dominate an IO arena, that means a lean NetworkTransform, not a rigidbody pipeline. Configure it for position first. Enable rotation only when the object’s spin is part of the read (a spinning power-up, a tumbling crate). Drop scale sync entirely for uniform pellets and coins; if every instance is the same size, you are paying bandwidth for a constant. That single cut multiplies across hundreds of entities and is one of the cheapest wins you will get.
Interpolation is what remote players actually feel. Tune it so spectators see continuous motion rather than stepped teleports, but do not over-smooth objects that live under a second. Short-lived pickups and burst debris often look cleaner with a controlled snap on spawn and despawn than with a long blend that still has residual error when the object is already gone. Match the interpolation window to lifetime: long-lived scenery can afford a smoother curve; ephemeral loot should arrive, read clearly, and leave without fighting the buffer.
Pair the component with object pooling and interest management so passives leave the wire when no client is near them. Pooled NetworkTransforms should reset sync state on reuse—clear pending snapshots, re-apply the minimal property set, then re-enable—so a recycled coin does not inherit stale interpolation from its previous life. Interest management (distance or grid-based) then decides whether that object is even considered for send. You are not building a full LOD system here; you are making sure Tier A only costs bandwidth inside the relevant interest set.
Fish-Net’s official property lists for NetworkTransform are brief commentary—usually a list of configurable fields with little on how the component is expected to be used under load. Treat the docs as a starting checklist, then open the component defaults, read the source for send conditions and interpolation paths, and validate under entity stress: dozens of pooled pickups moving through interest boundaries while a few players circle the same cell. If position-only sync still spikes, you have either left rotation or scale on, or you are still sending objects outside anyone’s interest. Fix the config and the culling before you reach for heavier tools.
PredictionV2 Rigidbodies Only Where Players Feel Them
Once Tier A is cheap and culled, the heavier tool is PredictionV2—and it belongs only on bodies the local player actually steers or shoves. For multiplayer rigidbodies in Fish-Net, PredictionV2 is the current newest and most developed path: enable it, then follow the prediction setup on Fish-Net’s manual site, because standalone tutorials for V2 remain sparse. That discipline matters. Prediction buys immediate client feel at the cost of running a parallel physics step, buffering inputs, and reconciling against server state. Spread it across every collidable in an IO arena and you erase the bandwidth wins you just earned on NetworkTransform.
Keep the predicted set tiny: player avatars and a small handful of high-interaction props—grapples, pushable crates, or balls that change ownership mid-match. Everything else stays kinematic or Tier A. In the predicted controllers, map raw inputs straight to forces or target velocities on the client so movement feels responsive on the frame it is pressed. The server still owns final state and authority; it re-simulates the same inputs, resolves collisions, and ships corrections. Ownership stays explicit so only the controlling client runs full prediction while spectators receive smoothed remote state.
Reconciliation is where smoothness lives or dies. Tune thresholds so micro-corrections—sub-centimetre position drift, tiny velocity nudges—blend away inside the interpolation window and stay invisible. Large, honest corrections (teleports after a stomp, hard wall collisions the client mis-predicted, ownership handoffs) should snap cleanly rather than fight the player with rubber-banding. Fish-Net’s client-side prediction is mature, with benchmarks that show lower bandwidth overhead than Mirror; that maturity is a real reason it fits real-time action IO. It only holds if the predicted rigidbody count stays small. Flood the tick with dozens of predicted bodies and reconciliation cost, collider pairs, and state history balloon until local feel and server authority both degrade. Tier B earns its place by staying exclusive to what the player can feel.
Ownership Handoffs, Force Rules, and Sleep Across Tiers
That exclusivity only holds if the boundary between tiers can move at runtime. A pellet, crate, or mount starts life as Tier A—cheap NetworkTransform, no prediction—but the moment a player grabs it, rides it, or folds it into a skill shot, it has to behave like something the local client can feel. Ownership transfer is the bridge, and the rules have to be explicit on the server.
Promote on hold, demote on release
When a player takes control, the server grants them ownership and briefly promotes the object into Tier B: enable the predicted rigidbody path, map their inputs to forces or velocities, and let reconciliation cover the short interaction window. On release—drop, dismount, or eat complete—revoke ownership, disable prediction, restore NetworkTransform as the authority channel, and snap remote viewers to the server pose before the object returns to passive sync. Keep the promoted set tiny and time-boxed; a grabbed prop that stays predicted after the player walks away is just Tier B leaking back into the flood you already refused.
Apply forces once; replicate outcomes
Gameplay forces belong only on the owning or predicting side. The owner runs AddForce, impulse, or velocity changes locally; everyone else receives the resulting state through the sync path already chosen for that tier. Duplicating the same force on every client creates double acceleration, mismatched collider pairs, and reconciliation thrash that no amount of interpolation will hide. Nested network objects need the same discipline: if joints, child colliders, or mount sockets matter for eats and grabs, parent-child ownership must stay consistent and you should prefer a single predicted root over a tree of independently ticking bodies.
Sleep, wake, and compact custom flags
Idle bodies still cost bandwidth if remotes keep interpolating them. Network sleep and wake so truly settled objects stop sending and stop being smoothed on spectators; wake only on meaningful contact or ownership change. When component defaults cannot express your gameplay flags—latched, edible, mountable, recently pushed—store compact custom physics state with SyncList or SyncDictionary rather than bolting extra RPCs onto every tick. Fish-Net provides SyncList and SyncDictionary types that handle this automatically, which keeps the wire small while still giving every tier a clear, shared picture of what is allowed to move.
Desync Forensics: Stabilize the Session Before You Blame Physics
When that shared picture still drifts, resist the urge to retune reconciliation first. Mixed-tier setups fail in ways that look like physics jitter but often start one layer below: the session never fully stabilized, a SyncType never applied, or an ownership handoff left two systems writing the same body. Treat desync as a forensics problem before you touch PredictionV2 thresholds.
Confirm the session, then walk the checklist
Wrong bind addresses, clients pointed at the wrong IP, and firewalls blocking the default game port 7777 produce rubber-banding and missed spawns that mimic bad interpolation. Spawn order mistakes and SyncType misconfiguration do the same: an object that never received its NetworkObject or never ran OnStartNetwork will float on defaults while everyone else assumes it is live. Fix connectivity and spawn path before you open the rigidbody inspector.
- Collider authority — server and clients must agree which collider is authoritative; duplicate non-trigger colliders on predicted bodies create phantom contacts only one side resolves.
- Physics materials — friction and bounciness that differ per build, or materials assigned only on one prefab variant, introduce non-deterministic slides after reconcile.
- Tick assumptions — PredictionV2 bodies advance on the prediction tick; NetworkTransform passives follow the observer timeline. Mixing the two without a clear owner produces micro-stutters at tier boundaries.
- Failed demotion — a grab that promoted Tier A to brief PredictionV2 must fully restore NetworkTransform and clear prediction state on release; leftover dual simulation double-writes position.
- Orphan forces — transform-only objects must never receive local AddForce or velocity writes with no owner; those impulses exist only on one client and read as permanent desync.
When something still looks wrong, build a tiny reproducible scene: two clients, one controlled predicted avatar, and a dense swarm of pooled Tier A passives under interest management. Drive the same grab, bump, and release sequence every time. Anecdotal “it jittered once in a full lobby” reports waste hours; a two-client swarm isolates whether the fault is ownership, tick mismatch, or a collider that only misbehaves under load. Log ownership changes and sleep/wake at the handoff points you already defined—most mixed-sync bugs surface there, not inside the reconciler.
WebGL Tick Consistency and URP Batching for Dynamic Bodies
Once those handoff logs look clean, the last place smoothness dies is the browser build itself. WebGL does not honour the same timestep contract the editor pretends it does. Lock Time.fixedDeltaTime and your Fish-Net tick rate to values you have measured under load in a real tab—not values that felt fine in Play Mode—and document what happens when the tab is backgrounded. Tab throttling starves predicted Tier B bodies first: reconciliation queues grow, corrections arrive late, and the player feels rubber-banding that never appeared in the editor. Tier A NetworkTransform passives degrade more gracefully; they simply stop receiving updates until the tab wakes, then snap or interpolate from the latest state. Treat that difference as design input, not a surprise.
When full PredictionV2 resimulation is too expensive in-browser, fall back to visual interpolation proxies on remote Tier B bodies. Keep true prediction on the locally owned avatar only; everyone else’s ship, mount, or grab target can ride a lightweight transform that eases toward the authoritative pose. You still own the physics outcome on the server—you just stop paying resim cost for spectators who will never feel the difference between a corrected rigidbody and a well-interpolated proxy.
Networking wins vanish if the render thread spikes. High-count dynamic meshes—pellets, debris, short-lived hazards—must share materials and sit in URP batches that survive instancing. One unique material per pooled coin undoes every bandwidth saving you earned by keeping those objects on NetworkTransform. Profile draw calls and batch breaks on device, not only in the Frame Debugger on desktop.
Validate early on real browser targets. Editor-only smoothness hides WebGL-specific reconciliation hitches, timer drift, and garbage spikes that only appear once the page is live. Ship a thin WebGL build that exercises your three tiers under a passive swarm and a handful of predicted actors; fix what that build shows before you tune cosmetics. The tiering architecture—NetworkTransform passives, sparse PredictionV2 actors, kinematic hazards—only delivers smooth IO physics when the browser is treated as a first-class runtime, not an afterthought export.