A Tribute to Galaxis | a Game Running on ESP32C3 With Bluetooth LE | a Game From 1980 by Ravensburger

by jmrtns in Circuits > Arduino

495 Views, 14 Favorites, 0 Comments

A Tribute to Galaxis | a Game Running on ESP32C3 With Bluetooth LE | a Game From 1980 by Ravensburger

game.jpg
Display.png
20240501_094358.png

Alarm at headquarters. Four spaceships are missing. By sending out radio signals in the different directions, the beam reports back how many of the spaceships are seen from a certain point. Who will find the missing spaceships first.

This is the basic idea of Galaxis, a game from the year 1980, initially created by Ravensburger. As a child I loved to play Galaxis and, what should I say, until now I do. On ebay you still can find some original games, but out of fun, I decided to make my own version of this game. And I really enjoyed it.

The final result runs on a ESP32C3, ESP32S3. I connected a round 1.18 SPI-display with 240x240 pixels and a rotary encoder. It makes use of Bluetooth LE to connect up to four players. For testing purpose I also added a preconfigured profile for a M5Dial, where the whole hardware is already contained.

Since I use LVGL as grapics library and I used Squareline Studio to generate the LVGL ui code. The background of the screen was created by an AI.

The sound was taken from my recall.


Here are the rules for the game

  1. Connect the devices to a USB power supply (for the future I have plans to use a LiPo battery). After the splash screen player A can start a new game by rotating the encoder wheel until "New" is display. Confirm with a press on the middle "enter" button.
  2. Up to three additional players can join the game by selecting "Join".
  3. If all players are connected, player A can select a coordinate and press enter. The search begins, a radio beam is emitted. After a few seconds, either a number (0-4) appears on the screen, or, if one of the ships has been found, a star will be displayed.
  4. The number indicates how many of the spaceships can be seen in a horizontal, vertical or diagonal direction.
  5. If the result was 0, the player can eliminate all intersections in horizontal, vertical or diagonal direction. To achieve this, the player plugs black pins into the holes on the board. There can't be any ships.
  6. For the numbers 1-4, the player plugs one of the yellow number pins into the coordinate on the coordinate system. 
  7. However, it should be noted that spaceships can lie in the radio shadow. This means that spaceships that in a direct line behind another spaceship are obscured by the first one and therefore cannot be seen. 
  8. Example: Assume there are two spaceships at points C1 and C4. 
  9. Then the radio beam from coordinate C7 only sees one spaceship (C4). The spaceship C1 is obscured. 
  10. From position C3, however, two spaceships can be seen. 
  11. The black pins can also be used to turn off coordinates where no more spaceships can be. So if a "1" already sees a spaceship, you can probably eliminate some coordinates. But be aware of the radio shadows as described before.
  12. If a spaceship has been found, this is indicated by '*', the player has another turn 
  13. If there is a number, it is the next player's turn 
  14. While the game goes further, the players draw their conclusions from the coordinates entered and continue searching at the intersections.
  15. The first player to find all four spaceships wins the game.
  16. Press the middle button to start a new game.


Translated with www.DeepL.com/Translator (free version)

 

Here you can download the original rules (in german language)


Schematic



Image of the Wiring

The display is connected to SPI pins of the ESP32 board.

We only use the wheel and the middle buttons of the rotary encoder. As I do not provide a PCB, the ground pin of the encoder is connected to D3 and set the pin to LOW. In this way the D3 pin is used as an additional ground pin. This makes crimping easier.

The speaker is optional, if you do not want to use sound, you can easily omit the speaker. But in the settings menu of the game you can disable sound at any time.


What is BLE?

Bluetooth Low Energy (BLE) is a wireless communication technology designed for short-range communication with low power consumption. It is part of the Bluetooth 4.0 specification and is used in various applications such as fitness trackers, smartwatches, medical devices, and home automation.

