DEV Community

Cover image for Multijugador en Godot 4: Guía práctica con MultiplayerSpawner
Ziva
Ziva

Posted on

Multijugador en Godot 4: Guía práctica con MultiplayerSpawner

El sistema multijugador de Godot 4 cambió mucho desde Godot 3. Si vienes de la versión anterior o de Unity, vas a ver nodos nuevos como MultiplayerSpawner y MultiplayerSynchronizer que hacen casi todo el trabajo pesado por ti. Lo bueno: bien usados, ahorran cientos de líneas de código. Lo malo: la documentación oficial los explica mal, y la mayoría de los tutoriales en YouTube están desactualizados.

Esta guía cubre lo que sí funciona en Godot 4.4+ para multijugador peer-to-peer simple, los errores más comunes y dónde la IA generativa todavía falla cuando la pides escribir código de red.

Qué viene incluido en Godot 4

Godot 4 trae un stack de red completo:

  • ENetMultiplayerPeer: capa de transporte UDP confiable. Funciona en LAN, WAN y a través de NAT (con port forwarding).
  • WebSocketMultiplayerPeer: alternativa para builds web/HTML5.
  • WebRTCMultiplayerPeer: peer-to-peer real con NAT traversal automático, pero requiere un signaling server.
  • MultiplayerSpawner: replica nodos automáticamente cuando se spawnean en el host.
  • MultiplayerSynchronizer: replica propiedades específicas (posición, salud, etc.) en cada frame.
  • RPCs (@rpc): llamadas remotas a funciones, con tres modos de autoridad.

Para la mayoría de los juegos indie, la combinación es: ENet + Spawner + Synchronizer + algunos RPCs. El resto (lobbies, matchmaking, autenticación) lo escribes tú o lo delegas a un servicio externo.

Configurando una sala simple

Vamos a hacer una sala donde el primer jugador es el host y los demás se conectan a él. El código mínimo es sorprendentemente corto.

extends Node

const PORT = 7777
const MAX_PLAYERS = 8

func host_game() -> void:
    var peer = ENetMultiplayerPeer.new()
    var error = peer.create_server(PORT, MAX_PLAYERS)
    if error != OK:
        push_error("No se pudo crear el servidor: " + str(error))
        return
    multiplayer.multiplayer_peer = peer
    print("Servidor escuchando en el puerto ", PORT)

func join_game(address: String) -> void:
    var peer = ENetMultiplayerPeer.new()
    var error = peer.create_client(address, PORT)
    if error != OK:
        push_error("No se pudo conectar: " + str(error))
        return
    multiplayer.multiplayer_peer = peer
    print("Conectando a ", address)

func _on_peer_connected(id: int) -> void:
    print("Jugador conectado: ", id)

func _on_peer_disconnected(id: int) -> void:
    print("Jugador desconectado: ", id)

func _ready() -> void:
    multiplayer.peer_connected.connect(_on_peer_connected)
    multiplayer.peer_disconnected.connect(_on_peer_disconnected)
Enter fullscreen mode Exit fullscreen mode

Eso es todo. El host llama a host_game(), los clientes llaman a join_game("192.168.1.42"). Las señales peer_connected y peer_disconnected te avisan cuando alguien entra o sale.

Replicando jugadores con MultiplayerSpawner

El nodo MultiplayerSpawner es la forma idiomática en Godot 4 de spawnear personajes. Reemplaza el viejo patrón de Godot 3 donde tenías que llamar rpc("spawn_player", id) y replicar manualmente.

Configuración:

  1. En tu escena de juego, añade un nodo MultiplayerSpawner.
  2. En el inspector, asigna su propiedad spawn_path a un Node2D o Node3D donde van los jugadores (algo como $Players).
  3. Añade tu escena de jugador (player.tscn) a la lista auto_spawn_list.
  4. Cuando el host instancie un jugador como hijo del nodo Players, el Spawner replica automáticamente esa instancia en todos los clientes.
# En el host, despues de que un peer se conecta:
func _on_peer_connected(id: int) -> void:
    if not multiplayer.is_server():
        return
    var player = preload("res://scenes/player.tscn").instantiate()
    player.name = str(id)  # importante: el name debe ser el id del peer
    $Players.add_child(player)
Enter fullscreen mode Exit fullscreen mode

El detalle clave es que el nombre del nodo (player.name) debe ser el ID del peer. Esto le dice a Godot a quién pertenece ese nodo. Si no lo haces, los inputs del jugador 1 controlarán a todos los personajes a la vez.

MultiplayerSynchronizer para movimiento

