Creating a multiplayer speed typing game using Flask, SocketIO and Celery

Liad Oz
Analytics Vidhya
Published in
4 min readMar 2, 2021

--

typefight match

Lately I have been playing multiple speed typing games but I got frustrated about how generic they are, at the start of a game you wait for other players to join presented with a text, when the game starts you type as fast as you can and when you finish you can see how you compared to the others. While it is fun to try and get first place there is no real reason to play online, there are no strategies and no player interaction, the fastest will always win.

Six months ago the idea of typefight came to me, and since then I have worked on it, making a lot of mistakes along the way, eventually coming to the setup I have right now. In this article I would like to show how typefight is built. I hope it would help anyone who would like to create an online game using python.

About typefight

typefight is a competitive speed typing game, unlike most typing games, players can interact with each other and may choose different typing order which allows a unique game play experience with different strategies.
typefight was inspired by tetris99 alongside top speed typing games such as
ztype and typeracer.

How to play

Section of the player view

Each player view is split to 3 parts, the attack words, the defend grid and the
accuracy bar. In order to win the game the opposing player’s grid must touch the accuracy bar, with it’s size set according to how much mistakes the player have made over the last 100 keystrokes. The defend grid will grow over time with new words either coming from the game advancing mechanism or from a rival attack.
At any point a player may choose which word to type (in the defend grid the word must have no other word above it) once the first character is typed the player may not switch to another word.

The game loop

The core of each game should be the game loop, which handles input, advances the game and then renders the changes. Using the game loop makes it easier to advance the game and render player data. Here is the game loop that I built:

Since each match should have a different game loop some sort of concurrency needs to be used, since in python you can’t have multiple threads run in parallel I chose to use Celery with Redis as a message broker, this enables creating the game loop in a different process and communication with the server.

Player communication with SocketIO

Flask-SocketIO is used to communicate between the server and the players. When a player wants to start a game the frontend code connects them to the SocketIO server and saves their session id which will be used to send input. Once a match with another player is made both players are put in a SocketIO room with a specific match id, this makes it easier to render data to both players.

Now we have the full picture of the communication process, a player starts
typing the letter ‘a’ the browser sends it using SocketIO it reaches the server
which publishes the data in redis, then a game loop gets the data and advances the game. When the server wants to render changes to the player it publishes redis message which the server picks up and sends using SocketIO to the player browser who is responsible for rendering it.

Frontend

The website itself is pretty simple, it uses the MVP design pattern and written
in Typescript, Gulp is used to compile and bundle the code into a JavaScript
file. The game rendering is done using PixiJS creation engine which allowed me to easily create the views and animations.

One of the major I have faced during writing the frontend is the ping induced by the server which was 63 millisecond, in terms of the game loop it means that when a user sends input to the server the loop will run twice before it is fetched, additionally a bad or distant connection would make the game unplayable. This issue is solved by adding some of the server logic to the frontend to predict what should happen next, for example, saving the words that can be typed so the client code can know if user input is a mistake or not.

Something that worked and one that didn’t

Early version of typefight using Tkinter

The biggest most time consuming mistake I made was not using a game loop from the start which caused me to make drastic changes in the game code design twice. Once I implemented the game loop the code became more streamlined, it was easier to implement bots, interaction between players and rendering player data.

A thing that helped me a lot was watching out for production since the early stages of development by keeping notes of everything that can go wrong or when a certain library recommends. In addition to setting up the production server when most of game logic is complete which helped spot problems earlier.

--

--