Key Features of BLE:

  1. Low Power Consumption: Optimized for devices that need to run on small batteries for long periods.
  2. Short Range: Typically operates within a range of 10 meters.
  3. Low Data Rate: Suitable for applications that require infrequent data transmission.
  4. Fast Connection: Quick to connect and transfer small amounts of data.


Code

Please find the code under https://github.com/jrmrtns/galaxis.

For the impatient, there is also a precompiled version available: https://jrmrtns.github.io/galaxis/. Just connect a ESP32C3 XIAO or ESP32S3 XIAO device to your computer, open the site in Crome or Edge browser and follow the instructions on the screen. Make sure you use the configuration and pinout from the schematic.


Some remarks to the code:

The code makes use the observer pattern for UI changes and BLE messages. In addition, it uses the MVC pattern for updating the UI.

Okay, but why making things so complicated? Here are some reasons:

  1. First of all, I do not want to have any calls to delay() methods, as this can lead to connectivity issues with BLE, especially on a ESP32C3.
  2. The game controller gets notifications from BLE and the encoder. This leads to an easier update mechanism.
  3. further there is no need for a separate single player view, as the "server" uses the same subjects to update the UI as the "client".
  4. decoupling: the controller does not need to "know" anything about the view. It updates only the current state of the game. The view doesn't need to know anything about the controller, the model either. You can easily change the design of the view, no need to change the controller.
  5. This leads to much cleaner code, with lesser side effects when changing any components.

In order to achieve this, there is a basic observer class. An observer subscribes to a subject, by registering.

The observer is implemented as an abstract class. The update method needs to be implemented in a concrete class. This will be later the view of the game.


In addition to this there is a subject class that notifies all registered observers (line 21-23) about changes to the subject. The observer only need to call the registerObserver method. When registering an observer, it is added to a list. Each observer of this list receives updates.


The UI follows the MVC pattern.

  1. The controller class, updates the data of the model. For example, the search result from the game logic, will be changed in the model.
  2. The model holds the current state of the game. The model is derives from a subject. Any change to a property (for example the searchResult) will notify all observers about the new searchResult.
  3. Last there is a view class wich is responsible to display changes. The view is derived from the observer, so any change to the model will be reflected in the UI. If the property 'searchResult' gets updated in the model, the view draws only the new search result on the screen.


The BLE service is constructed as a custom service. There is a BLECentralGame which behaves like a server, and a BLEDeviceGame, which doesn't have any logic and behaves like a client. Any request from the game will be sent as a request message over BLE and gets a answer as a response message.

For the BLE connection, the same observer/subject logic is used. The type GalaxisMessage is designed to exchange messages over BLE:

This GalaxisMessage holds the type of the message (e.g. a request or a response), the comand (e.g search, next_player) and the id of the receiver. In case of a broadcast message to all connected clients, the id takes the value of 0xFF (255). Some additional numbers (e.g. the current searchResult) can be added to the param1 and param2 fields.

Here is an example how a search request from a BLE device (client) gets answered by the BLE central (server):

Line 184 creates a new empty GalaxisMessage. From line 185 to 189 the new message is composed, and in line 190 the observers are updated.

In addition to this all connected clients will receive the GalaxisMessage as well, to update their model and view.

And here is where things finally come together: the controller from above is inherited from the MessageObserver. So it receives the GalaxisMessage to update the view.


3D Printing

I used Fusion360 to design the 3D files. They offer a free license for non comercial projects. This is my first real 3D project.

But: no 3D printer, no problem. On the bottom of this section there is a PDF file with the coordinates plan added, and you will be able to play on a sheet of paper, where you can note down the results.

Downloads

Supplies

The partlist do not contain so many parts. Keep in mind, these are the parts for one Galaxis deck. You can play with up to four decks, and you need the parts for each deck you like to assemble.

I mostly gave you the original vendor, but the parts are also availble at many online sellers in your country. The speaker is optional. As well the PCB for the rotary encoder is optional, but there is a snap in in the 3D files and it makes connecting the encoder much simlpler

