Overview
Multiplayer games where players play together are compelling, but their development involves complexity completely different from single-player games. Each player's PC or smartphone (client) must continuously synchronize state over the network. When someone moves, position information must be sent to everyone, making that character appear to move the same way on all screens.
Networking solutions are frameworks that help with this complex network communication and data synchronization. Unity once had UNet, but now offers Netcode for GameObjects as the official new solution (many popular third-party solutions like Photon also exist).
Netcode for GameObjects is designed to integrate with existing GameObject and component workflows, allowing relatively smooth multiplayer development.
This article covers the most fundamental concepts of Netcode for GameObjects: "Server and Client," "Object Synchronization," and "RPC."
Server and Client
Multiplayer games need an "authority" that manages game state and decides who did what. The Server fills this role. Each player connects as a Client and follows server decisions. This model is called Server Authority—the standard architecture for preventing cheats and maintaining game state consistency across all players.
Netcode for GameObjects can operate in three modes:
- Server: Operates only as server. Typically players can't control it—dedicated to game management.
- Client: Operates as a client connecting to the server.
- Host: Combines both server and client roles. Common in small-scale P2P (peer-to-peer) games where one player also serves as server.
NetworkManager and Transport Layer
The central component running Netcode for GameObjects is NetworkManager. This singleton manages network sessions, connections, and object spawning.
NetworkManager requires a Transport layer component for actual data transmission. By default, Unity Transport is used—suitable for local development and P2P. For dedicated servers, you can choose other TCP or UDP-based transports.
NetworkObject and NetworkTransform
Objects you want to synchronize over the network (player characters, moving platforms, enemies) need a NetworkObject component attached. This assigns each object a unique network ID for management.
To automatically synchronize that object's position, rotation, and scale, add a NetworkTransform component. This alone automatically sends server-side object movement to all clients for synchronization.
NetworkVariable: Synchronizing Variables
To synchronize variables like player health, score, or ammo count, use NetworkVariable<T>.
using Unity.Netcode;
public class PlayerHealth : NetworkBehaviour
{
// Define health variable as NetworkVariable
// Third argument sets who can write (default: server only)
public NetworkVariable<int> CurrentHealth = new NetworkVariable<int>(100, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server);
// Event called on clients when value changes
public override void OnNetworkSpawn()
{
CurrentHealth.OnValueChanged += OnHealthChanged;
}
private void OnHealthChanged(int previousValue, int newValue)
{
Debug.Log($"Health changed from {previousValue} to {newValue}");
// Update health bar UI here
}
// Server-side health reduction
public void TakeDamage(int amount)
{
if (!IsServer) return; // Do nothing if not server
CurrentHealth.Value -= amount;
}
}
Defining NetworkVariable<T> in a class inheriting NetworkBehaviour automatically synchronizes .Value property changes on the server to all clients. Clients can subscribe to OnValueChanged events to detect changes and update UI.
RPC (Remote Procedure Call)
Beyond variable synchronization, sometimes you want to execute specific processing on specific targets—"tell server about attack intent from client" or "command all clients to play an effect from server." This is the role of RPC (Remote Procedure Call).
In Netcode for GameObjects, RPCs are defined by adding attributes to methods:
[ServerRpc]: A method requesting execution from client to server. When a client calls this method, it actually executes on the server. Used to convey player input (attack button pressed, etc.) to the server.[ClientRpc]: A method commanding execution from server to all clients. When the server calls this method, it executes on all connected clients. Used for flashy effects or sounds that should occur simultaneously on all players' screens.
public class PlayerActions : NetworkBehaviour
{
// Called on client when player presses attack button
public void RequestAttack()
{
// Request AttackServerRpc execution from server
AttackServerRpc();
}
[ServerRpc] // Client to Server
private void AttackServerRpc()
{
// This code executes only on server
Debug.Log("Server received attack request.");
// Perform actual hit detection here
// As result, command all clients to play effect
PlayAttackEffectClientRpc();
}
[ClientRpc] // Server to all Clients
private void PlayAttackEffectClientRpc()
{
// This code executes on all clients
Debug.Log("Playing attack effect on client.");
// Play particle effect, etc.
}
}
Summary
Netcode for GameObjects is a powerful entry point for Unity multiplayer development.
- The
serverholds game logic authority; each player connects as aclient. NetworkManagermanages sessions;NetworkObjectindicates synchronized objects.- Position sync uses
NetworkTransform; variable sync usesNetworkVariable<T>. - Use
RPCto request specific processing execution. Client→Server is[ServerRpc]; Server→Client is[ClientRpc].
Network programming is a deep field involving latency issues and state synchronization consistency. However, understanding these fundamental components and concepts is the first step toward online multiplayer game development.