Ali Şahan Yalçın
DocsStep 1: A menu on screen

Tutorial: a working multiplayer menu

Step 1: A menu on screen

Create the levels, the Game Mode, the Player Controller and the menu widget, and get the menu showing when you press Play.

No Steam in this step. It only gets a menu on screen, because you cannot test what you cannot see.

You will make four things: two levels, a Player Controller that creates the menu, a Game Mode that installs that controller, and the menu widget itself.

Create the two levels

  1. In the Content Browser, right click and choose Level. Name it L_Menu.
  2. Right click again, choose Level, and name it L_Match.
  3. Open L_Match, put a floor and a light in it so it is visibly a different place, and save.
  4. Open L_Menu and leave it empty.
INFO: If your project came from the Third Person template, use its existing map as L_Match instead of making an empty one. It already has a floor, a Player Start and a Game Mode that spawns a character, which saves setting all three up later. An empty map still works, but players arrive in the dark with nothing under them, which looks exactly like a bug that is not there.

Create the menu widget

  1. Right click in the Content Browser and choose User Interface > Widget Blueprint.
  2. Choose User Widget if it asks for a parent class.
  3. Name it WBP_MainMenu and open it.

You are now in the UMG designer. Palette on the left lists what you can add, Hierarchy shows what you have added, and the middle is the canvas.

Two panels, not one list of buttons

A player is never doing all of this at once. Before they are in a session they can host or look for one. Once they are in, hosting and searching are meaningless and what they want is to see who else is here.

So the menu is two panels and you show one at a time:

PanelShown whenHolds
BrowseNot in a sessionHost, Find, the session list, Join
LobbyIn a sessionThe player list, Start, Leave
INFO: This is why a host never searches for their own game. Host puts you in the session, so you land on the Lobby panel with everyone else. Find and Join are the other player's route to the same place.

Lay out the panels

  1. Drag a Vertical Box from the Palette onto the canvas. This is the root; both panels go inside it.
  2. Drag a second Vertical Box into the first. This is the Browse panel.
  3. Drag a third Vertical Box into the first, below the second. This is the Lobby panel.

Into the Browse panel:

  1. Two Button widgets, each with a Text widget inside, labelled Host and Find.
  2. A Combo Box (String) below them.
  3. One more Button with a Text inside, labelled Join.

Into the Lobby panel:

  1. A Text widget for the player list.
  2. Two Button widgets with Text inside, labelled Start and Leave.

Finally, drag one more Text widget into the root box, below both panels. That is your status line, and it belongs to neither panel because it has something to say in both.

Name them, and make them variables

This part matters. A widget you cannot reach from the graph is useless, and Unreal does not expose them by default.

Select each one in the Hierarchy, rename it in the Details panel, and tick Is Variable:

Rename it toWhat it is
Panel_BrowseThe first inner Vertical Box
Panel_LobbyThe second inner Vertical Box
Button_HostThe Host button
Button_FindThe Find button
Button_JoinThe Join button
Button_StartThe Start button
Button_LeaveThe Leave button
Combo_SessionsThe Combo Box (String)
Text_PlayersThe player list Text, in the Lobby panel
Text_StatusThe bottom Text widget
WARNING: If Is Variable is unticked the widget never appears in the graph, and every step after this has nothing to connect to. This is the most common place to get stuck in UMG.

Show the right panel

Two visibility bindings, and the menu switches itself. You never write code to swap them.

For Panel_Browse:

  1. Select it, and in Details find Behavior > Visibility. Click Bind, then Create Binding.
  2. Add Get SteamForge Sessions, drag off it to Is In Session.
  3. Add a Select node, feed the bool into Index, set True to Collapsed and False to Visible, and wire it to Return Value.

For Panel_Lobby, do exactly the same but swap them: True is Visible, False is Collapsed.

INFO: Is In Session is the only thing deciding this, and it lives on a subsystem rather than on the widget, so it is already true by the time the panel asks. Hosting and joining both set it, which is why one binding covers both routes in.

Compile and save.

Create the Player Controller

The widget exists, but nothing creates it. A player's UI belongs to that player's Player Controller, so that is what creates it.

  1. Right click in the Content Browser and choose Blueprint Class.
  2. Pick Player Controller from the list.
  3. Name it BP_MenuController and open it.

In its Event Graph, from Event BeginPlay:

  1. Create Widget, with its Class dropdown set to WBP_MainMenu.
  2. Drag off Return Value and add Add to Viewport.
  3. Add Set Input Mode UI Only, and connect the widget into its In Widget to Focus pin.
  4. Add Set Show Mouse Cursor, with its checkbox ticked.

Set Input Mode UI Only needs a Player Controller on its Target pin. Drag in a Self node, because inside a Player Controller you already are one. Set Show Mouse Cursor is a variable on this class, so it needs no target at all.

INFO: Without Set Input Mode UI Only and Set Show Mouse Cursor you get a menu you can see and cannot click. The buttons are fine. The game is capturing the mouse.

Compile and save.

Create the Game Mode

A Player Controller is not used until something says to use it. That is the Game Mode's job: it decides which Controller and which Pawn a level gets.

  1. Right click in the Content Browser and choose Blueprint Class.
  2. Pick Game Mode Base.
  3. Name it BP_MenuGameMode and open it.
  4. In the Details panel, find Classes and set Player Controller Class to BP_MenuController.

Compile and save.

Tell the level to use it

  1. Open L_Menu.
  2. In the toolbar choose Window > World Settings.
  3. Set GameMode Override to BP_MenuGameMode.
  4. Save the level.
WARNING: Setting it in World Settings applies to this level only, which is what you want here. Setting it in Project Settings > Maps & Modes would apply it to every level, including your match, and you would get the menu on top of the game.

Check it

Press Play. You should see the Browse panel only: Host, Find, a dropdown, Join, and the status line. The Lobby panel is collapsed because you are not in a session, which is the bindings already doing their job.

The buttons do nothing yet. That comes next.

If you see nothing at all, confirm you are playing L_Menu and that its GameMode Override is set. If you see both panels, one of the two Select nodes has True and False the wrong way round.

Where to go next

Step 2: host a session.