Of course any ESP32 will work, but keep in mind that you have to adjust the SPI settings in the software sketch. As well the 3D printer files are designed to snap in the Seeed XIAO ESP32XX boards.

All links are non affiliate links. I do not earn any money if you follow the links.


Seeed Xiao ESP32C3 or Seeed Xiao ESP32S3

Seeed Studio | Seeed Studio

Adafruit ANO Rotary Encoder

Adafruit

Adafruit ANO Rotary Navigation Encoder Breakout PCB

Adafruit

240×240, General 1.28inch Round LCD Display Module, 65K RGB

Waveshare

Sourcing Map 0,25 W 8 Ohm (optional)

Amazon

PLA Filament

in black, white and yellow (but you can use any colors of your favorite brand)


I also used some additonal items and tools I had to hand:

  1. Wire
  2. Solder
  3. Soldering iron
  4. Crimping Tool (optional)
  5. Dupont Crimp Connectors (optional)

Print the Parts

Print the parts of the game:

  1. 1 x Boden.stl (rotate by 180 degrees)
  2. 1 x Deckel.stl
  3. 1 x Display.stl (lay flat in slicer)
  4. 1 x Inlay.stl. (rotate by 180 degrees. For this print supports are needed)
  5. 1 x Platte.stl. Change color after the layer, where the coordinate system begins
  6. 5 x Pin-0
  7. 10 x Pin-1
  8. 10 x Pin-2
  9. 10 x Pin-3
  10. 5 x Pin-4
  11. 50 x BlackPins (for disabling coordinates)
  12. 4 x BlackPins (but print it in white. These are used for the missing spaceships)

As we need to print the number pins with the number on top, I had some issues with adhesion. For this reason you probably will need support and a raft.

Preparation of Cables

assembly-01.jpg

Prepare three cables. This is optional, you can solder cables directly to the board, but be aware: maintanence getting harder and you have to place the cable from encoder to the board (Step 3) before soldering.

If you have the possibility to crimp conectors to cables, its getting easier to assemble. Another possibility is to use Dupont Cables and remove one end.

Connect Rotary Encoder

assembly-02.jpg

Solder the cable in the middle (from the image in Step 2) to the rotatry encoder

Place Cable of Encoder

assembly-03.jpg

Place the cable between the gap of the bottom side of Inlay, and let the rotary encoder snap into the inlay.

Place Inlay in the Case

assembly-04.jpg

Insert the inlay into the bottom of the case.

Soldering

assembly-05.jpg

Solder the remaining two cables directly to the pads of the board.

Place ESP32 Board

assembly-06.jpg

Let the ESP32 board snap into the bottom of case. Optionally fix it with a drop of glue, to improve stability when connecting the USB cable.

Connect Display

assembly-07.jpg

Connect the display and snap the display into display holder.

Get Code

Clone the code from my GitHub repository.

git clone https://github.com/jrmrtns/galaxis

Build and Upload

VSCode.png

To build the code, you need Visual Studio Code on your laptop. The code makes use of the PlatformIO Extension. This Extension should be installed automatically if the folder "Galaxis" is opened in VS Code.

Build and Upload Software

assembly-08.jpg

Build and upload the software to the chip, snap the display holder into the case and connect power to USB-C.

Specific Hardware

Settings.png

The code should work on any ESP32 board. In the platformio.ini file you have the possibility to adjust SPI settings for your specific board.

Here you can also add the build_flag for the UI language (see next Step). Currently available is english (default) and german.

Additional Translations

Translations.png

In the include folder there is a settings.h file in the code. Here you can add additional translations to any language you need. Translations in english and german are provided. You can append -D DE to the build_flags in platformio.ini to select the german UI (see previous step). If you don't append any language to build_flag, the default is english.

Don't Like My UI?

F9M68PQM06Q328K.png

To design the screens in a visual way, I used SquareLine Studio. For private projects is a free license available, but a subscription is required. In the Design folder you find the project files. You can change the screens and update the UI by exporting the UI to the project. The current background image is generated by an AI.

Play and Have Fun

The headline says it all. So...