Contenido del repositorio de origen con títulos, ejemplos, código, tablas, enlaces e imágenes preservados.
Unity Multiplayer for Mobile & WebGL2
This skill guides you through building real-time multiplayer Unity games that ship to both mobile (iOS/Android) and WebGL2 browsers. The two primary server frameworks covered are Colyseus (automatic state sync, room-based) and Nakama (full game backend with auth, storage, matchmaking).
Decision tree — start here
1. Choose your server framework
Pick Colyseus when:
- You need automatic state synchronization (schema-based binary deltas)
- Your game is primarily room-based (lobbies, matches, sessions)
- You want the fastest path to a working prototype
- You'll handle auth/storage/leaderboards yourself or don't need them
Pick Nakama when:
- You need built-in authentication (device, email, social, Steam)
- You need persistent storage, leaderboards, tournaments, friends, groups, chat
- You want a production-grade backend from day one
- You're comfortable with manual state management via opcodes
→ For Colyseus details: read references/colyseus-integration.md → For Nakama details: read references/nakama-integration.md
2. Understand the WebGL2 hard constraints
WebGL builds cannot use raw TCP/UDP sockets, cannot use C# threads, and cannot host servers. All networking must go through WebSocket (or WebRTC). In production, HTTPS pages require wss:// connections.
The standard cross-platform pattern:
#if UNITY_WEBGL && !UNITY_EDITOR
// WebSocket transport only — no UDP, no threads
m_Driver = NetworkDriver.Create(new WebSocketNetworkInterface());
#else
// Native platforms can use UDP for lower latency
m_Driver = NetworkDriver.Create(new UDPNetworkInterface());
#endif→ Full constraints and workarounds: read references/webgl2-constraints.md
3. Choose your WebSocket library
| Library | Cost | WebGL | Key strength |
|---|---|---|---|
| NativeWebSocket | Free | ✅ | Bundled with Colyseus SDK, v2.x auto-dispatches to main thread |
| Best WebSockets | ~€18 | ✅ | WSS, compression, profiler integration |
| unity-websocket | Free | ✅ | MonoBehaviour API, built-in ping/RTT, zero WebGL code changes |
| Unity Transport (UTP) | Free | ✅ | Official Unity package, dual UDP+WebSocket listen |
Avoid WebSocketSharp — it uses System.Net.Sockets and does not work in WebGL builds.
→ Full comparison and code examples: read references/websocket-networking.md
4. Pick your architecture pattern
| Genre | Pattern | What syncs |
|---|---|---|
| FPS / Action | Client-side prediction + server rewind | State + input |
| MMO / RPG | Snapshot interpolation | State only |
| RTS / Fighting | Deterministic lockstep / rollback | Input only |
| Turn-based | Request-response | Actions only |
| Casual / Social | Colyseus auto-sync or Nakama relay | State or messages |
→ Deep dive on each pattern: read references/architecture-patterns.md
Quick-start: Colyseus + Unity
Server (TypeScript):
import { defineServer, defineRoom, Schema, type, MapSchema } from "colyseus";
class Player extends Schema {
@type("number") x: number = 0;
@type("number") y: number = 0;
}
class GameState extends Schema {
@type({ map: Player }) players = new MapSchema<Player>();
}
class GameRoom {
onCreate() { this.setState(new GameState()); }
onJoin(client) {
this.state.players.set(client.sessionId, new Player());
}
onMessage(client, type, message) {
const player = this.state.players.get(client.sessionId);
if (type === "move") { player.x = message.x; player.y = message.y; }
}
onLeave(client) { this.state.players.delete(client.sessionId); }
}
defineServer({ rooms: { game: defineRoom(GameRoom) } });Unity Client (C#):
using Colyseus;
var client = new Client("ws://localhost:2567");
var room = await client.JoinOrCreate<GameState>("game");
// Listen to player additions
var callbacks = Callbacks.Get(room);
callbacks.OnAdd(state => state.players, (sessionId, player) => {
SpawnPlayer(sessionId, player);
callbacks.Listen(player, p => p.x, (val, prev) => MovePlayer(sessionId));
});
// Send input
await room.Send("move", new { x = transform.position.x, y = transform.position.z });→ Full Colyseus integration guide: references/colyseus-integration.md → Server template: assets/colyseus-room-template.ts → Client template: assets/unity-colyseus-manager.cs
Quick-start: Nakama + Unity
Server (TypeScript runtime):
const matchInit: nkruntime.MatchInitFunction = (ctx, logger, nk, params) => {
return { state: { players: {}, tick: 0 }, tickRate: 20, label: "" };
};
const matchLoop: nkruntime.MatchLoopFunction = (ctx, logger, nk, dispatcher, tick, state, messages) => {
for (const msg of messages) {
const data = JSON.parse(new TextDecoder().decode(msg.data));
state.players[msg.sender.userId] = { x: data.x, y: data.y };
}
dispatcher.broadcastMessage(1, JSON.stringify(state.players));
return { state };
};Unity Client (C#):
using Nakama;
var client = new Client("http", "127.0.0.1", 7350, "defaultkey",
UnityWebRequestAdapter.Instance);
var session = await client.AuthenticateDeviceAsync(SystemInfo.deviceUniqueIdentifier);
var socket = client.NewSocket(useMainThread: true);
await socket.ConnectAsync(session);
var match = await socket.CreateMatchAsync();
// Send state
await socket.SendMatchStateAsync(match.Id, 0,
System.Text.Encoding.UTF8.GetBytes(JsonUtility.ToJson(position)));
// Receive state
socket.ReceivedMatchState += (matchState) => {
var data = System.Text.Encoding.UTF8.GetString(matchState.State);
ApplyState(matchState.UserPresence.UserId, JsonUtility.FromJson<Position>(data));
};→ Full Nakama integration guide: references/nakama-integration.md → Server template: assets/nakama-match-handler-template.ts → Client template: assets/unity-nakama-manager.cs
Performance checklist
When optimizing for mobile + WebGL2, follow this priority order:
- Reduce what you send — Delta compression, quantization, smallest-three quaternion encoding. Only sync changed data. Use
NetworkVariablefor persistent state, RPCs for events. - Reduce how often you send — 20-30 ticks/second is optimal. Use interpolation to smooth gaps. Colyseus defaults to 20Hz patchRate.
- Reduce who receives — Interest management / area-of-interest filtering. Far entities get lower update rates or are culled entirely.
- Use binary serialization — MessagePack for C# is the best general choice (10-100x faster than JSON, compact). Avoid JSON in production hot paths.
- Pool everything — Object pooling for network messages, byte arrays, collections. WebGL GC runs only once per frame; mid-frame allocations risk OOM.
- Batch on mobile — Minimize cellular radio activations. Front-load transfers, avoid polling patterns. Offer 30 FPS option.
→ Detailed optimization guide: references/performance-optimization.md
Deployment overview
Both Colyseus and Nakama deploy via Docker. For production:
- Nginx reverse proxy with WebSocket upgrade headers
- SSL/TLS required for WebGL clients (
wss://) - Colyseus scaling: Redis for presence + driver, PM2 in fork mode
- Nakama scaling: CockroachDB cluster, multi-node Nakama with gossip discovery
→ Full deployment guides: references/deployment-guides.md
Reference files index
Read these as needed — don't load all at once:
| File | When to read |
|---|---|
references/architecture-patterns.md | Choosing network topology, state sync strategy, or ECS networking |
references/colyseus-integration.md | Setting up Colyseus server, Unity SDK, rooms, schema, matchmaking |
references/nakama-integration.md | Setting up Nakama server, Unity SDK, auth, multiplayer, storage |
references/websocket-networking.md | Choosing/configuring WebSocket library, reconnection logic |
references/webgl2-constraints.md | Understanding WebGL2 limitations, conditional compilation patterns |
references/performance-optimization.md | Network bandwidth, serialization, GC, mobile battery, object pooling |
references/deployment-guides.md | Docker, Nginx, SSL, Redis, scaling, managed hosting options |
Asset templates index
| File | Purpose |
|---|---|
assets/colyseus-room-template.ts | Production-ready Colyseus room with auth, reconnection, clock sync |
assets/nakama-match-handler-template.ts | Authoritative Nakama match with tick loop, presence tracking |
assets/unity-colyseus-manager.cs | Unity singleton managing Colyseus connection, room join, state callbacks |
assets/unity-nakama-manager.cs | Unity singleton managing Nakama client, socket, auth, match lifecycle |
assets/unity-websocket-client.cs | Standalone WebSocket client with exponential backoff reconnection |
