If you don't want to read any of this boring information and just want to play a cool game, that's fine — here's the link!
There’s a fun dice game called Toss Up! that my sister, brother-in-law, and I like to play. It's a really simple game that's made up of ten multi-colored dice, each with green, yellow, and red faces.
Toss Up is played by rolling all ten dice. Every die that lands on green is set aside and you keep rolling. You keep rolling until all ten dice have landed on green or you roll a red die with no greens. Once all ten dice have landed on green, you can start a new round, adding to your total for the turn. At any point, you may decide to bank your points so you don't lose them, and let the next player have a turn. This cycle goes on until someone reaches the target score.
Building Cube Toss!
Last weekend we had a huge snowstorm, and I had a lot of time on my hands. I had been thinking about trying to build my own version of Toss Up for a while now, and this was the perfect opportunity.
I wanted to build the game so people on different devices could play together, and I wanted the game to feel smooth, with the UI updating as players took their turn.
I've built a couple mini-games before, and I've used those opportunities to play around with frameworks that I'm not familiar with. This time I stuck with ol' reliable — SvelteKit running on a NodeJS runtime.
Shareable Rooms
My goal was to make this a multiplayer game, with as little overhead as possible — I'm not planning on this being the next chess.com. I didn't want to go through the hassle of creating and managing a database. In order to achieve this I used JavaScript's Map object to hold all the active rooms and their info. Every time a new room is created, a new entry is added to the rooms map.
rooms.ts
The rooms map gets initialized when the Node process starts, and it lives as long as the Node process does. When the process gets restarted for any reason, the rooms get emptied. Since these are generally quick games, and I'm not restarting the server every five minutes, this is an acceptable trade-off.
Live Updates
To achieve the real-time updates I was hoping for, I used server-sent events (SSE). Server-sent events allow your front-end to continuously listen to your server, and update the UI as updates are available. So while Geoffrey is playing his turn on his iPhone, Elizabeth sees what's happening on her Window PC.
Unlike websockets, server-sent events are only one directional so while you can listen for events from your server, you can't send events. In Cube Toss I'm getting around this limitation by simply sending data via POST requests.
Final Thoughts
This game was a lot of fun to build. I'll probably tinker with it a bit more here and there so it may look different in a few days. If you've ever played Toss Up, you’ve got to give Cube Toss a try!