Lesson 6: Scene Management with Networking (In-Scene Placed vs Dynamic Spawn)
Most multiplayer vertical slices fail during scene transitions, not combat logic. A clean gameplay loop can still break when players load at different speeds, ownership resets unexpectedly, or scene objects spawn twice.
In this lesson, you will build a stable scene transition flow for Unity Netcode, then decide which objects should be in-scene placed versus dynamically spawned.
Lesson objective
By the end of this lesson, you will have:
- A practical scene loading sequence for host and clients
- A clear split between in-scene placed and dynamic networked objects
- Guardrails that protect ownership and authority across transitions
- A transition test checklist for reconnect and late-join reliability
Why this matters
You can hide many replication mistakes in a single-map test. Scene changes expose them immediately: duplicate objects, missing interactables, or players spawning in invalid states.
If Lesson 5 defined state/event replication boundaries, Lesson 6 defines world lifecycle boundaries.
Core model for multiplayer scene flow
Use this baseline:
- Server decides when to transition
- Server triggers network scene load
- Clients complete load and notify readiness
- Server performs final spawn/restore pass
- Gameplay unlocks only after readiness gate
This prevents gameplay from starting while half the session is still initializing.
In-scene placed vs dynamic spawn
Use in-scene placed network objects for static, map-bound entities
Good examples:
- Capture points fixed to the map
- Doors and switches authored by level design
- Objective terminals with scene-specific positions
These objects are easier for designers to reason about and version in scenes.
Use dynamic spawn for runtime or player-driven entities
Good examples:
- Player avatars and reconnect replacements
- Temporary pickups and projectiles
- AI units tied to match events
Dynamic spawn gives cleaner lifecycle control for entities that do not belong permanently to one scene file.
Common transition bugs to avoid
Bug 1 - Loading scene locally without NetworkSceneManager
If any peer uses a local load path outside Netcode scene flow, object state diverges quickly.
Bug 2 - Spawning player objects before readiness sync
Early spawning can break ownership handoff when clients are still instantiating scene objects.
Bug 3 - Mixing static and dynamic responsibilities
When an object can be both authored in-scene and spawned at runtime, duplicates and authority confusion are common.
Step-by-step implementation pass
Step 1 - Define object lifecycle table
Create a small table with:
- Object type
- Spawn source (
in-sceneordynamic) - Authority owner (
serveror delegated) - Persistence rule (
per sceneoracross scenes)
Do this before coding transitions.
Step 2 - Gate gameplay with readiness
Add a simple readiness tracker on the server. Clients signal readiness only after scene load completes and required systems initialize.
Do not enable movement or combat until all required clients are ready.
Step 3 - Restore player state after load
For persistent values (health, team, loadout):
- Keep server-authoritative state outside scene-only components
- Re-apply values after player object availability
- Confirm UI sync after re-application
Step 4 - Isolate scene-specific dependencies
For each networked system, answer:
- What breaks if this scene object is missing?
- Is there a fallback or delayed bind path?
This avoids null-reference cascades during transition windows.
Step 5 - Run transition validation
Run this checklist:
- Host + one client transition 5 times in a row
- Trigger transition during active gameplay input
- Add one late joiner after first transition
- Disconnect and reconnect one client between transitions
- Verify no duplicate network object IDs or double-spawned actors
Document one failure mode and one fix in your sprint notes.
Example pattern - server-driven scene load with readiness gate
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MatchSceneFlow : NetworkBehaviour
{
private readonly HashSet<ulong> _readyClients = new();
public override void OnNetworkSpawn()
{
if (!IsServer) return;
NetworkManager.SceneManager.OnLoadEventCompleted += OnSceneLoadCompleted;
}
public void LoadMatchScene(string sceneName)
{
if (!IsServer) return;
_readyClients.Clear();
NetworkManager.SceneManager.LoadScene(sceneName, LoadSceneMode.Single);
}
[ServerRpc(RequireOwnership = false)]
public void NotifyReadyServerRpc(ServerRpcParams rpcParams = default)
{
_readyClients.Add(rpcParams.Receive.SenderClientId);
if (_readyClients.Count == NetworkManager.ConnectedClientsIds.Count)
{
StartMatchClientRpc();
}
}
private void OnSceneLoadCompleted(string sceneName, LoadSceneMode mode, List<ulong> completed, List<ulong> timedOut)
{
// Optional: server-side post-load setup before readiness signals.
}
[ClientRpc]
private void StartMatchClientRpc()
{
// Enable local gameplay systems after server confirms all peers are ready.
}
}
This gives one coordination point for scene lifecycle, instead of ad-hoc per-system timing.
Mini challenge
Create scene-lifecycle-map.md with:
- Three in-scene placed objects and why they are static
- Three dynamic-spawn objects and when they are created/destroyed
- One transition bug you can now reproduce reliably
If another teammate can run your map and reproduce the same transition order, your flow is deterministic enough for slice scale.
Pro tips
- Keep spawn authority rules near object definitions, not only in docs.
- Log scene transition milestones with timestamps and client IDs.
- Favor explicit post-load init methods over hidden
Awakeside effects.
Common mistakes
- Starting match timers before all clients are ready
- Reusing the same prefab as both in-scene and dynamic without strict rules
- Persisting transient scene references across map loads
Troubleshooting
"Some players spawn twice after transition."
Check whether that prefab exists in-scene and is also spawned by runtime code.
"Client can move, but objective systems are null."
You likely unlock input before scene dependency binding completes.
"Reconnect users lose team/loadout state."
Ensure server-owned persistent state is reapplied after object spawn, not only at initial connect.
Recap
You now have a scene lifecycle model that keeps transitions deterministic, avoids duplicate spawns, and preserves authority boundaries during map changes.
Next lesson teaser
Lesson 7 introduces lag, prediction, and reconciliation fundamentals so your slice feels responsive while staying server-authoritative.
Related links
- Lesson 5: RPC vs NetworkVariable Tradeoffs
- Unity Netcode Scene Management Docs
- Unity Guide - Multiplayer Networking Chapter
Lock this transition flow now; every later networking lesson depends on scene stability.