Doppler

A ray-traced mobile multiplayer game built around a hand-rolled engine.

The Doppler browser game interface showing a fight in space.

2026 update: I recently revived the game: made the characters’ eyes less creepy and improved the gameplay. I also stopped paying for the original decla.red domain, so I rebranded the game as doppler. It’s playable at doppler.schmelczer.dev1.

My BSc thesis was on a novel ray-tracing renderer, SDF-2D2, and this project was about eating the pudding. The concept is simple: the scene is set in space. Two teams have to conquer tiny planets and can also shoot at the other team. Points are given based on the number of planets controlled, and the first team to reach a predefined score wins.

Design patterns

Given I already had a bespoke renderer, I figured: might as well write the game engine too. How hard could it be? Fairly hard, turns out. However, there were a few design patterns which made it tractable.

Both the game client and server are written in TypeScript (TS), which made it easy to define a third TS package: a library which sits between them and contains the shared logic. So, for example, the wire schema and even the movement logic are defined in one place. This eliminates a class of bugs caused by discrepancies between, for instance, the server-side movement physics and the client-side prediction of this movement.

When it comes to the game objects, I decided to borrow inspiration from Smalltalk’s message passing. Objects send events to other objects: these can be broadcasts, messages limited to an area, or perhaps messages between two objects that physically overlap. The objects can then declare which messages they’re interested in receiving. This includes the concept of “doesNotUnderstand”3, which allows messages to be passed on to nested objects. This all results in a very decoupled system where everything can interact with anything it wishes to through standard messages without having to implement #objects × #interaction methods.

Conclusion

Ultimately, the game proved that the renderer works in practice. It was a great deal of fun drawing every object with signed distance fields, and I was delighted that the rendering just worked by the end. Unfortunately, I didn’t continue working on the game as the gameplay didn’t feel interesting to me even after I’d tried tuning it and adding/removing features. So I had to realise that I’m just not fond of 2D games after all, and I lost the motivation to improve it further. The technical challenges were fun, though.

  1. https://doppler.schmelczer.dev/
  2. SDF-2D: https://schmelczer.dev/articles/sdf-2d-ray-tracing/
  3. “doesNotUnderstand”: https://wiki.c2.com/?DoesNotUnderstand

Searches titles, descriptions, and the full text of every article.

    to move to open Esc to close