Awesome-Sauce Conflict Resolution System Unity app post-mortem
The Awesome-Sauce Conflict Resolution System is a light "tabletop" role-playing game system which I invented. During a time when an online role-playing community which I oversaw was considering a reboot (we eventually just shut it down), I wondered if we might start using my system for our combat. I'd had some limited success with running scenes that used the system by manually calculating the needed dice rolls and tracking the various characters' health and such, but I found that other players had difficulty remembering the rules of the system and I had to explain things over and over. I thought that automating the system and giving it an interface that lays out all the options for a player might alleviate that issue quite a bit, especially when the more advanced mechanics are used. I especially wanted to have a visual representation of the possible roll outcomes (which end up in bell curves when there's extra dice involved) so players could get a better sense of what they gain by doing different moves. I figured, most of what would be needed could be achieved with simple GUI stuff, and I already knew basically how to do that in Unity thanks to my previous Bombercan project, so it shouldn't take too long to knock out a Unity app for this, right?
Yeah, no, GUI-based stuff can take a lot longer than I realized. X) Especially when you throw networked play into the mix. It took over three years of an-hour-or-two-here-and-there development for me to finish this project. Still, I learned quite a bit in the process.
What Went Right
Learning Model-View-Controller
One of the goals I set for myself early on in this project was to learn the model-view-controller programming pattern. I'd heard of it, but never had any practical experience with it. So I did some research and found an MVC library for Unity. I'm not sure how closely it follows typical MVC practices, and it took me a while to really wrap my head around how to use it. Eventually, though, I was able to create systems for each aspect of my GUI where the data, the display, and the control logic were all nicely compartmented.
Learning Networking
This is probably the aspect of the project which increased my potential value as a game developer the most. Making games (or any software for that matter) that involves networked communication is a beast. You have to think about not only how things work in the program itself, but how some other instance of the program might affect it, how to ensure that they don't become out of sync with each other, and what to do when there's a disagreement between them. I ended up with a very "mother may I" approach to a lot of things: the local instance will send a request to the server, the server will examine its own game state (which may differ from the local instance's because of messages it has received from other instances just before now), and then the server will send out a response saying "Okay everybody, this instance just did X" or "No, you can't do that because Y".
Finally Getting a Grasp on Unity's Layout Groups
This actually happened late in the project. For a good while I just manually set the size and positions of GUI elements, because I'd never gotten the hang of Unity's Layout group and element components. Eventually, though, I ran into something which forced me to figure it out.
The main thing that tripped me up is that if you want to have GUI elements that stretch to fit their contents (like a chat bubble that gets bigger the more text it has in it) and put those inside another GUI element that also stretches (like a ScrollView which holds chat bubbles and stretches to accommodate more of them as they appear), then you need a Content Size Fitter component -- but ONLY on the top-level GUI element! In this example, the Content Size Fitter goes on the Content element within the ScrollView, causing the chat bubbles within it to expand to their needed height and the Content to stretch to accommodate them.
I still don't fully comprehend why some Layout components work the way they do, but at least I've got examples of them configured to work the way I like. That way I can copy-paste them into new projects and skip the hassle of experimentation.
What Went Wrong
Severely Underestimated Time and Effort
As mentioned in the intro part of this post-mortem, this project took waaaaaay longer than I'd been expecting. Frankly, I'm not sure it was really worth the time investment. If somebody had been able to tell me from the start how long I'd be working on it, I'm pretty sure I would have chosen to skip it and work on something else. There were also times when I wondered if cutting the sunk cost and leaving the app incomplete would be better than spending the remaining effort to complete it, and in retrospect, yeah, it may have been. But then, that's the trouble with learning new things -- you don't know how long it takes to do something until you've done it at least once.
UNet Got Deprecated
When I started this project, the standard way to do networked games in Unity was with a library called UNet. It was a little difficult to work with for my purposes because it was designed to keep Unity's physics objects and simple variables attached to those objects automatically synchronized between networked game instances. What I needed was more of sending and receiving custom messages. Finding out how to do that within the UNet system was the biggest struggle of the project. Once I did, though, UNet at least made it easy to get game instances connected and talking to each other.
And then UNet got deprecated. X) Technically I could still use the library, but the matchmaking service Unity provided for it was shut down. This meant that I could only use it for local area network play. I spent a lot of time trying to find a workaround to enable Internet play, since a large part of the point of this app is to let online role-playing communities use the ASCRS. There are alternative Unity networking libraries out there, including one called Mirror that's essentially an unofficial continuation of UNet, but the bottom line is that I would need to somehow provide my own match-making service. I'm pretty sure that would be possible, but it's not worth the extra effort needed when I'm already aching to shove this project out the door. As a pittance of support, I determined that the app works fine over the Internet if the players can simulate a LAN using a Virtual Private Network, and I included some direction in the manual about that.
Inconsistency About Notifications Vs. Direct Method Calls
One of the features of the model-view-controller pattern I was trying to use is notifications. The basic idea is that one part of the code sends out a sort of "message", and then other parts of the code pick that message up and react to it in a special OnNotification method. The timing of that reaction is a little hazy, but it allows different parts of the application to do whatever they need to based on the notification, and they and the part that sent out the notification don't really need to know anything about each other. For example, when a button is clicked, it sends out a notification saying "I've been clicked", and then it's up to something else -- typically the controller code for the panel which that button exists inside -- to figure out what to do.
I didn't always remember to use notifications, though. There were parts of the code where I just called methods directly, like telling a panel controller to reset itself. That sort of thing especially happened a lot in the main control logic -- I'd get a network message about something being changed, and I'd send direct orders to the relevant panel controllers. It all works, I'm just not sure I was following best code practice with that sort of thing.
Got Lazy Toward the End
There are a number of ways I got lazy as the end of the project approached. I cut a few planned features, like the ability to filter chat messages according to what type they are (some of them, for example, are minutia about changes to actions as a player prepares them), sending private messages to particular players, and saving and loading specific characters instead of just the state of an entire scene. I'd have liked to replace the clunky DO AN ACTION panel with buttons for ATTACK and DEFEND on each specific character, that would make it more intuitive. And when I made the title menu (ironically one of the last things a game developer typically gets around to), I didn't bother with the model-view-controller system, I just made a single controller class for the menu and tied the buttons directly to methods in that class. Considering what I've said above about how the project outlasted its worth, maybe it's best that I cut what corners I did.
Files
Get Awesome-Sauce Conflict Resolution System
Awesome-Sauce Conflict Resolution System
A light "tabletop" RPG system implemented in Unity
Status | Released |
Author | AubreyTheBard |
Genre | Role Playing |
Tags | Dice, Multiplayer, tabletoprpg, Unity |
Languages | English |
Accessibility | Color-blind friendly |
Leave a comment
Log in with itch.io to leave a comment.