As the gaming industry continues to grow in size, the need to create a unique and dynamic user experience has become even more mandatory. Because of its fandom, businesses have to maximize the multiplayer gaming experience to drive customer acquisition and retention. However, companies are faced with a number of obstacles when trying to scale multiplayer games, all of which can be solved through Redis.
Personalized interactions and high-speed reactions are at the heart of creating a unique user experience. Redis provides game publishers with a powerful database that can support low-latency gaming use cases. Recently a Launchpad App built a unique application that could have only been deployed by Redis due to its unmatched speed in transmitting data.
This is crucial because participants play from all around the world. Interactions between players must be executed in real-time to support gameplay, requiring the latency to be less than one millisecond.
Let’s take a deep dive into how this was done. But before we do so, make sure to have a browse through the exciting range of different applications that we have on the Launchpad.
You’ll build a real-time Geo-distributed multiplayer top-down arcade shooting game using Redis. The backbone of the application is Redis, for it acts as an efficient real-time database that enables you to store and distribute data.
As we progress through each stage chronologically, we’ll unpack important terminology as well as each Redis function.
Let’s identify the different components you’ll need to create this game. The application consists of 3 main components:
The main idea of this multiplayer game is to keep it real-time and distribute it geographically. That means that all the instances in your cluster should be updated so that you don’t run out of synchronization. Now let’s take a look at the architecture.
Now let’s take a look at the flow of the architecture.
Under the root of the repository, you will find a Docker compose YAML file:
Under this YAML file, there are two major services that are defined – redis and backend.
Below is how the Dockerfile for Redis looks like:
Below is the Dockerfile for NodeJS backend:
Bringing up the services
Ruin the following commands from the online_game directory
You access the online WebServer via http://127.0.0.1:8080
There are three RedisGears functions that each have their own set of sub-functions:
Once a user starts the game, the first thing the user will do is search for a game using RediSearch. If the game is present then that person will try and join the game. If not then RedisGears is triggered to create a new game. See the function below
Once the user has created a new game, then other players will join and everyone will be able to play.
If no game is present, then RedisGears is triggered to create a new one.
Once the user has created a new game, then other players will join and everyone will be able to play.
This function adds a new player to the game and it has the same approach as Create_new_game function. Again, RedisGears is triggered which then creates a new user
When a user joins the game, RedisGears is triggered to enable the Join_game function. This also increments the player count of the game_instance (HINCRBY).
When a user is eliminated from the game or chooses to leave, RedisGears is triggered to facilitate the process. This also automatically reduces the player count and automatically creates a notification to confirm that this action has been completed.
During gameplay, players will fire missiles to eliminate other competitors. When a player fires a missile, the below sub-function is then triggered:
If a missile hits another player, then that user will be eliminated from the game. The below code determines whether a player has been hit by a missile.
MESSAGE_EVENT_HANDLERS | Explanation |
p (pose) args: [user_id, x, y, orientation]; | A client receives a user_id position update |
c(click) args: [user_id, x (where it was clicked at), y (where it was clicked at), angle (from the player position to click position)]; | A client receives user_id click event |
r (respawn) args: [user_id, x, y]; | A client receives user_id has respawned |
l (leave) args: [user_id]; | A client receives user_id has left the game |
j (join) args: [user_id, x, y] | A client receives user_id has joined the game, and user_id has spawned in the (x, y) position |
uid (user id) args: [is_valid]; | A client receives the response whether it is possible to find ‘log the user in |
gid (game id) args: [is_valid]; | A client receives if the user is part of the game (is user authorized) |
hit args: [user_id]; | A client receives a message that user_id has been hit / client can remove user_id from rendering it |
RediSearch indexes are registered on container startup in the redis/start_redis.sh
Created Redis Search indexes:
As with any Redis database, one of the most adored assets is its ability to transmit data between components with unrivalled efficiency. Yet in this application, without the exceptional latency speed that Active-Active provides, the game would simply not be able to function.
Gameplay is purely interactive, where users from all around the world react and fire missiles at other players. From start to finish, RedisGears deploys a sequence of functions based on the chronological order of the application set-up.
This is done with ease due to the efficiency of RedisGears which enables an active-active geo-distributed top-down arcade shooter application to be deployed.
If you want to find out more about this exciting application you can see the full app on the Redis Launchpad. Also make sure to check out all of the other exciting applications we have available for you.
Jānis Vilks
Jānis is a Big Data engineer who works at Shipping Technology.
If you want to discover more about his work and the projects he’s been involved in, then make sure to visit his GitHub profile here.