Building My Unity State Machine with MVVM + UniRx | Gobara Devlog Ep 3


Hey everyone, it’s From QC with GameDev!

For this devlog, I want to dive into something that turned out to be a big part of my project’s architecture — keeping track of which state the game is in and how I manage transitions between UIs. This became really important once my project grew beyond a single screen and started including menus, settings, and gameplay panels that needed to talk to each other cleanly.

Early on, I realized I needed a clear way to represent where the game was at any given moment. Was the player on the main menu? In the settings panel? Exploring the dungeon? To handle that, I implemented a scene-level state machine. The idea is pretty simple: each state represents a point in the application (in my case, a specific UI panel), and transitions define how the player can move between those points.

For example, if I’m on the Quit panel from my main menu, I can define that as the Quit State. The transitions out of it could be something like “OK” or “Back.” That’s it — super straightforward, but surprisingly powerful. What I like about this approach is that it ties the UI and the game state together. I can always tell what’s happening by checking the current state, and it makes debugging way easier since every UI action triggers a well-defined transition.

Now, once I had this system in place, I realized I wanted the entire project to follow a more deliberate structure. I didn’t want to end up in the common Unity trap of having a bunch of “Managers” and “Handlers” all talking to each other in random ways. That’s where the MVVM (Model–View–ViewModel) pattern came in.

I chose MVVM because it gives a really nice separation of responsibilities. The Model is where all the data lives — stuff like player stats, inventory, or the current dungeon layout. The View is what the player actually sees and interacts with, all the UI elements and visuals. And the ViewModel acts as the bridge between the two. The key rule here is that the Model doesn’t know about the View, and the View doesn’t directly touch the Model. They only communicate through the ViewModel.

Once I started applying this, my workflow became much more organized. I started thinking of my UI as a collection of independent Views — each panel in my game (main menu, quit panel, settings, in-game HUD) would handle its own showing and hiding behavior. Instead of one giant UI manager controlling everything, each View became responsible for managing itself and reacting to changes in the ViewModel. This gave each panel more autonomy and made it easy to add or remove UIs without breaking the rest of the system.

My state machine itself was implemented as a dictionary mapping one state to possible transitions, and those transitions mapped to the next state. So if I’m in state S1 and receive transition T, I know I should go to state S2. It’s a simple lookup, but it made the flow between panels very predictable.

To keep track of my design visually, I used Draw.io for flowcharts and class diagrams and even dropped the .drawio file right into my Unity project so I could easily reference it as I built. It was really satisfying to see everything slowly click into place — each View, Model, and ViewModel connecting together like pieces of a puzzle.

Along the way, I noticed some patterns emerging. Certain components, like my enemy display, treasure display, or item display, were being reused in several places. Instead of duplicating code, I extracted these into their own reusable View components (for example, EnemyDisplayView). This way, I could have a single, consistent way of showing that type of data anywhere in the UI.

The same idea applied to my ViewModels. Sometimes several Views needed to access the same data — for instance, the currently active player or a list of ScriptableObjects that represent characters. So I made shared ViewModels for those too, like a RoundViewModel that handled the logic of whose turn it was, or a CharacterSOViewModel that centralized access to character ScriptableObjects.

Another interesting evolution in this process was how I handled ScriptableObjects. Instead of passing them directly around between Views, I’d often just pass an identifier (like a string name) to the ViewModel, and let the ViewModel fetch the correct ScriptableObject internally. This reduced coupling and made everything a lot cleaner. Basically, my rule became: never pass around ScriptableObjects when an ID will do.

One last big change I made was integrating UniRx, Unity’s reactive programming library. Before that, I was manually raising C# events every time a variable changed. It worked, but it got tedious fast. With UniRx, I can define reactive fields — and whenever a value changes, all subscribers automatically get updated. It cut down a ton of boilerplate and made my data flow feel a lot more natural.

Overall, this part of development was a huge leap forward for how I structure my projects. Building the state machine and implementing MVVM forced me to think carefully about how everything communicates. Every UI panel became its own little self-contained unit, reacting to data changes through a clean pipeline.

Next time, I’ll talk about how this whole system ties into actual gameplay — how the state machine controls turn flow and how the player’s actions update the ViewModel and, in turn, the UI.

Leave a comment

Log in with itch.io to leave a comment.