Word Flow: The Technical Breakdown
- Harshita Shetye
- 5 days ago
- 3 min read
I built this game from scratch in Unity and C#. From the start, my focus was on writing clean, scalable code to create a solid foundation for a polished core loop.
1) The Foundation: A Smart and Flexible Grid
Every word game needs a board, so the first task was building a flexible grid that I could easily resize and manage.

A central GridManager.cs script acts as the architect for the entire board. When the game starts, it builds the grid cell by cell, creating Tile objects from a single prefab. The state of the board is tracked in a simple 2D array (Tile[,]).
This clean internal map proved essential for logic like refilling the board after a word is cleared.
To ensure the board always looks great, a dedicated CameraController.cs script automatically centers and zooms the camera to perfectly frame the grid, regardless of the player's screen size. This creates a responsive experience that feels right on any device.
2) The Feel of the Game: Iterating on Player Input
With the board in place, I focused on the most important part of any puzzle game: the "feel". My initial implementation used simple mouse-detection events on each tile. It worked, but after playtesting, I realized the mechanic felt stiff and unforgiving.
This led to my first major iteration, focused entirely on user experience:
Making Diagonals Easy: Initially, the square colliders on the tiles made diagonal swipes feel clumsy. By swapping them for CircleCollider2D, the hitboxes became more forgiving, and the game instantly felt smoother and more responsive. It's a small change that made a huge difference to the feel.
Adding Forgiveness with Backtracking: I refactored the WordBuilder.cs script, which manages the player's current selection. I added logic that allows players to correct a mistake by simply sliding their finger back over a letter to deselect it. This is the intuitive behavior players expect from a top-tier mobile game and was crucial for making the core loop satisfying instead of frustrating.
3) Making it a Game: Fast and Flexible Validation
The final piece was connecting the player's input to the game's rules.

This was a key technical decision. Instead of a simple list, which would be slow to search, the script loads over 80,000 words into a HashSet data structure. A HashSet is like having a perfect index for a dictionary - it can tell you if a word exists almost instantly. This guarantees that word validation is lag-free.
Furthermore, the script is decoupled from the data source. I exposed a slot in the Inspector for the .txt dictionary file, meaning a designer could easily swap in a different dictionary (for another language, perhaps) without ever needing to change a line of code.
4) The Meta-Game: A Scalable Decoration System
The word game provides the fun, but the decoration system provides the long-term motivation for players. I designed this system to be highly scalable and easy for a designer to add new content to.

The core of this is the RoomManager, which controls the visual state of the player's room. Instead of dynamically creating items when they are placed, the room is pre-filled with every possible decoration, all set to "invisible." When the player buys an item, the RoomManager simply "reveals" it. This "pre-placed" approach is incredibly robust and avoids the complex positioning bugs that can come with a free-form placement system.

To make it efficient, the manager doesn't search a slow list to find items. On startup, it automatically scans the room for all DecorationSlot components and organizes them into a Dictionary. This is like creating a perfectly organized filing cabinet, which allows the manager to find and activate any specific decoration almost instantly, ensuring the system stays fast even with hundreds of items.
5) Clean Communication: An Event-Driven Architecture
One of the biggest challenges in game development is preventing your code from becoming a tangled mess, where every script has a reference to every other script. To solve this, I used an event-driven architecture.
Think of it like a radio broadcast. The ScoreManager acts like a radio station. When the score changes, it doesn't need to know about the UI text that displays it. It simply broadcasts a message: "The score is now 1,000!". The UIManager acts like a radio receiver tuned to that station. It hears the broadcast and knows its job is to update the text on the screen.
This creates a clean, one-way line of communication. The ScoreManager is completely decoupled from the UI, and we use this pattern throughout the project:
The PlayerInventory broadcasts an OnInventoryUpdated event, and the RoomManager listens for it to update the room.
The individual ShopItemController buttons broadcast an OnPurchaseAttempted event, and the ShopManager listens for it to handle the transaction.
This event-driven approach makes the entire codebase modular, scalable, and much easier to debug. Adding a new feature that needs to know the score is as simple as tuning another "radio" to the ScoreManager's broadcast, without ever having to change the ScoreManager itself.
Comments