Tiled Of It - October 2022 Postmortem


State of the project

"Tiled of it" (working title: "Fragment Fuser") was born during the Devtober 2022 jam. I wanted to pick a project I could complete in one month without many sacrifices.

Gameplay at the end of the month

The hot questions were:

  • Can I make a card game where you combine cards to make words?
  • How do I pick which text goes on each card? (Is it even possible to have a deck of cards that makes hundreds of words?)
  • How do I make it fun to play?

For small projects like this, I like to lean on some of my strengths while exploring new curiosities and weaknesses.

The blend was supposed to be:

Lean on familiar stuff:

  • Make it a word game
  • Add networking support (spoiler: the way I implemented it was less familiar than I had planned)

Explore unfamiliar stuff:

  • Make it a card game
  • Use Unity UI controls and callbacks in more depth
  • Use networking hooks within Unity. I landed on Evan Lindsey's Unity-WebGL-SignalR wrappers.
  • Use multiple projects. For example, I'd have a Console app for puzzle simulations and deck generation, a Web app to host the SignalR hub, a Unity library, and a Common library that the other projects referenced.

Since my previous project (Punchy Jam Plant) focused on music and art, I would rely on non-original sound and image assets. For example, I would use Kenney assets for audio and cards.

What went wrong?

My biggest struggles stemmed from making this an online multiplayer game. I have a strong Web and network-related background, but not in this particular stack. I hit a lot of interesting surprises along the way, which ate more time than I had planned.

Off the top of my head, surprises included:

  1. ASP.NET Core SignalR syntax is different than what I'd used in ASP.NET / .NET Framework. This forced me to take detours, like learning about how ASP.NET Core dependency injection since I couldn't access a singleton.
  2. Unity seems geared toward single-threaded apps, not async/background-thread stuff. Some SignalR callbacks fired on background threads and led to odd quirks. For example, if I updated a TextMeshProUIGUI.text property in a background thread, the change would not be reflected in-game until the object became dirty some other way (such as by re-positioning it). Life was good once I refactored my logic to queue these commands for the main thread.
  3. I'm grateful for the Unity-WebGL-SignalR hooks because I wouldn't have been able to create them myself. But I hit some connection-resiliency-related snags. For example, there didn't seem to be a way for the app to learn that there was a connection error. And the WebGL wrapper's callback dictionary was designed to only be used once (via a static Dictionary and Add calls), whereas I would be replacing callbacks over time. I hacked that plumbing in, so users were less likely to encounter a silent network error, and they were able to connect to the server multiple times in the app's lifetime.

It was exciting to overcome each hurdle, and I'm glad I learned a lot, but it took so long.

I hope you never see this connection error. But if you do, remember that I did it for you! :D

I didn't rely on stock art as much as I had planned. A few Kenney icons stuck around, but most were replaced by crude drawings. I was also hoping to add more sound effects and music but ran out of time.

I meant to create avatars for each player. I also kept changing the "gameplay" art and never hit something that felt right.

Avatar doodles

A wood-backed gameplay screen with more rectangles. I kind of miss it.


What went right?

The game concept worked better than I expected.

I was relieved to generate a deck of potent cards early in the month. The poorest-performing card in the 50-card deck could still pair with 18 other cards. The game idea was viable. Whew.

Deck generation worked like this:

  1. Split words into their substrings
  2. Make a list of popular substrings (used by many words)
  3. Randomly draft some substrings from that pool, and use them as cards in a deck.
  4. Score each card based on how many other cards it combined with
  5. Score the deck based on how many words you can make by combining two cards.
  6. Mutate the deck into a competing deck: copy the original deck, remove some [random, poor-performing, etc.] cards, and replace them with alternative cards.
  7. If the new (mutated) deck scores better, it becomes the new "best deck."
  8. Keep mutating the "best deck" until you can't.

It also helped to have a game engine and simulation before diving deep into the UI. I wrote a command-line app that simulated playing the game. This allowed me to track things like:

  • How often is a player forced to discard because they can't make a play? We want to keep this low.
  • Do the rules favor the first player or the last player?
  • Should players take turns in a circle, or play "as fast as they want", or some other order?

...and then tweak the rules to overcome issues.

Early simulation of a single 3-pile game.

The v0.5 prototype still has a bias in favor of the last player, but it could have been so much worse. :) Long-term, we can avoid the bias by playing multiple rounds, and giving each player a round in Nth place.

Originally, I planned to have multiple single-word piles, where you could add [and remove, and re-order] a card to form a new word. This was complicated to explain, and caused more discarding than I was comfortable with. Since I hadn't invested much in the UI or networking yet, I was able to flip to a grid structure without a ton of rework.

Finally, it helped that my family play-tested the game. This encouraged me to continue and made me aware of usability issues. 

What's next?

In the short term, I'll be taking a break to avoid burnout.

After that, I might revisit the backlog. At the top of the backlog are topics like:

  1. Improve graphics
  2. Add sound effects and music (and volume controls, for folks who don't want this stuff)
  3. Refine the dictionary (some words and definitions and explicitness aren't quite right)
  4. Add more fanfare around points and winners at the end of the game
  5. Improve the online multiplayer experience, such as by letting players vote to skip an away-from-keyboard player's turn.
  6. Track local achievements, like when a new word is built.
  7. Allow players to configure the bot's difficulty
  8. Local multiplayer

If you try the game, please drop a comment! I appreciate your constructive feedback!

Maybe next time, we'll learn more about the fabled "Dictioncanary"

Leave a comment

Log in with itch.io to leave a comment.