Skip to main content

Creating Your First Multiplayer Game in Godot

This comprehensive guide shows you how to create a simple multiplayer game from scratch in Godot that connects to a dedicated server hosted on PlayFlow Cloud. This setup is compatible with both web and desktop platforms using TCP + TLS (“wss” protocol).
Godot 4.x - This guide uses Godot 4.4, but any 4.x version should work. We’ll be using the Compatibility renderer for web platform support.

Complete Project

Download the complete project files from GitHub (community-maintained sample)

What You’ll Build

By the end of this tutorial, you’ll have:
  • A 3D multiplayer game with player movement
  • Connection UI for server details
  • WebSocket networking with TLS support
  • Multiplayer synchronization using Godot’s built-in systems
  • A working dedicated server setup on PlayFlow

Before We Begin

1

Create New Project

Create a new Godot project and select the Compatibility renderer. This ensures web platform compatibility.
2

Set Up Main Scene

Create a new scene, save it as “main.tscn” and select 3D Scene as the root type. Right-click the file after saving and select Set as Main Scene.

Part 1: Building the Connection UI

Let’s start by creating the user interface that players will use to connect to your PlayFlow server.
1

Create Connection Display

  1. Open main.tscn and add a child node of type Control
  2. Rename it to “ConnectionDisplay”
  3. Set Custom Minimum Size to X: 256.0px and Y: 128.0px
2

Add Container Layout

  1. Add a child node to “ConnectionDisplay” of type VBoxContainer
  2. Set Layout Mode to Anchors and Anchors Preset to Full Rect
3

Create URL Input Field

  1. Add a child node to “VBoxContainer” of type HBoxContainer
  2. Add a TextEdit child to “HBoxContainer” and rename it to “UrlInput”
  3. Set Placeholder Text to “Url”
  4. Toggle on Fit Content Height
  5. Set Custom Minimum Size to X: 192.0px and Y: 32.0px
  6. Toggle on Expand under Horizontal
4

Create Port Input Field

  1. Add another TextEdit child to “HBoxContainer” and rename it to “PortInput”
  2. Set Placeholder Text to “Port”
  3. Toggle on Fit Content Height
  4. Toggle on Expand under Horizontal
5

Add Connection Buttons

  1. Add a Button child to “VBoxContainer” and rename it to “ConnectButton”
  2. Set Text to “Connect”
  3. Add another Button child to “VBoxContainer” and rename it to “DisconnectButton”
  4. Set Text to “Disconnect”
6

Set Unique Names

Right-click each input and button node and select Access as Unique Name. This allows us to reference them easily in scripts.
7

Create Connection Display Script

  1. Right-click “ConnectionDisplay” and select Attach Script
  2. Create a new script called “connection_display.gd”
  3. Add the following code:
8

Connect Button Signals

  1. Select the “ConnectButton” and go to the Node tab next to the Inspector
  2. Connect the “pressed()” signal to “ConnectionDisplay”
  3. Repeat for “DisconnectButton”
9

Add Game Environment

  1. Add a child node to “Main” of type MeshInstance3D and rename it to “Ground”
  2. Assign a new PlaneMesh to the Ground
  3. Set the PlaneMesh Size to X: 10m and Y: 10m
  4. Add a child node to “Main” of type Node3D and rename it to “Players”
  5. Add a child node to “Main” of type MultiplayerSpawner
  6. Add a Camera3D as a child to “Main” and position it as desired
  7. Add a DirectionalLight3D as a child to “Main” and rotate it (suggested: X: -60.0)

Part 2: Creating the Multiplayer Manager

Now we’ll create a Multiplayer Manager to handle all networking aspects of our game.
1

Create Multiplayer Manager Scene

  1. Create a new scene, save it as “multiplayer_manager.tscn”
  2. Select Node as the root type
2

Create Multiplayer Manager Script

  1. Right-click the root node and select Attach Script
  2. Create a new script called “multiplayer_manager.gd”
  3. Add the following code:
3

Add as Autoload Singleton

  1. Go to Project → Project Settings → Autoload
  2. Set Path to “res://multiplayer_manager.tscn”
  3. Set Node Name to “MultiplayerManager”
  4. Click Add
This makes the MultiplayerManager available globally throughout your project.

Part 3: Creating the Player

Let’s create the player character with movement and networking synchronization.
1

Create Player Scene

  1. Create a new scene, save it as “player.tscn”
  2. Select 3D Scene as the root type (this creates a Node3D)
  3. Add MeshInstance3D as a child to Player
  4. Assign a CapsuleMesh to the MeshInstance3D
  5. Move the MeshInstance3D up by Y: 1.0m so it sits on the ground
2

Add Network Synchronization

  1. Add a MultiplayerSynchronizer as a child to Player
  2. In the MultiplayerSynchronizer, click Add property to sync
  3. Select Player → position under Node3D
This ensures player positions are automatically synchronized across all clients.
3

Add Player to Group

  1. Select the Player root node
  2. Go to the Groups tab next to the Inspector
  3. Add the player to group “Players” (type “Players” and click Add)
