Multiplayer in Construct 3
The GamePush plugin for Construct 3 includes an auto-sync engine built on top of GamePush multiplayer. You register the objects you want to synchronize once, start auto-sync β and the plugin does everything else:
- builds the state schema from registered objects;
- sends the state of your objects every tick;
- creates, updates and destroys copies of other players' objects;
- creates world objects controlled by the host for all players;
- survives host migration without losing objects.
No code is required β everything is configured with actions and conditions in the event sheet. If you need low-level access, the full SDK is available in scripts via runtime.GamePush.multiplayer.
The general multiplayer concepts (host and peers, sync modes, interpolation) are described in the Multiplayer section β they fully apply to Construct 3 as well.
How it worksβ
Just like in the SDK, the plugin provides three synchronization mechanisms. In Construct 3 they look like this:
| Mechanism | Plugin actions | Purpose |
|---|---|---|
| Player state | Register object for sync with scope Player state | Player avatar: position, health, skin. Each player controls their own |
| Global state | Register object for sync with scope Global state | Enemies, items, environment. Only the host simulates them, others see copies |
| Messages | Send message / On message condition | One-off events: a shot, a death, an item pickup |
Key terms:
- Tag β a string identifier of an object type in the state (e.g.
"player","enemy"). Each registered object has its own unique tag. - Local instance β your own instance of a Player state object. You move it, everyone else receives updates.
- Proxy β an instance the plugin automatically created on your side to display another player's object.
- Entity β a global state object with a network ID (netId). It exists "for real" on the host and as a synchronized copy everywhere else.
Quick startβ
The developer workflow:
- Build a lobby with channels: all players join the same channel.
- Connect to multiplayer with the
Connectaction. - On the start of the game layout, register your objects and start auto-sync.
Connecting from the lobby (for example, the host presses "Start" and everyone goes to the game layout):
Legend
Button_Start
GP_Channels
System
Button_Start β Object Button (Button)
GP_ChannelsβΊGamePush Channels plugin
SystemβΊConstruct 3 System object
Minimal sync setup on the game layout:
Legend
System
GP_Channels
MP_player
SystemβΊConstruct 3 System object
GP_ChannelsβΊGamePush Channels plugin
MP_player β Object Sprite (Sprite)
This is enough for:
- your
MP_playerto automatically send its position andhpevery tick; - every player to get copies (proxies) of all other players;
- a player's proxy to be destroyed automatically when they leave.
Call all Register ... and Sync ... actions before Start auto-sync. When auto-sync starts, the plugin builds the state schema from everything that has been registered. Connect can be called before or after β synchronization starts once both are done.
Synchronizing the playerβ
Registering an objectβ
The Multiplayer βΈ Register object for sync action links an object type to multiplayer:
| Parameter | Value |
|---|---|
| Object | The object type (Sprite etc.) |
| Tag | A unique tag in the state, e.g. "player" |
| Scope | Player state β each player controls their own instance; Global state β the host controls all instances |
| Transform | None, Position (x, y), Position + angle or Full (position, angle, size, opacity, visibility) |
| Interpolate | Smoothly interpolate numeric transform fields (position, angle). Turn it off for teleports and instant movement |
| Layer | The layer to create copies on for other players. Empty β the first layer |
Object variablesβ
The Multiplayer βΈ Sync variable action adds an instance variable to synchronization. The variable is picked from a dropdown β no typos possible, and the event updates itself if the variable is renamed.
Enable Interpolate only for numbers that should change smoothly. Leave strings and "instant" values (health, item ID) without interpolation.
Legend
System
GP_Channels
MP_player
SystemβΊConstruct 3 System object
GP_ChannelsβΊGamePush Channels plugin
MP_player β Object Sprite (Sprite)
Variables are synchronized automatically in both directions: you change a variable on your object β it updates on your proxy for everyone else.
Appearance, animations and meshβ
Three extra actions extend synchronization of a registered object:
- Sync appearance β checkboxes: blend mode, color, flipped, mirrored, sampling, opacity, visibility.
- Sync animations β checkboxes: animation name, frame, speed, repeat-to frame. In most games the name and speed are enough β sync the frame only if you need exact frame-by-frame matching.
- Sync mesh β the mesh grid size and all its points (position and texture coordinates).
Legend
System
GP_Channels
MP_player
SystemβΊConstruct 3 System object
GP_ChannelsβΊGamePush Channels plugin
MP_player β Object Sprite (Sprite)
The amount of mesh data grows with the number of points: each point is 4 numbers sent every tick when changed. Use small meshes (e.g. 4Γ4) and only where you really need them.
Your instance and other players' proxiesβ
When auto-sync starts, the plugin binds the first existing instance of each player object as your local one. If there are several instances or the object is created later, bind it explicitly with the Bind local instance action (for example, after switching to a new layout).
You can tell your own player apart from proxies by UID using the MultiplayerLocalPlayerUID expression:
Legend
MP_player
System
MP_player β Object Sprite (Sprite)
SystemβΊConstruct 3 System object
Use the same trick to apply controls only to your own character.
The plugin creates and destroys other players' proxies by itself. If you need to attach extra logic to them (a nickname, a health bar), use the triggers:
Legend
GP_Channels
MP_player
System
NameTag
GP_ChannelsβΊGamePush Channels plugin
MP_player β Object Sprite (Sprite)
SystemβΊConstruct 3 System object
NameTag β Object Text (Text)
Inside the trigger the MultiplayerProxyPlayerID, MultiplayerProxyTag and MultiplayerProxyUID expressions are available.
Spawning players at spawn pointsβ
Place MP_SpawnPoint objects on the layout and position players on them at the start. Each player sets the position themselves β for their own local instance:
Legend
System
MP_SpawnPoint
MP_player
SystemβΊConstruct 3 System object
MP_SpawnPoint β Object Sprite (Sprite)
MP_player β Object Sprite (Sprite)
Synchronizing the environment from the hostβ
World objects β enemies, items, crates β are registered with the Global state scope. Only the host controls them:
- instances placed on the layout automatically become global state entities on the host;
- on peers, the pre-placed copies are replaced with synchronized entities β no duplicates;
- objects the host creates during the game automatically appear for everyone;
- objects the host destroys disappear for everyone;
- on host migration, the new host picks up the latest world snapshot and continues the simulation β nothing to do on your side.
Legend
System
GP_Channels
MP_enemy
MP_armor
SystemβΊConstruct 3 System object
GP_ChannelsβΊGamePush Channels plugin
MP_enemy β Object Sprite (Sprite)
MP_armor β Object Sprite (Sprite)
Run world logic (enemy AI, moving platforms) on the host only β wrap it in the Is host condition:
Legend
GP_Channels
System
MP_enemy
GP_ChannelsβΊGamePush Channels plugin
SystemβΊConstruct 3 System object
MP_enemy β Object Sprite (Sprite)
These events simply won't run on peers, and enemy positions arrive over the network already interpolated.
React to entities appearing and disappearing with the triggers:
Legend
GP_Channels
MP_enemy
GP_ChannelsβΊGamePush Channels plugin
MP_enemy β Object Sprite (Sprite)
Messages: shooting, item pickups, deathsβ
One-off events don't need state β use Send message and the On message condition. Send parameters:
- Event name β the event name, e.g.
"shot"; - Data β a data string (join values with
&and a separator); - Target player ID β
0for everyone, a player ID for a specific recipient,MultiplayerHostPlayerIDβ host only; - Echo β whether to receive your own message (handy for handling a shot with a single event for everyone, including the shooter).
Shootingβ
The shooter sends coordinates and an angle, everyone (including the shooter, echo: Yes) creates a bullet:
Legend
Mouse
MP_player
GP_Channels
System
Bullet
Mouse β Object Mouse (Mouse)
MP_player β Object Sprite (Sprite)
GP_ChannelsβΊGamePush Channels plugin
SystemβΊConstruct 3 System object
Bullet β Object Sprite (Sprite)
Who fired is determined by the MultiplayerCustomEventSenderID expression. The bullet itself doesn't need to be synchronized β every client simulates its flight locally, and the damage is authoritatively resolved by the target's owner or the host.
Item pickupβ
An item is a global entity, so only the host can destroy it. The player sends the host a request with the item's netId, the host destroys the item, and it disappears for everyone:
Legend
MP_player
MP_armor
System
GP_Channels
MP_player β Object Sprite (Sprite)
MP_armor β Object Sprite (Sprite)
SystemβΊConstruct 3 System object
GP_ChannelsβΊGamePush Channels plugin
echo: Yes covers the case when the picking player is the host themselves.
Death and respawnβ
Each player is authoritative for their own hp. When health runs out β notify the others and respawn:
Legend
MP_player
GP_Channels
MP_SpawnPoint
System
DeathFX
MP_player β Object Sprite (Sprite)
GP_ChannelsβΊGamePush Channels plugin
MP_SpawnPoint β Object Sprite (Sprite)
SystemβΊConstruct 3 System object
DeathFX β Object Sprite (Sprite)
Reference: Actionsβ
| Action | What it does | Usage example | Important notes |
|---|---|---|---|
| Multiplayer βΈ Connect | Connect to a multiplayer room by channel ID | In the lobby after joining a channel: Connect to channel Channels.ChannelID | The player must be a channel member. Host selection takes a few seconds after connecting |
| Multiplayer βΈ Disconnect | Disconnect from the room | When leaving to the menu | Other players' proxies will be destroyed |
| Multiplayer βΈ Set mode | Choose the sync mode: Fast (60 tick) or Smooth (20 tick) | Fast β for shooters and racing, Smooth β for strategies and slower games | Set it before Start auto-sync. Default is Smooth |
| Multiplayer βΈ Send message | Send an event to other players: name, data, target (0 β everyone, ID β a specific player), echo | A shot: Send "shot" with data X & ":" & Y to 0, echo Yes | Don't send constantly changing coordinates via messages β that's what state is for |
| Multiplayer βΈ Register object for sync | Link an object type to sync: tag, scope (Player/Global state), transform preset, interpolation, layer | Register MP_player as "player" in Player state | Call before Start auto-sync. The tag must be unique |
| Multiplayer βΈ Sync variable | Add an instance variable to sync (picked from a dropdown) | Sync variable hp of MP_player (interpolate: False) | After Register object, before Start auto-sync. Interpolate only smoothly changing numbers |
| Multiplayer βΈ Sync appearance | Sync appearance: blend mode, color, flipped, mirrored, sampling, opacity, visibility | Hide a picked-up weapon for everyone: Opacity and Visible checkboxes | Opacity and visibility are already part of the Full transform preset β don't duplicate them |
| Multiplayer βΈ Sync animations | Sync sprite animation: name, frame, speed, repeat-to frame | Run/jump animations of a character: Name and Speed checkboxes | Enable the frame only for exact frame-by-frame sync β it's extra traffic |
| Multiplayer βΈ Sync mesh | Sync mesh distortion: grid size and all points | A waving flag, deformable jelly | Traffic grows with mesh size β keep meshes small |
| Multiplayer βΈ Start auto-sync | Build schemas from registered objects and start automatic sync | The last action in the setup block on layout start | New Register ... calls after the start won't make it into the schema |
| Multiplayer βΈ Stop auto-sync | Stop the automatic sync loops | When leaving the game layout to the menu | The room connection is kept |
| Multiplayer βΈ Bind local instance | Explicitly bind the picked instance as the player's local object | After switching to a new layout, or when there are several instances | By default the first instance is bound automatically |
Reference: Conditionsβ
| Condition | Type | What it checks / when it fires | Important notes |
|---|---|---|---|
| Multiplayer βΈ On connect | Trigger | Connected to the room | The host may not be selected yet at this point |
| Multiplayer βΈ On connect error | Trigger | Connection failed | The error text is in the GamePushChannels.LastError expression |
| Multiplayer βΈ On disconnect | Trigger | Disconnected from the room | |
| Multiplayer βΈ On disconnect error | Trigger | Disconnect failed | |
| Multiplayer βΈ Is connected | Regular | The player is connected to the room | |
| Multiplayer βΈ Is host | Regular | The current player is the host | Use it as a gate for AI and world logic. The role can change at any moment |
| Multiplayer βΈ On became host | Trigger | The current player became the host | Fires both on the initial host selection and on migration |
| Multiplayer βΈ On became peer | Trigger | The current player became a peer | |
| Multiplayer βΈ On host migrated | Trigger | The room host changed | Auto-sync survives migration by itself; usually nothing to do |
| Multiplayer βΈ On player joined | Trigger | A player joined the room | The new player's proxy is created automatically once their state arrives |
| Multiplayer βΈ On player left | Trigger | A player left the room | Their proxy is destroyed automatically |
| Multiplayer βΈ On players updated | Trigger | The connected players list updated | For player lists in the UI |
| Multiplayer βΈ Each connected player | Loop | Loop through connected players | MultiplayerCurPlayerID, MultiplayerCurPlayerPing etc. are available inside |
| Multiplayer βΈ On message | Trigger | A message was received. Filter by event name; empty name β any message | Data β MultiplayerCustomEventData, sender β MultiplayerCustomEventSenderID |
| Multiplayer βΈ On tick | Trigger | Every SDK network tick (20 or 60 per second) | For fixed-step game logic. Delta β MultiplayerLastTickDelta |
| Multiplayer βΈ On send state error | Trigger | Sending the state failed | |
| Multiplayer βΈ Is auto-sync active | Regular | Auto-sync is running (Start auto-sync was executed) | |
| Multiplayer βΈ On entity created | Trigger | A global entity appeared (created by the host) | Pick the instance by MultiplayerEntityUID |
| Multiplayer βΈ On entity destroyed | Trigger | A global entity was removed | The instance is destroyed right after the trigger β create your effects in time |
| Multiplayer βΈ On player proxy created | Trigger | Another player's object was materialized locally | Pick by MultiplayerProxyUID; the player ID β MultiplayerProxyPlayerID |
| Multiplayer βΈ On player proxy destroyed | Trigger | Another player's object is about to be destroyed | |
| Multiplayer βΈ On global state updated | Trigger | A global state update arrived (peers only) | Advanced scenario: auto-sync already applies the state to instances by itself |
| Multiplayer βΈ For each entity | Loop | Loop through synced entities with a tag | MultiplayerEntityId, MultiplayerEntityUID, MultiplayerEntityField are available inside |
Reference: Expressionsβ
All expressions are called via the plugin object, e.g. GamePushChannels.MultiplayerMyPlayerID.
Connection and playersβ
| Expression | Returns | Example |
|---|---|---|
MultiplayerMyPlayerID | Current player ID | A label above your own character |
MultiplayerHostPlayerID | ID of the current host (0 if the host is not selected) | Send message target to message the host only |
MultiplayerConnectedPlayersCount | Number of connected players | "Players: " & GamePushChannels.MultiplayerConnectedPlayersCount |
MultiplayerConnectedPlayersAsJSON | Connected players array as a JSON string | For parsing with the JSON object |
MultiplayerNetworkPing | Current ping in ms | Connection quality indicator |
MultiplayerTickRate | Current tick rate (20 or 60) | |
MultiplayerBufferSize | Interpolation buffer size (number of snapshots) | Debugging |
MultiplayerBufferDelay | Interpolation buffer delay in ms | Debugging |
MultiplayerLastTickDelta | Last tick delta in ms | Fixed-step movement inside On tick |
Inside the Each connected player loopβ
| Expression | Returns |
|---|---|
MultiplayerCurPlayerID | ID of the player in the loop |
MultiplayerCurPlayerState("key") | A state field of the player in the loop |
MultiplayerCurPlayerIsHost | 1 if the player in the loop is the host, otherwise 0 |
MultiplayerCurPlayerPing | Ping of the player in the loop, ms |
MultiplayerCurPlayerConnectionStability | Connection stability 0β1 |
MultiplayerCurPlayerSessionDuration | The player's time in the room, ms |
Stateβ
| Expression | Returns | Example |
|---|---|---|
MultiplayerMyState | Current player state as a JSON string | Debugging |
MultiplayerMyStateKey("key") | A field of your own state. Supports dot paths | MultiplayerMyStateKey("hp") |
MultiplayerPlayerState(id, "key") | A state field of any player by ID | MultiplayerPlayerState(2, "hp") |
MultiplayerPlayersStateAsJSON | Full players state map as a JSON string | Debugging |
MultiplayerGlobalStateAsJSON | Full global state as a JSON string | Debugging |
Messages (inside On message)β
| Expression | Returns |
|---|---|
MultiplayerCustomEventName | Name of the last message |
MultiplayerCustomEventSenderID | Sender ID of the last message |
MultiplayerCustomEventData | Data of the last message |
Entities and proxiesβ
| Expression | Returns | Example |
|---|---|---|
MultiplayerEntityId | netId of the current entity (in For each entity / On entity created) | |
MultiplayerEntityUID | UID of the current entity instance | With the Pick instance with UID condition |
MultiplayerEntityTag | Tag of the current entity | |
MultiplayerEntityType | Object type name of the current entity | |
MultiplayerEntityField("key") | A field of the current entity | MultiplayerEntityField("hp") |
MultiplayerEntityIdForUID(uid) | netId of an entity by instance UID | Data for an item pickup request |
MultiplayerEntityUIDForId("netId") | Instance UID by netId | Pick an item on the host by the netId from a message |
MultiplayerEntityCount("tag") | Number of entities with a tag | MultiplayerEntityCount("enemy") |
MultiplayerLocalPlayerUID("tag") | UID of your local instance for a tag | Tell your own character apart: Pick instance with UID |
MultiplayerPlayerProxyUID(playerId, "tag") | UID of a player's proxy instance | Find a player's character by their ID |
MultiplayerProxyPlayerID | Player ID of the current proxy (in On player proxy created/destroyed) | |
MultiplayerProxyTag | Tag of the current proxy | |
MultiplayerProxyUID | UID of the current proxy | With the Pick instance with UID condition |
Stay in Touchβ
Other documents of this chapter are available here. To get started with GamePush, see the Tutorials chapter.
GamePush Community Telegram: @gs_community.
For your suggestions e-mail: official@gamepush.com
We Wish you Success!