This is a guide to building the back-end of a simple game character selection system that lets us see the character selected by other players on our device in real-time. Let us explore how we can implement a character selection system for a real-time multiplayer game.
Overview
The main goal of this module is to allow our players to pick a character from a set of available characters and make it visible to other players in real-time. Multiple players might select the same character if there is no real-time validation of the selected characters.
We need a system where the different player can select their desired character on a first-come, first-serve basis. That means that if one player selects a specific character, then other players should not be able to select that same character. In this article, we will learn how we can make such a system for character selection.
The Architecture
This guide is simply an overview of the architecture, unlike a tutorial where you follow step-by-step guides. Instead, I'll share how you can build a few different pieces and put them together, so let's dive right into the details.
Making a Simple Database
We need to make a simple database containing information about all the players and their selected characters. Personally, I'd pick MongoDB because of its simplicity over a relational database. A Redis server would suffice too. For the sake of this article, I'm using MongoDB with Mongoose.
I have a Users model that contains basic information about the player. A player can only be present in only one room, so we have a roomName
field to keep track of the game the player is currently playing.
I also have a Rooms model, which basically represents a game. It contains basic information about the game, the list of players, and more.
The property that we are interested in is the characters
property. It contains the list of characters selected by the players. Both the players
and characters
are ordered lists of String
. The first item of the characters
list represents the character of the first item of the players
list.
These two models are the only essential collections we need to get started. The Rooms model also contains a property gameStarted
that keeps track of whether the game has started.
Setting a Character Change Event
Next, we need to write a controller that listens for events emitted by the client when one of the players picks a character. Let's call the event CharacterChange
. The event will be fired by a game client, such as a Socket.io client in Unity, whenever a player changes a character.
Here's a sample code to do just that.
Let's break down the controller's job into smaller pieces to better understand it.
- When the client sends the selected character for the given player, we look at the
characters
list in the user's current room to see if the character is already in use. If it's already there, we reject the request to change by ignoring it or sending an appropriate message. - If the character is not in use, we set the new character to the
characters
list for the player. Then we emit an event to all the connected clients in the room to send thecharacters
list.
That's all. After receiving the event, it's the client's job to properly update the UI to mark the unavailable characters.
Race Conditions
What about Race conditions that might occur from multiple requests?
Different databases have different ways of dealing with race conditions when reading or inserting data into or from the database. In the case of MongoDB, we need to use some sort of validation inside the findOne
callback.
Redis has its own way of handling race conditions by using transactions. Based on your choice of database, you might have to look by yourself at how race conditions can be handled. Ultimately, the goal is to ensure that two players don't select the same character.
That's it. I hope you learned a basic concept on how character selection can be updated in real-time for different players in the same lobby. Subscribe for more blog posts.