4

Create Player Script

  1. Right-click the Player root node and select Attach Script
  2. Create a new script called “player.gd”
  3. Add the following movement code:

Part 4: Input Mapping and Player Spawning

1

Configure Input Map

  1. Go to Project → Project Settings → Input Map
  2. Add these input actions (click Add New Action for each):
    • move_forward - Assign W key and Up Arrow
    • move_backward - Assign S key and Down Arrow
    • move_left - Assign A key and Left Arrow
    • move_right - Assign D key and Right Arrow
2

Create Player Spawning System

  1. In main.tscn, select the MultiplayerSpawner node
  2. Right-click and Attach Script, create “spawner.gd”
  3. Add the following code:
3

Configure MultiplayerSpawner

  1. Set Spawn Path to “Players” (the Node3D we created earlier)
  2. Under Auto Spawn List, click Add Element
  3. Set the scene path to “res://player.tscn”
This tells the spawner which scene to instantiate and where to place new players.

Part 5: Server Export Configuration

1

Add Linux Export Preset

  1. Go to Project → Export
  2. Click Add… and select Linux/X11
  3. Rename the preset to “Linux Server”
  4. Set the export path filename to “Server”. Note the exact name you use here — when you upload the build, the executable path you configure must match this exported binary name so PlayFlow knows which file to run.
2

Configure for Dedicated Server

  1. In the Linux Server preset, go to the Resources tab
  2. Set Export Mode to “Export as dedicated server”
  3. This will create a headless server build suitable for PlayFlow
3

Export the Server

  1. Click Export Project…
  2. Choose your export location
  3. Toggle Export With Debug for development builds
  4. Click Save
4

Create Archive

Create a .zip archive of all exported files. This is what you’ll upload to PlayFlow.
PlayFlow expects a .zip file containing your server executable and any required assets.

Part 6: Deploy to PlayFlow and Test

1

Upload to PlayFlow

  1. Create your PlayFlow account at app.playflowcloud.com
  2. Create a new project for your Godot game
  3. Open the project’s Builds page and upload your server .zip file there
Prefer automation? You can upload builds through the API instead: request an upload URL with POST /api/v3/builds/upload-url?name=YOUR_BUILD and PUT the zip to the returned upload_url. See the API guide for details.
2

Configure Network Port

CRITICAL: When configuring the port in PlayFlow:
  1. Set Port Number to 8080 (matches our server code)
  2. Set Protocol to TCP
  3. Enable TLS - This is required for “wss://” protocol used in browser games
Without TLS enabled, web clients cannot connect to your server. This is essential for browser compatibility.
3

Start Server Instance

  1. Create and start a server instance in PlayFlow
  2. Copy the Host URL and External Port from the server details
The External Port is allocated by PlayFlow and will differ from your internal 8080. Always read the host and external port from the running server (the network_ports[] array in the API response, or the server details in the dashboard) rather than assuming a fixed port.
4

Test the Connection

  1. Run your Godot project locally (you can enable Multiple Instances in Debug settings for testing)
  2. Enter the PlayFlow Host URL in the “Url” field
  3. Enter the External Port in the “Port” field
  4. Click Connect
  5. Your player should appear and you can move around with WASD keys!
Testing Multiple Players: Enable Debug → Customize Run Instances → Enable Multiple Instances and set instance count to 2. Run the game and connect both instances to see multiplayer in action.

Technical Architecture

Network Setup

  • Protocol: WebSocket with TLS (“wss://”)
  • Server Port: 8080 (internal)
  • Synchronization: Player position only
  • Authority: Server-authoritative with client input

Key Components

  1. MultiplayerManager: Handles connection logic and server detection
  2. Player: Networked player with movement and authority management
  3. ConnectionDisplay: UI for entering server connection details
  4. MultiplayerSpawner: Automatically spawns players when clients connect

Platform Support

  • Desktop: Windows, Linux, macOS
  • Web: Browser support via WebSocket + TLS
  • Server: Headless Linux builds for PlayFlow

Next Steps

Lobby System

Add lobbies and matchmaking

WebGL Deployment

Deploy for web browsers

Common Issues

  • Verify the server URL and port are correct
  • Ensure TLS is enabled in PlayFlow port configuration
  • Check that the PlayFlow server instance is running
  • For local testing, use “ws://” instead of “wss://” (localhost only)
  • Check that MultiplayerSynchronizer is properly configured on the player
  • Verify the player scene is added to MultiplayerSpawner’s Auto Spawn List
  • Ensure players are being added to the “Players” group
  • Check that spawn_function is set correctly in spawner.gd
  • Verify MultiplayerManager is added as an Autoload singleton
  • Check that OS.has_feature("dedicated_server") returns true in server builds
  • Ensure the “Export as dedicated server” option is enabled in export settings
  • Check that input actions are properly defined in Project Settings → Input Map
  • Verify is_multiplayer_authority() check in player movement code
  • Ensure the player has authority set via set_multiplayer_authority()

Resources