Multiplayer Online na Unity com Relay e Lobby
O jeito mais simples de fazer unity netcode relay hoje é usar o pacote Multiplayer Services com a API de Sessions: um jogador cria a sessão, a Unity aloca um servidor de Relay e devolve um código de entrada de poucas letras, o amigo digita o código e entra. Ninguém abre porta no roteador, ninguém precisa de IP, e você não paga servidor próprio enquanto estiver dentro da franquia gratuita.
Este tutorial monta isso com o Netcode for GameObjects no Unity 6.3 LTS: os pacotes certos, o projeto ligado ao Unity Cloud, o código para criar e entrar por código, uma lista de salas no estilo lobby, os limites do plano gratuito e os erros que aparecem no caminho.
Unity Netcode e Relay: por que Relay e Lobby existem
Quando você faz multiplayer em rede local, o cliente conecta direto no IP do host. Pela internet, isso quase nunca funciona: o host está atrás de um roteador doméstico (NAT) e às vezes atrás do NAT da operadora, que bloqueia conexões de fora. Pedir ao jogador para abrir porta no roteador é perder boa parte de quem tentou jogar.
O Relay resolve isso com um servidor intermediário. Host e clientes conectam para fora, no Relay, e ele repassa os pacotes entre eles. O host continua rodando o jogo; o Relay não executa lógica nenhuma.
O Lobby resolve o outro lado: como o cliente descobre a partida. Ele guarda as salas abertas, com nome, número de vagas e dados dos jogadores, e entrega o código de conexão do Relay para quem entra.
Na API de Sessions, as duas coisas viram uma só: sessão é a sala (Lobby) com a rede (Relay) já ligada. Se você ainda não conhece host, cliente e NetworkObject, comece pelo post de como fazer jogo multiplayer na Unity e volte aqui.
Pacotes: Netcode for GameObjects e Multiplayer Services
No Package Manager (Unity Registry), instale:
- Netcode for GameObjects (
com.unity.netcode.gameobjects). Para o Unity 6.3, use a linha 2.x (o manual do 6.3 lista a 2.13.3). Se o Package Manager oferecer uma linha mais nova, confira a compatibilidade com a sua versão do editor antes de trocar. - Multiplayer Services (
com.unity.services.multiplayer), versão 2.4.1 segundo o manual do Unity 6.3. Ele reúne Relay, Lobby e matchmaking e traz como dependência os pacotes de Authentication e Core.
Não instale os SDKs antigos separados de Relay e Lobby junto com o Multiplayer Services: a funcionalidade já está nele, e misturar gera classes duplicadas.
Na cena, crie um objeto com NetworkManager e Unity Transport, e configure o Player Prefab como no tutorial básico. A sessão encontra o NetworkManager sozinha e inicia host ou cliente quando a rede sobe.
Conectar o projeto ao Unity Cloud
Os serviços precisam saber de qual projeto é cada chamada.
- Abra Edit > Project Settings > Services.
- Faça login com a conta Unity e escolha Link project (ou crie um projeto novo no Unity Cloud).
- No painel do Unity Cloud (cloud.unity.com), abra o projeto e confira que Relay e Lobby estão habilitados nos produtos de multiplayer.
- Volte ao editor e confirme que o Project ID aparece em Services.
Sem esse vínculo, a inicialização funciona, mas a criação de sessão falha com erro de projeto.
Criar sessão e gerar código de entrada
Tudo começa com inicializar os serviços e logar o jogador. O login anônimo não pede nada: gera um ID e guarda no aparelho.
Arquivo SessionLauncher.cs, num objeto do menu:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Multiplayer;
using UnityEngine;
public class SessionLauncher : MonoBehaviour
{
[SerializeField] private int maxPlayers = 4;
[SerializeField] private string sessionName = "Sala do Juan";
public ISession CurrentSession { get; private set; }
private async Task EnsureSignedInAsync()
{
if (UnityServices.State != ServicesInitializationState.Initialized)
{
await UnityServices.InitializeAsync();
}
if (!AuthenticationService.Instance.IsSignedIn)
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
}
public async Task<string> CreateSessionAsync()
{
await EnsureSignedInAsync();
SessionOptions options = new SessionOptions
{
MaxPlayers = maxPlayers,
Name = sessionName,
IsPrivate = false
}.WithRelayNetwork();
try
{
CurrentSession = await MultiplayerService.Instance.CreateSessionAsync(options);
Debug.Log("Sessão criada. Código: " + CurrentSession.Code);
return CurrentSession.Code;
}
catch (SessionException e)
{
Debug.LogError("Falha ao criar sessão: " + e.Error + " " + e.Message);
return null;
}
}
public async Task<bool> JoinByCodeAsync(string code)
{
await EnsureSignedInAsync();
try
{
CurrentSession = await MultiplayerService.Instance.JoinSessionByCodeAsync(code.Trim().ToUpperInvariant());
return true;
}
catch (SessionException e)
{
Debug.LogError("Falha ao entrar: " + e.Error + " " + e.Message);
return false;
}
}
public async Task<IList<ISessionInfo>> ListSessionsAsync()
{
await EnsureSignedInAsync();
QuerySessionsOptions query = new QuerySessionsOptions { Count = 20 };
QuerySessionsResults results = await MultiplayerService.Instance.QuerySessionsAsync(query);
return results.Sessions;
}
public async Task<bool> JoinByIdAsync(string sessionId)
{
await EnsureSignedInAsync();
try
{
CurrentSession = await MultiplayerService.Instance.JoinSessionByIdAsync(sessionId);
return true;
}
catch (SessionException e)
{
Debug.LogError("Falha ao entrar: " + e.Error + " " + e.Message);
return false;
}
}
public async Task LeaveAsync()
{
if (CurrentSession != null)
{
await CurrentSession.LeaveAsync();
CurrentSession = null;
}
}
}
O ponto central é .WithRelayNetwork(). Segundo a documentação do Multiplayer Services, quando o host escolhe o tipo de rede na criação, a rede sobe automaticamente assim que a sessão existe, e quem entra depois é conectado no mesmo fluxo. Você não chama StartHost nem StartClient na mão: o pacote aloca o Relay, configura o Unity Transport e inicia o NetworkManager como host.
Multiplayer online na Unity: entrar na sessão e iniciar o host
No menu, ligue dois botões e um campo de texto. Arquivo SessionMenu.cs:
using TMPro;
using UnityEngine;
public class SessionMenu : MonoBehaviour
{
[SerializeField] private SessionLauncher launcher;
[SerializeField] private TMP_InputField codeInput;
[SerializeField] private TMP_Text codeLabel;
public async void OnCreateClicked()
{
string code = await launcher.CreateSessionAsync();
codeLabel.text = string.IsNullOrEmpty(code) ? "Erro ao criar" : "Código: " + code;
}
public async void OnJoinClicked()
{
bool joined = await launcher.JoinByCodeAsync(codeInput.text);
codeLabel.text = joined ? "Conectado" : "Código inválido ou sala cheia";
}
}
O async void só é aceitável aqui porque são handlers de botão; o resto usa Task. Quem cria a sessão vira host e vê o código na tela. Quem digita o código entra como cliente, e o Player Prefab aparece para os dois.
Para testar sem fazer build, use o Multiplayer Play Mode: ele abre jogadores virtuais no mesmo editor. Como configurar, e como fazer o movimento sincronizar depois que todos entram, está no post sobre NetworkTransform e sincronizar movimento.
Conectar dois jogadores é a parte que tem tutorial. O que vem depois não tem: decidir quem é autoridade de cada coisa, sincronizar vida, inventário e pontuação sem trapaça, tratar quem cai no meio da partida, e encaixar isso num jogo com menu, fases e fim. Multiplayer multiplica o trabalho de cada sistema, e é onde quem faz sozinho mais costuma parar.
Lobby: lista de salas e dados do jogador
Entrar por código serve para jogar com amigo. Para quem quer achar partida aberta, use a consulta de sessões. Pela documentação, a consulta devolve as sessões públicas e não cheias; sessão com IsPrivate = true só entra por código.
Cada resultado é um ISessionInfo com Id, Name, MaxPlayers, AvailableSlots e HasPassword. Um item de lista simples:
using TMPro;
using Unity.Services.Multiplayer;
using UnityEngine;
public class SessionListItem : MonoBehaviour
{
[SerializeField] private TMP_Text label;
private SessionLauncher launcher;
private string sessionId;
public void Setup(ISessionInfo info, SessionLauncher owner)
{
launcher = owner;
sessionId = info.Id;
int taken = info.MaxPlayers - info.AvailableSlots;
label.text = info.Name + " (" + taken + "/" + info.MaxPlayers + ")";
}
public async void OnJoinClicked()
{
await launcher.JoinByIdAsync(sessionId);
}
}
Atenção: o ID da sessão não é o código de entrada. ID serve para a lista; código serve para digitar.
Para mostrar nomes dos jogadores na sala, a documentação mostra o WithPlayerName(VisibilityPropertyOptions.Member) nas opções da sessão, junto com AuthenticationService.Instance.UpdatePlayerNameAsync(nome) depois do login. Dados de jogo (personagem escolhido, pronto ou não) vão como propriedades do jogador ou da sessão. Mantenha nesses campos só o que a sala precisa mostrar antes da partida; o estado do jogo em si fica no Netcode.
Limites do plano gratuito e custos
Segundo a página de preços dos Unity Gaming Services, consultada em outubro de 2026:
- Relay: os primeiros 50 CCU médios por mês são gratuitos, e cada CCU médio adicional custa US$ 0,16. Banda: 3 GiB por CCU, até 150 GiB por mês, somando as regiões. Acima disso, US$ 0,09 por GiB em EUA e Europa e US$ 0,16 por GiB em Ásia e Austrália.
- Lobby: 10 GiB por mês por grupo de regiões (EUA e Europa; Ásia e Austrália), com o mesmo preço por GiB acima disso.
CCU médio é a média de usuários conectados simultaneamente no mês, não o pico. Um jogo indie em teste ou com comunidade pequena cabe com folga. A conta muda quando o jogo cresce ou quando você manda dados demais por segundo: sincronizar posição 60 vezes por segundo de 20 objetos consome banda rápido. Cadastre um método de pagamento só quando for necessário e configure alertas de uso no painel.
Dinheiro não é o único limite. Com Relay, o host é um jogador comum: se ele fecha o jogo, cai a internet ou o celular bloqueia a tela, a partida acaba para todos. Para co-op entre amigos e partidas curtas, isso é aceitável. Para jogo competitivo, com ranking e partidas longas, o host vira ponto fraco e também pode trapacear, porque roda a simulação na máquina dele. Nesses casos o caminho é servidor dedicado, que custa por hora de máquina. Comece pelo Relay, valide se as pessoas jogam, e só migre quando o jogo justificar.
Erros comuns: autenticação, região, timeout
- "UnityServices not initialized" ou erro de autenticação: você chamou a sessão antes de
InitializeAsynceSignInAnonymouslyAsync. OEnsureSignedInAsyncdo script resolve. - Erro de projeto ou de permissão: o projeto não está vinculado em Project Settings > Services, ou Relay e Lobby não estão habilitados no Unity Cloud.
- Dois jogadores com o mesmo ID no Multiplayer Play Mode: o login anônimo guarda o ID no aparelho, e instâncias da mesma máquina podem dividir esse cache. Use perfis diferentes com
AuthenticationService.Instance.SwitchProfileantes do login. - Código inválido: códigos expiram quando o host sai. Peça um novo e confira maiúsculas.
- Latência alta: o Relay escolhe a região pelo host. Se o host está longe dos outros, todos sofrem. A documentação mostra como passar
RelayNetworkOptionspara escolher protocolo e região na criação. - Cliente entra e não aparece: Player Prefab não registrado no
NetworkManagerou faltandoNetworkObject. - Timeout ao conectar: firewall corporativo ou rede que bloqueia UDP. O Relay aceita outros protocolos via opções da sessão; em build Web, o protocolo precisa ser WebSocket.
Próximo passo
Faça o teste mínimo hoje: dois jogadores no Multiplayer Play Mode, um cria, o outro entra por código, e os dois veem o Player Prefab. Depois mande uma build para um amigo em outra cidade e repita pela internet de verdade. Com a conexão resolvida, o próximo problema é fazer o movimento parecer suave na tela do outro, e a teoria de latência e interpolação está no post sobre netcode e otimização de latência.
Perguntas frequentes
Preciso dos pacotes separados de Relay e Lobby?
Não. O pacote Multiplayer Services (com.unity.services.multiplayer), na versão 2.4.1 para o Unity 6.3, reúne Relay, Lobby e matchmaking na API de Sessions. Você cria uma sessão com WithRelayNetwork e ela já cuida da alocação no Relay e da sala.
Relay e Lobby da Unity são gratuitos?
Há franquia gratuita. A página de preços dos Unity Gaming Services, consultada em outubro de 2026, lista no Relay os primeiros 50 CCU médios por mês e 3 GiB por CCU até 150 GiB por mês, e no Lobby 10 GiB por mês por grupo de regiões. Acima disso, cobra por uso.
Qual a diferença entre Relay e servidor dedicado?
No Relay, um dos jogadores é o host e roda a simulação; o Relay só repassa pacotes entre ele e os outros, sem rodar lógica do jogo. No servidor dedicado, uma máquina na nuvem roda o jogo sem jogador. Relay é mais barato e simples, mas o jogo depende da conexão do host.
Por que preciso de login para usar Relay e Lobby?
Todo serviço da Unity identifica o jogador por uma conta de Authentication. O login anônimo resolve sem pedir nada ao jogador: ele gera um ID salvo no aparelho. Sem chamar SignInAnonymouslyAsync antes, as chamadas de sessão falham.



