Gaming

Multiplayer Tic-Tac-Toe Game in React Native Mobile

7 min read Michael Carroll on Mar 21, 2023
Real-time tic tac toe tutorial

This Tutorial Is Out of Date

While this tutorial contains useful information, this post was written using PubNub's React SDK V1. Check out our React SDK docs for an up-to-date reference. You can learn more about how PubNub powers thousands of customers worldwide in our PubNub for Developers resources.

Have suggestions or questions about the content of this post? Reach out to devrel@pubnub.com.

Note: This is part one of building an online multiplayer tic-tac-toe game in React Native using PubNub. If you have finished part one, please view part two of the tutorial where you will implement more backend functionality and play the game. You can view the completed application on GitHub.

Tic-tac-toe is a classic paper-and-pencil game that consists of rudimentary rules: two players, X and O, take turns placing their pieces in a square on a 3×3 table. A winner is declared when one of the two players places three of their pieces in a horizontal, vertical, or diagonal row.

In this tutorial series, you will develop a React tic-tac-toe game, an open-source JavaScript framework, where two players play against one another in real time. In part one, you'll implement the frontend by setting up the game environment and the game lobby where players will be able to enter their usernames, then create or join a room to play the mobile app. In Part Two, you’ll implement and test the game.

Tic Tac Toe Multiplayer Gaming and PubNub

This game is meant to provide a connected shared experience for players, where they can play with their friends anywhere around the world. To do so, you’ll use PubNub to power the game’s real-time infrastructure. All you have to focus on is developing a great experience for the players.

PubNub provides a secure, scalable, and reliable infrastructure to power any application through its real-time data APIs. With multiple SDKs available for your application needs, PubNub makes it easy to send and receive messages on any device in under 100 milliseconds.

You will use the PubNub React SDK to connect two players to a game channel where they will play against each other. Each move the player makes will be published to the channel (the lobby room), as a JSON payload, so the other player’s game board updates with the current move. By updating the table in real time for each move, players will feel as if they are playing next to each other.

Multiplayer Tic Tac Toe Game Functionality

The completed application, available on GitHub, will function and publish on both Android and iOS devices.

You'll add a lobby where players can join or create a room. If a player creates a room, they become the room creator and wait for another player to join their room.

If another player wants to join that same room, they enter the lobby room name (channel name) in the alert prompt and become the first player's opponent. If a player tries to join a room that already has two people, they will be unable to join.

Once the game starts, the tic-tac-toe game board is displayed, along with the initialized score for the players.

If the game ends in a draw, then neither player gets a point. But if there is a winner, the winner’s score is updated. The room creator gets an alert asking them if they want to play another round or exit the game. If the room creator continues the game, the board will reset for the new round. If the room creator decides to exit the game, both players will return to the lobby.

Before you can begin implementing the game, you'll need to set up your environment.

React Tic-Tac-Toe Environment Setup

If you don’t already have React Native set up on your machine, then be sure to follow React's getting started guide - a fantastic beginner walkthrough in getting started with React Native. Follow the rest of the instructions in the documentation to install any essential dependencies.

In your terminal, go to the directory you want to save your project in and create a new application.

You need to install five dependencies and link them to the app you just created. To make this easy, add the following script file dependencies.sh to your app’s root directory.

You'll need to make the script executable with the chmod command.

Run the script by calling dependencies.sh from the terminal.

Finally, now that your machine is set up, you'll need to create a free PubNub account, as you'll need your publish/subscribe keys to send information across the PubNub Network.

Initializing the Multiplayer Tic Tac Toe Project

Create a file named index.js in your app’s root directory and add the following code.

You'll need to create a new file named App.js. This is the main file for the game and it contains the components for the lobby and the table. Begin by importing the components and dependencies that will be used throughout the project.

Add the base constructor where you will insert your Pub/Sub keys to connect to PubNub, initialize the local state objects, and initialize the variables.

Each state object and variable will be discussed later on. Ensure you initialize PubNub after initializing the state.

Next, subscribe to the channel gameLobby when the component mounts.

The channel gameLobby is the main channel that players publish (send messages to) and subscribe to (receive messages from) when they are in the lobby. More logic will be added to this functionality later on, but for now, focus on the render method.

The Lobby component is shown first because this.state.is_playing is initialized to false. Once an opponent has joined a room channel that is waiting for another player, then this.state.is_playing is set to true and the Lobby component will be replaced by the Game component. The Spinner component is displayed to the room creator as long as the room creator is waiting for another player to join the game.

