UGTK / Toolkit / Gameplay Systems / Tournament System Completed
Tournament System
Summary
The Tournament System generates and manages a single-elimination bracket UI from a list of players. It builds rounds and match slots with configurable orientation, seeding, spacing and connector graphics, supports multiple layout strategies (Standard, Butterfly, Midpoint), lets you declare winners and advance the bracket, and can save/load the whole state via a ScriptableObject snapshot. Optional netcode components let remote players join and report results.
Content
Modules Dependencies
- QR Multiplayer System: optional; the netcode receiver/sender (
Mn_TournamentHostReceiver,Mn_TournamentClientSender) useUGTK.GameplaySystems.QrMultiplayerSystemandUGTK.Api.WebSocketsSystemto let remote clients join and submit results. - Uses its own
SO_TournamentDataandSO_TournamentUILayoutDatabaseScriptableObjects for configuration and layout presets.
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 TournamentPlayer), Mn_TextUpdater (in TournamentUser) |
Only in the demo scene. The Debug scene of this module also uses UIModule/GradientSystem, UIModule/LayoutAutoResize, UtilitySystems/KeyInputActionSystem, UtilitySystems/PoolingSystem, UtilitySystems/TimingSystem, UtilitySystems/WebParamSystem, UtilitySystems/WindowsDeviceManagement.
Nothing in the runtime code needs them: import this module on its own and it works, but
the demo scene opens with missing scripts where those components were.
Setup
The bracket is data first and pixels second: SO_TournamentData holds it, and the scene draws it.
- Create a
SO_TournamentDataasset and add the entrants. - Add
Mn_TournamentManagerto the scene, give it that asset, and give it aSO_TournamentUILayoutDatabase- the profiles inside decide how the bracket is drawn. - Pick the shape with
E_TournamentLayoutOrientation.TournamentLayoutFactorybuilds the matching strategy:LayoutBracketStandardfor the usual ladder,LayoutBracketButterflyfor two halves meeting in the middle, and theLayout_Midpointfamily for the four directions. TournamentPlayeris the entrant,TournamentUserthe participant row, andMn_TournamentConnectorsGraphicdraws the lines between matches.Mn_CanvasZoomerexists because a full bracket does not fit on a screen.
For the networked version, use TournamentHostScene and TournamentClientScene together:
Mn_TournamentHostReceiver owns the truth, Mn_TournamentClientSender only asks. The state travels
as an S_TournamentSnapshot - the whole bracket, not a diff - so a phone that reconnects halfway
through is correct immediately instead of being patched back into place.
A bracket only exists for a power of two. Six entrants become eight with two byes, and where
those byes go is the difference between a fair draw and one where the same seed advances free every
time. TournamentMathUtils places them; check the result with an entrant count that is not a power
of two before you trust a real tournament to it.
How To Use
- Add
Mn_TournamentManagerto a RectTransform under a Canvas, assign theparticipantSlotPrefaband (optionally) aroundsRoot. - Set the players with
SetPlayers(names, rebuildNow)/AddPlayer/RemovePlayerAt, then configureorientation,seedingMode(Ordered/Random) +shuffleSeed, slot size, spacing and connector options. - Call
BuildTournament()to generate the bracket (rounds, match slots and connector graphics). UseDestroyGeneratedUI()to clear it. - Advance the bracket with
DeclareWinner(round, match, winnerIsA),ForceWinPlayer(name)orClearMatchResult(...); query state withIsMatchReady/IsMatchResolved/GetAllReadyMatches. - Save and restore the bracket with
SaveMomentIntoScriptableObject()andLoadByScriptableObject()(firesonSnapshotSaved/onSnapshotLoaded). - For a higher-level flow use
Mn_TournamentController(player count/nickname setup, orientation cycling, validation andonTournamentGenerated/onTournamentGenerationFailedevents); for online play add the host/client netcode components.
Testing Scene
Open TournamentScene in the module's Debug/ folder.
What to do, in order:
- Build a bracket with eight entrants and walk it to a winner.
- Build one with a count that is not a power of two, say six.
- Try it with entrant names left blank or padded with spaces.
- Switch the layout orientation, including the butterfly.
- Use
TournamentHostSceneandTournamentClientScenetogether for the networked flow.
Step 2 is the structural case: a bracket only works on a power of two, so six entrants have to be padded with byes, and how those byes are placed decides whether the bracket is fair. Step 3 is the input case — the names come from players, so blanks and stray spaces are normal, not exceptional.
The recording is the setup panel doing its job: a maximum of eight, eight players added with the New default player button, and Generate drawing the bracket - Player 1 against Player 8, Player 5 against Player 3, and so on up to the final. The seeding is random, so pressing Generate again gives a different first round from the same roster, which is the quickest way to see whether your layout survives every pairing.
Technical Info
- Mn_TournamentManager: core system; builds rounds/slots/connectors, handles seeding, fit-to-root scaling, winner declaration and snapshot save/load.
- Mn_TournamentController: front-end controller for configuring players and orientation and triggering generation with validation.
- Layout strategies (
ITournamentLayoutStrategy):LayoutBracketStandard,LayoutBracketButtferly,Layout_Midpoint, selected viaTournamentLayoutFactory. - Mn_TournamentParticipantSlot / Mn_TournamentPlayer / Mn_TournamentConnectorsGraphic / Mn_CanvasZoomer: slot, player and connector-drawing UI pieces plus canvas zoom.
- SO_TournamentData / SO_TournamentUiLayoutDatabase / S_TournamentUILayoutProfile / TournamentSnapshotTypes: configuration, layout presets and snapshot data.
- Mn_TournamentHostReceiver / Mn_TournamentClientSender: optional netcode for remote join and result reporting.
© 2026 Marcello De Bonis. All rights reserved
Depends on 9
Used by 0
- No other module depends on it.
Measured from the repository: code references (asmdef) plus prefab and asset GUIDs. Importing this module alone brings in 25 modules in total.
UGTKengine within an engine


