← Back to overview

The Amazeballs ball game

A multiplayer game where players compete to be the first person to get their ball to the end of a randomly generated maze.

Published on May 27, 2025
The Amazeballs ball game

The game starts with each player positioned at the top-left corner of the maze, with the objective of navigating and reaching the bottom-right corner, where the finish hole is located. To control their ball, players hold an ESP32 chip in their hands, which they need to tilt to move in the direction they want to go. The further you tilt this controller, the faster the ball moves. However, watch out, as the maze features obstacles in the form of holes, which will stun you for a few seconds when you fall into them!

This project was made in a group of four people at the Fachhochschule Vorarlberg in Dornbirn, Austria. I was involved in working out a lot of the parts in Python, like network communication, maze generation, splitscreen support and camera movement. We made substantial work on the project during the ÖH Hackathon, which you can read more about here.

Architecture

In terms of architecture, the project can be divided into three parts: the ESPs for each player, a central server for managing the game state and the game view (the ‘frontend’). All the communications between the different devices are performed using UDP over Wi-Fi, and there are a pre-defined number of players that can join the game to keep the packet sizes consistent and under control. Multiple ESPs and game views are supported per game, but only a single server (in our case it was a Raspberry Pi) manages the state.

The ESP code is written in C and compiled using the VSCode extension ESP-IDF, while the server and game view are both written in Python. To display the actual game for players to see, the Pip package ‘pygame’ is used and both the server and the game view use an additional package called ‘netifaces-plus’ to make it easier to get the primary network interface for broadcasting packets.

Since both the server and the game view are written in the same programming language, they can share some critical code for things like maze generation and protocol definitions. One of the coolest things for me is the maze generation code: it uses a pseudorandom generator based on a random seed determined by the server, which means the seed can be used on both the server and the frontend to generate the exact same maze. This way, we don’t ever need to send wall configurations and hole positions, as those are generated deterministically with the same seed and same generation code. Just send the seed from the server to the frontend(s) and they can figure it out! For the server, knowing the exact maze configuration is important to determine wall and hole collisions, while the frontend needs it to actually display the maze for the players.

The protocol definitions are also interesting, however. Since I didn't know a lot about how to work with packets in Python, I decided to effectively write my own simplistic packet library based on the Python ‘struct’ package. No pickle or scapy were involved.