Add the CSS styles at the end of the file.

Before you finish the rest of App.js, take a look at the Lobby component.

Implementing the Lobby Component

In the lobby, players can enter their usernames and create or join a room. The logic that saves the username and calls the right method when a button is pressed is implemented in App.js. All the methods in the lobby component are used to style the buttons, but there are only three methods of focus in this tutorial: onChangeUsernameonPressCreateRoom(), and onPressJoinRoom, which are passed in as props from App.js.

In the app’s root directory, create a new folder named src and within that folder, create another folder named components. Inside of components, create a new file named Lobby.js. Add the following to the new file.

In summary, the logic in Lobby.js is setting up the username field and the two buttons. As previously mentioned, the only logic you do is to style the buttons. In this case, the buttons' background color, border color, and text color change when the button is pressed.

Make sure to add the CSS styles to the end of the file:

Saving the Username

Whenever the player types in the username field, onChangeUsername is called. This method, along with the rest of the methods in this post, is found in App.js.

You need to save the username in the username state and limit the number of characters to 15 characters so the username won’t be too long. You can increase or decrease this number if you wish.

Creating the Room Channel

Next, implement the method for onPressCreateRoom, which is called when the user presses the Create button.

The first check is to see if the username field is not empty. If the field is empty, the player is alerted to enter a username. A random room ID is generated and truncated to five characters. The ID is then appended to tictactoe–, which will be used as the game channel that players will subscribe and publish to in the PubNub Network. Below the if statement, add the following code. In order to obtain the number of people in the channel, PubNub's Presence function is used.

Once the room creator subscribes to the new channel, you alert the room creator to share the room ID with other potential players.

Add the following code to the else statement used above to alert the room creator to share.

Since you want to change the state for certain objects, setState is used to perform this change. Below the alert, in the else statement, add the following to set the state and close the else statement.

After changing the state of four objects, the boolean is_room_creator and the room creator’s username will be published to gameLobby. The Spinner component will be displayed to the room creator while they wait for someone to join the game.

Back in the componentDidMount function, you need to set up a listener to listen for certain messages that arrive in gameLobby .

You need to get the room creator’s username, so an if statement is used to check if the message arrived is msg.message.is_room_creator. If true, change the state x_username to the room creator's username.

Joining the Room Channel

The last method onPressJoinRoom is needed to finish setting up the lobby.

Ensure that the username field is not empty. If it’s not empty, then a prompt is shown to the opponent to enter the room name.

Since you need to consider both platforms (iOS and Android), check which platform the app is running on and use the appropriate prompt. For Android, use the prompt dependency react-native-prompt-android, since Alert.prompt is only supported for iOS devices.

Essentially, both prompts accomplish the same goal: call joinRoom(value), where value is the room name and cannot be an empty value when OK is pressed.

Since there can't be more than two people in the same lobby, hereNow is used to check the total occupancy for the channel. If the total occupancy is less than one, the player is trying to join a room that has not been created or there is a typo in the room name.

If the total occupancy is two, then there is a player in the channel, the room creator, who is waiting for another player to start the game.

If the total occupancy is greater than two, then the player is trying to join a room with a game in progress, so an alert tells the player that the room is full and to join another room.

Once the opponent successfully subscribes to the game channel, a message is published with the opponent’s username and readyToPlay set to true. Since the player is not the room creator, not_room_creator is set to true.

Finishing the Lobby Component

To finish the Lobby component, add the last logic for the listener in componentDidMount.

Both players will unsubscribe from gameLobby since they are subscribed to the game room channel. In setState, three actions are performed:

  1. Set the opponent's username to o_username

  2. Set is_waiting to false so the Spinner component will disappear from the room creator’s view

  3. Set is_playing to true so the game between the two players can start.

The last method to implement before finishing the lobby is componentWillUnmount.

This method is called when the component is unmounted and destroyed. The player is unsubscribed from gameLobby and this.channel, the channel the player is subscribed to for the game.

You've successfully set up your React Tic-Tac-Toe game and initialized the lobby room. Now that you have finished the logic for the lobby, you'll continue in Part Two of this tutorial by setting up the Tic-Tac-Toe Table and adding the game logic, and implementing real-time interactivity between the players.

Be sure to continue in Part Two to complete building your own Tic-Tac-Toe real-time multiplayer game in React Native.

If you have any other questions or concerns, please feel free to reach out to devrel@pubnub.com.