Tic-Tac-Toe - Part 3 - Multiplayer, with a Lobby



Attached Files

The following files have been attached to this tutorial:



Download now 908.03 KB


Download now 175.5 KB


11,666 visits, 24,617 views



This tutorial is licensed under CC BY 4.0. Please refer to the license text if you wish to reuse, share or remix the content contained within this tutorial.



I've already done two tutorials on the game itself, so I'm not going to repeat anything here. Have a look at them first to see how they are built. This version is actually a stripped down version of the second one, as I made overall improvements to the design to accommodate the AI engine (over the first version). Having said that, I've ripped out the AI engine completely, as it is not needed when the main purpose of this tutorial is to have two players play against each other.

The new initial layout is now the Login screen. It mainly consists of a TextBox for the player to enter their alias and an OK button to start. All layouts now have a status area that provides just basic status information.

The first event just sets up the GUI, and then confirms that Multiplayer is supported. When the OK button is press, we move to the Join layout.


The Join layout is were we show all of the peers currently in the lobby, and allow the player to pick another player to start a game with. As players join the lobby, they automatically are entered into the list. The current player then selects a suitable opponent and presses the Play button. There's some logging text and two debugging buttons also.

The eJoin Event sheet holds all of the client/side lobby connection code as well as the main game connection code. The code is broken up into 5 primary groups, and the GUI code.

On startup we set up the GUI elements, activate the LobbyRoom group and deactivate the MainRoom group, and start the connection to the signalling server. It's possible that we are already connected, and/or logged-in, if we have restarted the Join layout, we decode our current state and make the most appropriate call of connecting/logging-in/joining.

On signalling connected - we log-in if not done already. This is outside of any group as the action is common to both lobby and game.

LobbyRoom group

On signalling logged in - we join the "lobby" room.

On signalling joined room - if we come back as the host, we must leave the room, as the real lobby wasn't running, and we must immediately leave. Otherwise, we just flag that we are a client.

On peer connected - a client is connecting to the lobby. We clear out GUI list and our Dictionary. The GUI list shows the other players. The Dictionary is just a quick lookup to convert from alias to ID. C2 supports converting from ID to alias (PeerAliasFromID) but not the other way around, so this is just a quick way to do so. We now rebuild our lists, being careful to not include ourselves, or the lobby.

On peer message "GameRequest" - this is the key message that gets everything rolling. This message passes in the GameRoomName, which we store, and then we decode the X and O PeerIDs from this. We deactivate the LobbyRoom group, as we will be kicking out of the lobby. Here I've added a small delay before activating the Hosting group and Leaving the (lobby) room. This is to let the message finish its processing and report back to the client.

On signalling left room - we need to deal with the different scenarios of peers leaving. If the host is the one leaving, and we are in a room, Disconnect from room, otherwise just deactivate the LobbyRoom and activate the LostConnectionToLobby group to clean up. If not a host, if we are a valid client, skip the trigger, otherwise just complain that no lobby was found and lock out the GUI.

On peer disconnected - if the host disconnected and we are in a room, Leave room, otherwise just deactivate the LobbyRoom and activate the LostConnectionToLobby group to clean up.

On kicked - do the same thing as "disconnected".

Hosting group

This is the transitioning code for leaving the Lobby and preparing to switch to the Main room for the game. There can be a couple of scenarios here, so we need to deal with the different combinations to get us fully out of the lobby context so we can start up the game context.

On signalling left room - here we check if we are still in the room. Leaving isn't the same as disconnecting. Either Disconnect, or just activate the SwitchRooms group.

On peer disconnected - same thing - if we are still in the room, after a disconnect, Leave the room. Otherwise, just activate the SwitchRooms group.


This just cleans up our lobby state, deactivating all of the lobby/transition groups, activates the MainRoom and joins the main room with the instance of our dual-player game. NOTE: this is done this way as you can not Join a new room until you are completely out of any previous room. The Join can not be called directly from the left-room or disconnected triggers as there is still context to the old room. Doing the old active/deactivate with a group manages this.

MainRoom group

We need to deal with not being in the lobby any more, but in our dedicated main game room. We're back to the normal procedure of one peer being the host and the other the client., so we need to deal with both cases.

On signalling joined room - we just log some state here.

On peer connected - we send a hello message here, just for debugging. Log some state. If this instance of the game is X, call SetupGame() with appropriate details to set up the actual game engine with this peer as X and the other as O, or vice-versa. And finally, we go to the Game layout!


This just logs some status, waits 5 seconds, and then restarts the same layout.

ButtonPlay:On clicked deals with a selection being made and enabling the Play button.

When the Play button is pressed, we deactivate the LobbyRoom, activate the Hosting room, and set up some global variables. We then send a StartGameWithClient message with our encoded message and Leave the room. This kicks off the whole leave-the-lobby-and-switch-to-the-game mechanism above.

The next few events are just for testing.


Again we have to deal with handling a trigger change that can't be fully processed until after the trigger returns. Deactivate the RebuildJoinList group and just clear out our temporary lists and build them back up again from the list of connected peers. We exclude ourselves and the host.


  • Order by
Want to leave a comment? Login or Register an account!