UGTK cat mascotUGTKengine within an engine Request access

UGTK / Toolkit / Gameplay Systems / QR Multiplayer System Completed

Gameplay Systems — UGTK

Qr Multiplayer System

Summary

The Qr Multiplayer System turns any smartphone into a game controller: the host (desktop/totem/WebGL) opens a WebSocket match and shows one QR code per player; when a player scans a QR, the phone opens the WebGL client page and automatically joins the match as that player.


Content


Modules Dependencies

Carried inside the prefabs. These modules are not referenced by the assembly definition - the components are simply already attached to the prefabs this module ships. Remove one of them from the project and the prefab keeps its layout and loses that behaviour, with nothing in the console to say so.

Module Component, and the prefab carrying it
UIModule/TextUpdaterSystem Mn_TextUpdater (in GamePlayerUiInfo), Mn_TextUpdater (in StartingPlayerUiInfo)

Only in the demo scene. The Debug scene of this module also uses UIModule/GradientSystem. Nothing in the runtime code needs it: import this module on its own and it works, but the demo scene opens with a missing script where that component was.


How It Works

Host flow

  1. Mn_LobbyPlayerSessionManager decides the number of players (min/max, Confirm()OnPlayerNumberDecided(n)).
  2. That event connects Mn_Host (which sends host.init_match) and calls Mn_QrCodeManager.GenerateQrs(n).
  3. For each player i = 1..n a pooled PlayerQrElement builds the URL clientBaseUrl?m_id=<matchId>&p_id=<i>, shortens it via PHP (qr/create_short_link.php) and renders the QR (local ZXing).
  4. Mn_Host.OnPlayerJoin → lobby UI (Mn_StartingPlayerUiInfo), QR hidden (Mn_QrCodeManager.OnPlayerConnected), gameplay spawn (Mn_GameplayPlayerManager.OnNewPlayerJoined).
  5. Mn_Host.OnPlayerMessageMn_HostMessageReceiver: handles nickname, character, confirm (ready check → OnAllPlayersReady); any other subEvent is forwarded to the Mn_PlayerInstance.ReceiveInfos override of your game.

Client flow (WebGL page opened by the QR)

  1. Mn_WebParam reads the URL: m_idMn_Client.ChangeMatchId, p_idMn_Client.ChangePlayerId, then onReadCompleteMn_Client.Connect() (sends player.join_match).
  2. Mn_ClientSender sends lobby info: ChangeNickname, ChangeCharacter, ConfirmSend.
  3. During gameplay use Mn_Client.SendPlayerGenericInfo(subEvent, value) (player → host) and listen to OnHostToPlayer / OnBroadcastToPlayer (host → player).

Setup

The system comes as two scenes, because host and player are two different builds of two different things:

  1. HostScene runs on the screen everyone looks at — the TV, the projector, the arcade cabinet. It generates one QR per seat and shows the lobby.
  2. ClientScene is what a player's phone opens after scanning. It is normally exported as a WebGL build and served from a URL.

Both need the WebSockets module pointed at the same server, and the host needs its match id to match what the QR encodes — that pairing is the whole contract, and it is the first thing to check when a phone scans a code and nothing happens.

VirtualPlayerInstance, GamePlayerUiInfo and StartingPlayerUiInfo are the prefabs the lobby instantiates per connected player; PlayerQrElement is the QR tile itself.


How To Use

  1. Host scene: place Mn_Host (+ SO_SocketInfo), Mn_QrCodeManager (pool of PlayerQrElement), Mn_LobbyPlayerSessionManager, Mn_HostMessageReceiver, Mn_GameplayPlayerManager; wire the events as in the debug HostScene.
  2. On the QR prefab set the flow baseUrl to your published WebGL client page.
  3. Client scene: place Mn_Client (+ same SO_SocketInfo), Mn_WebParam with the m_id/p_id bindings, and your Mn_ClientSender-derived sender. Build as WebGL and publish it at the baseUrl above.
  4. In your game, derive from Mn_PlayerInstance (host) and Mn_ClientSender (client) and define your own subEvent constants, identical on both sides.

Note: in this system player ids are numeric (1..N, one per QR); Mn_HostMessageReceiver does int.Parse on them.


Testing Scene

The codes in the recording belong to a match created while it was being made, so they are long expired: scanning them gets you nothing. Run the scene yourself and the ones you get will be live.


Technical Info

Scripts:


© 2026 Marcello De Bonis. All rights reserved

Real dependenciesOpen in the map →

Measured from the repository: code references (asmdef) plus prefab and asset GUIDs. Importing this module alone brings in 23 modules in total.