El Synchronizer replica propiedades específicas de un nodo. Para un personaje que se mueve, querrás replicar position y quizás rotation.

  1. Dentro de tu escena de jugador, añade un MultiplayerSynchronizer.
  2. En el inspector, abre el editor de Replication.
  3. Añade position (replicado en cada frame) y rotation si aplica.
  4. Configura replication_interval a 0 para movimiento crítico, o a 0.05 (20 Hz) para reducir tráfico de red.

El Synchronizer hace lo siguiente: en cada tick, el peer que tiene autoridad sobre el nodo envía las propiedades replicadas a todos los demás peers, que las aplican localmente. La autoridad por defecto es el host (peer ID 1), pero puedes cambiarla:

# En _ready() del nodo player:
func _ready() -> void:
    # Cada jugador es dueno de su propio personaje
    var peer_id = name.to_int()
    set_multiplayer_authority(peer_id)
Enter fullscreen mode Exit fullscreen mode

Con esto, cada jugador controla su personaje y el host no tiene que procesar los inputs de todos.

RPCs para acciones puntuales

Para cosas que pasan ocasionalmente (disparos, daño, chat) usa RPCs:

@rpc("any_peer", "call_local", "reliable")
func chat_message(text: String) -> void:
    print("[", multiplayer.get_remote_sender_id(), "]: ", text)

# Llamar desde cualquier peer:
chat_message.rpc("Hola a todos")
Enter fullscreen mode Exit fullscreen mode

Las tres anotaciones importantes son:

  • "any_peer" o "authority": quién puede llamar la función. authority es solo el dueño del nodo; any_peer permite que cualquiera la llame.
  • "call_local" o "call_remote": si el llamante también ejecuta la función localmente. Para chat sí, para movimiento no.
  • "reliable" o "unreliable": TCP-style o UDP-style. Acciones críticas usan reliable; movimiento puro usa unreliable_ordered.

Donde la IA generativa todavía falla

He pedido código multiplayer a varios LLMs y los errores se repiten:

1. Mezcla de APIs Godot 3 y Godot 4. Los modelos generales fueron entrenados con muchos tutoriales viejos, así que te darán código con rpc("function_name") en lugar de function_name.rpc(), o set_network_master() en vez de set_multiplayer_authority(). El primero compila pero no hace lo correcto; el segundo ya ni existe en Godot 4.

2. RPC sin anotaciones. Olvidan poner @rpc("any_peer") y luego no entienden por qué el cliente no puede llamar la función. Por defecto, los RPCs son authority-only.

3. Authority mal configurada. Los clientes intentan modificar nodos de los que no son autoridad, las modificaciones se sobrescriben en el siguiente sync, y el código parece "casi funcionar".

Herramientas como Ziva que conocen específicamente la API de Godot 4 evitan estos tres problemas porque consultan la base de clases del editor en tiempo real, no patrones aprendidos de tutoriales viejos. Para multiplayer en particular, donde el modo authority + el tipo de RPC + el reliable/unreliable importan mucho, esto es la diferencia entre "compila" y "funciona en producción".

Errores comunes y cómo depurarlos

El cliente conecta pero no se ve el otro jugador. Casi siempre es porque el MultiplayerSpawner no tiene la escena en su auto_spawn_list, o porque el nombre del nodo no coincide con el peer ID.

Los inputs del jugador 1 controlan a todos. Te falta set_multiplayer_authority() en _ready() del personaje.

Cliente y host se desincronizan. Probablemente estás modificando una propiedad replicada en ambos lados a la vez. Solo la autoridad debe modificar las propiedades sincronizadas.

Lag visible aún en LAN. Sube replication_interval a 0 (cada frame) o usa interpolación del lado del cliente.

Cuándo usar otra cosa

ENet con MultiplayerSpawner funciona para:

  • Co-op de hasta ~8 jugadores
  • Juegos PvP simples sin matchmaking complejo
  • Juegos donde el host puede ser un jugador (sin servidor dedicado)

No es la opción correcta para:

  • MMOs (necesitas servidores autoritarios escalables)
  • Juegos competitivos con anti-cheat (necesitas servidor dedicado, no peer authority)
  • Browser builds (usa WebRTC + signaling server)
  • Cross-platform mobile (PlayFab, Photon o Nakama suelen ser mejores)

Recursos para profundizar

La documentación oficial de Godot Multiplayer cubre todo lo anterior con más profundidad, aunque tiende a saltar entre Godot 3 y Godot 4 sin marcarlo. Lee dos veces antes de implementar.

Si estás empezando con multiplayer en Godot, este código alcanza para un proyecto pequeño funcional en una tarde. Las complicaciones reales (matchmaking, anti-cheat, persistencia) vienen después y se resuelven con servicios externos, no con más código de Godot.

Top comments (0)