The incredible art of over-engineering: Everybody Plays Golf Post-Mortem
Over-engineering: a plan where one adds unnecessary complexity in implementing a simple feature for a technical project. In the same way it’s dangerous to plan a game with too many features in a game jam, over-engineering sinks a lot of projects, personal or otherwise. While we’ve set out to make a satirical game about energy systems, thus providing us an excuse to make a terrible game, we admit that over-engineering has made our latest Ludum Dare game worse than we originally planned. Here’s our post-mortem of Everybody Plays Golf, an overly complex game with an ironically simple premise.
What is Everybody Plays Golf?
Everybody Plays Golf is a tongue-in-cheek riff on the Twitch Plays genre. In this online game, anyone with an internet connection fights over the control of a single golf ball, as they attempt to putt it into the hole at the upper-right hand corner of the stage. The catch is that there is an energy system, à la Farmville and other free-to-play social games, that prevents the player from putting more than 7 times. While the game claims one can recover energy over time, this is actually a bit of a white lie: every player’s energy does not recover until the golf ball falls into the hole. Once it does, everyone recovers all 7 units of energy, and the ball resets its position back to the bottom-left corner of the map.
It’s simultaneously an experimental game about cooperation, a satire on social games, and a technical nightmare for the sole programmer who put all the pieces together.
What went right
Using game jams as an opportunity to learn something new
We’ve always used game jams to learn something new, such as Blender modifiers, Unity path-finding, story-writing, procedural generation, and so forth. This time was no different: we decided to take what we learned on hack.source.net to make a networked game where everyone controls the same object. In this case, we’ve taken the time to learn all the moving parts necessary to create an asynchronous networked system: making a server that simulates the physics of the golf ball, using a free trial of Google Cloud to host said server, creating a client that calculates the direction the user wants to putt the golf ball, setting up a MySQL database to store all the players’ putting directions, and code a few PHP scripts to get access to MySQL databases. It’s a strange framework that gets the job done and forces us to learn and re-learn some critical professional skills, such as SQL, Get and Post requests, networking, etc.
A goofy tutorial
We also took a stab at looking into TextMesh Pro assets from the Unity asset store. While playing around with it, it came to us this asset can be used to create a 90s advert like tutorial. Thus, our cheesy tutorial was born: a ridiculously positive and verbose set of instructions on how to play the game…even though the game is simple enough for one to figure out how to play with enough experimentation. Putting this tutorial in was a bit of a risk at the time because the server wasn’t working. We’re glad we put the time in to improve the presentation of the game.
Making incremental builds
As usual, we started with building the basic models and scripts to create a prototype where one controls a golf ball with a mouse click. By starting very small, it was easy for us to detect problems early before building new features on top of this game. This vital process kept all the moving parts manageable by keeping the project simple and stable.
Not letting non-working parts prevent us from progressing
For the longest time, the server part of the game was not working: despite having it uploaded and running on a static IP address to a Google Cloud virtual machine, the server would not start listening to a port. While this did delay the development by a significant factor, it didn’t keep us from improving other parts of the game that needed attention, including graphics and information sent and stored into the database. Even though the game was unplayable for the grand majority of the development (at least in the way that was intended), we’ve still managed to find workarounds or working on portions of the game we’re more well-informed of while we’re trying to figure out what went wrong.
What needs improvement
Overly complex design
The full details of how Everybody Plays Golf works goes as follows:
- The client: the PC/Mac/Linux build that the user downloads. It does the following:
- Connect to the server. Once connected…
- Sync the position of the golf ball in real-time,
- Syncs and stores how many times the server has recorded the golf ball fell into the hole. This is used to check if the player’s energy needs to be refilled when they open the application again.
- Locally how much energy the player has. A unit of energy is depleted each time the player clicks.
- Send a Post request to a PHP script, sending information about the name of the player, and the direction they’ve putted.
- The server: a Unity headless Linux build running in a Google Cloud server. It does the following:
- Spawn the golf ball, and monitor its movement and physics.
- Send a Get request every 0.2 seconds to a PHP script, receiving information on the last set of putts it hasn’t read yet.
- Uses all the putt directions it receives, and applies them to the golf ball. That’s right: only the server moves the golf ball directly!
- Sends a Post request once the golf ball has been putted to indicate which directions should be marked as read.
- The database: a MySQL database and a set of PHP scripts hosted off of our own website. It does the following:
- Store a list of directions, names, and a flag on whether the entry has been read or not.
- Provide 3 PHP scripts:
- One for recording directions into the database, and automatically flagging them as unread.
- One for retrieving all the directions that are flagged as unread from the database.
- And one for marking specific directions to mark as read (each direction has a unique ID).
To be clear, each of these parts were either a separate build of the game, or using a completely different scripting language. That meant that often, there were many portions of the code that only applied to one part of the game. Making sure each of these parts were working in harmony took the most amount of time and energy.
Naturally, there are way too many parts for a game jam game, and one that in hindsight, could have been simplified even further had we known how Unity’s UNET networking framework worked better.
RemoteSettings not working
The dreaded, “it works on my computer” occurred when we tried to make a server build of our game, and hosted it up to the Google Cloud server. The client would not connect to the server, even through it worked fine in our local setup. After a ton of online research, we soon realized the server simply wasn’t listening to the port it was programmed to. For the longest time, we could not figure out why; we’ve instead moved on to other parts of the game while mulling over it. It was only when we were nearing the submission deadline did we realize through logs that Unity’s RemoteSettings, which we were checking its status before retrieving a port number, was not working. Baffled, we’ve removed the status check before grabbing the port-number (i.e. the equivalent of hardcoding the port number), and the server finally worked. After that, we only had minor bugs to fix on the client before submission. Still, it was very stressful during the time we had no idea what was broken with the server.
The game provides no feedback on how many people are playing, making it incredibly confusing to figure out why the golf ball may be moving on its own. Additionally, since the server receives from the database every 0.2 seconds and is the only part responsible for moving the golf ball, there is almost always delay between clicking the mouse and observing the golf ball moving. And for additional pain, the client could fail to send to the database the direction the player putted for any technical reason, yet they’ll still lose energy for it. All of this leads to poor feedback to the player, providing some confusing information as to why the ball might be moving on its own, or conversely, why it’s not moving when the player clicked.
There was a pause screen we left in the game, in case we added any audio to the game, so that one can use it to access the options screen as well as the credits. Unfortunately, we didn’t have time to fix the text labels on that screen, or had the time to test whether options or credits worked. With such broken features left in the game, it might have been better to remove it entirely.
If it wasn’t obvious, we ran out of time adding audio. Sigh.
What to do next
From the beginning, we knew we were taking major risks working on this game within the Ludum Dare deadline. That said, we probably could have taken a refresher, or made a simple library of codes that would help us accelerate the development than the approach we took for this jam. We should also strive to make a simpler model, removing the database portion entirely. Finally, never use RemoteSettings until we know how it works.