My current project, Sunshine, has been in development way longer than I expected. I knew this project would be a major learning experience, and would involve a lot of experimentation, and therefore, a lot of time spent not knowing what I’m doing. Rather than feature creep and pie-in-the-sky ideas dragging this process through the mud, however, my development time period got stretched out due to an ongoing illness (as of yet undiagnosed) that devastated my life for most of 2014 and is still going. A process that might’ve lasted 3-4 months has instead crept along at a snail’s pace for beyond a year. I’m not here to write about the illness though, but about the game. Since development has taken much longer than expected, I figured I’d write at length about what I’m working on and my thoughts on the dev process, without giving spoilers. This will be a bit rambly, incoherent, and metaphysical, as my infection is going through another bad spike of intensity. My apologies.
My previous game, A Night in the Woods, was simple on the programming end. There was a textbox at the bottom of the screen that printed messages for the player. There was a flashlight the player could pick up and then toggle on and off. There were stationary objects the player could pick up with a click, that displayed customizable newspaper headlines. There was a key, two doors, and a door opening animation. There was a barrel you could activate upon collecting enough scraps of paper, and an ending sequence you could trigger by using a bedroll. And there was a generic script that made 2D sprite graphics always face the player.
Along with the graphics, sound, and writing (most of which had been done in advance for a different game), this took me a month to produce. I was in peak health, holding down a contract job by day and coding away until bedtime at night. I knew there were a lot of programming concepts I didn’t understand, but I felt like a badass. For one, this was my first time ever holding down a dayjob and not feeling like a zombie upon arriving at home. For two, I knocked it out of the park with this game. Even with messy programming that would make a CS major cringe, I crafted a compelling experience that shook many players to the core. I knew though that my coding knowledge was missing key data, so for my next project there were specific things I set out to accomplish that, upon learning, would fill in the gaps.
The Original Concept
While working on ANITW, I came across Connor Sherlock’s The Rapture is Here and You Will Be Forcibly Removed from Your Home. That game really struck a chord with me. The feeling of vast emptiness and impending doom, and a large object heading toward you. Haunting music. It was an experience I’d never had before with a game. I really liked that it had a fixed length. The fixed length allowed me to forget gamer expectations and just absorb whatever was about to happen next without question.
I like that the game didn’t force you down any path with objectives or other quantified progress, and that there was no way to “lose” or “die”. There’s just 20 minutes, these glowing sparklies that play voiceovers, and a lot of surprises. It took several playthroughs to really appreciate all the game had to offer. I knew I wanted to take one aspect of the game—the oppressive disc slowly approaching from overhead—and apply it to a different kind of game. Consider it the second entry in a two-game genre, the First-Person a UFO is Coming Straight for You and You Are Powerless to Stop It genre.
Tweaking the Concept
Apart from the UFO itself, I knew I wanted a city instead of a farm, a fixed time to play, a story of some kind. At first it was going to be a very personal story, and only take place outdoors. The player would run down hallway-like streets with intersections, like the graph of a choose-your-own-adventure game rendered as a city. And there would be eyes watching you, following you. Over time that concept gradually morphed until the barricaded streets were opened into an explorable city. I added indoor areas to hide from the eyes. The entire scenario changed from a personal crisis to a cautionary tale about the surveillance state.
Each one of these changes made me rethink the player verbs, the gameplay loop, and how that tied to the meaning of the game. The original concept had no object interaction. You’d simply walk to key locations and those locations would reveal more of the story. As the theme shifted its focus to the surveillance state, I decided object interaction was necessary, as your behavior would affect the state’s treatment of you. With a surveillance situation, it made sense to incorporate hiding from the spheres as a part of the game. This lead to adding indoor areas. Since it’s a large city I didn’t want to build entirely by scratch, I added randomized interior instancing. Then I had to ask myself, what is your role in this surveillance state? Can you die? Is there failure? What is the cost of failure? Are there other people? I found a way to fill the city with people without straining resources: use a single citizen NPC that is re-used for every interior, and make it so you only see one interior at a time. Everyone is in their homes and the outside part of the city is empty. That’s a lockdown situation. From there, more of the story developed. You’re the only person disobeying the lockdown and running around. Why? To what ends? From there I got more story.
This is an example of a thing I’ve ranted about in soundbyte form — gameplay informs story informs gameplay informs story — but has remained too elusive a concept to write an article about in full. I guess this is a good start.
It took many iterations to reach the gameplay loop I have now, that I feel fits the theme of the game without following old conventions for the sake of convention. Each time I changed the loop, it took a lot of re-coding existing systems that are in a pretty messy knot at this point. Adding features to the interiors, changing the ways the NPCs behave, changing the way the UFO behaves, the eyes, changing how all of these things interact. The resulting code is still a bit messy, but it is light-years beyond what I made in ANITW.
This section is just a list of things I’ve learned how to do while making this game, to give a sense of how much it takes to do what often seems simple. You can skip ahead if you like. This is not a comprehensive list:
- Load and parse strings from a text file in CSV (comma-separated values) format
- Define custom data structures, used to store parsed strings mentioned above and to handle apartment and object instancing
- Spawn the player object in code, rather than having the player placed in the level itself
- Create a singleton object (an object that is not duplicated and remains persistent across level loads) to manage the game state
- Properly reset data stored in the singleton so the player can hit a reset button and start over without quitting the app
- Get objects to send messages to each other directly rather than via a centralized script
- Create a gameController object that all other objects can interface with
- Figure out how the hell to code interfaces
- My first attempts at encapsulation, which are a bit haphazard
- An honest-to-god homebrew level-of-detail system, that hides objects not within your field of view, turns off shadow casting beyond a certain distance, stops rendering objects past a certain distance, and uses a quirk of the game’s world layout to cut out 1/4 of the world meshes no matter where you are. That also works seamlessly in VR
- Oh yeah, did I mention VR
- Create a generalized “use object” function that lets me code custom behavior per-object without modifying the player object code
- Create a system to show object highlights (using a toon shader) that allows for targeting interactive objects within a field of view instead of having to precisely target them in the center of the screen, since this game doesn’t have crosshairs
- A GUI system that displays a pause menu and arbitrary strings of text for interactive objects
- Consistent behavior for the entire game world so that things actually pause when you hit the pause button
- A mini-map that is on your character’s arm and shows your location in the world, along with the location of objectives
- Animation blending so the player’s arm can raise to show the mini-map while other animations play
- A Twitter-like texting system that can not only display text messages but, behind the scenes, send commands to the gameController object for special events
- An AI algorithm for the eye spheres that finds a randomized location large enough for the sphere to fit, that has line-of-sight to the player, within a certain distance
- An AI algorithm for the eye spheres that follows the player when they have been spotted within a certain field-of-view, and randomly searches around when it loses sight
- How to even code things like determining if an object is within a certain field-of-view, line-of-sight checks, and other three-dimensional space stuff
- A system to lean left and right around corners for stealth purposes, that ensures your head never pokes through a wall or other object
- A system for recording and storing the player’s walking path for 60 minutes of time (is actually arbitrary, but the game is 60 minutes long)
- Reliable ways to code objects so they play nice with each other, can communicate with each other, and can manage their own problems
- How to instantiate objects via code
- How to instantiate objects via code based on a list of prefabs configured in the editor, that has a max instance count for each object and manages this list
- How to remember the state for every apartment and, upon opening a door, summon all those reusable prefabs to the proper location and configuration so that it appears as though every apartment has a consistent layout that’s always there, even though the game only ever renders one at a time using the same set of objects
- How to create a table of event flags and a table of integer counters that can be accessed via the gameController script, that any object can access to read/write game state
- A sound system with a library of clips and a number of sound channels, all of which can be searched by name to play sounds in those non-localized channels or for objects localized in 3D space to play on command
- A system to fade in/fade out/adjust the volume of any of these sound channels
- Controlling the animation of the player for walking and running, with matching footsteps
- A lot of really computer-sciency Good Practice things that I’m not CS-educated enough to explain using the proper terms right now
Getting Ahead of Yourself
For awhile I thought I was almost done with the game. As I approached a satisfying gameplay loop, however, I realized I was still at the prototyping stage. At what point during this exploration do you lock things down and say, “Yes, this is it. This is the game”? I stick to the axiom laid out by Antoine de Saint-Exupéry: “A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away.” This applies not just to “gameplay”, but to story, to theme, to the tight integration of player action and other forms of meaning. Throughout prototyping I added many things: A randomized quest generator that creates phrases in the form of “[VERB] the [NOUN]”. Lights on the UFO that can also see you, in addition to the eye spheres. An effect where time speeds up when the UFO can see you. All of these were removed.
Many other features, that fit the final game theme, have stayed. Only a small number of questions remain, and when those questions are answered, the prototyping phase will officially end and full production will begin. That means creating the final graphics, sound, and spatial design. (I would say “level design”, but something in my gut tells me this is a bit off.)
Apart from the spoilerific decisions about gameplay that I can’t get into, there’s another part to knowing when I’m done with prototyping. And that is the following question: How far can you reach beyond your comfort zone without falling over? I have coded a lot of systems for Sunshine I thought were completely beyond my skillset. The code is now very messy, and I would be wise to not push it too much further. This is where I make the hard decisions about what design ideas are nice but ultimately untenable. This ties into the design quote I mentioned earlier, but is more about practicality than perfection.
It is really easy to cut things out when you’re doing a weekend game jam. There’s a hard deadline warning you, “Stop adding things now or else you will have nothing to show for all your hard work!” That’s how I made 10 Seconds in Hell. That’s how I started making A Night in the Woods, but I got a cold (that would later develop into my ongoing illness), so I gave up on submitting it for the game jam. Instead, I set my own deadline of a month. That forced me to make a lot of hard decisions, fantastic decisions that I hated in the moment but were the right thing to do. With Sunshine I intended to try working on a more complex game for a longer period, say three or so months, to stretch my time-management abilities further. I had to adjust this timeline heavily because of my illness, like an astronomer compensating for gravitational lensing, but in the end the time will still come where I must make hard cuts to my original vision. I will hate making those cuts, but like a well-manicured tree (or the forgotten art of making a film less than 3 hours long), all of those cuts will shape the final result for the better. Most big-budget games strive for “more more more!” when they should strive for “better better better!” Which requires less less less! The time to cut is now.
The Final Cut
The most important thing to remember during this phase of Hard Decisions is what your game is about. On a big-picture level, what is it about? I don’t mean plot. I mean — What is your game saying? It doesn’t have to be a moral lesson or anything like that, but it should say something, even if that something can only be understood by synesthetes. There must be some kind of meaning. The very core of that meaning is what matters, even if it is accidental. Everything else is window dressing. Too much window dressing means you can’t see that core, and it means you have less time to work on that core.
You trim the twigs, not the trunk. So make sure you know what the trunk of your game is. That can be hard to know during prototyping, but when you find the trunk, that is when you begin to trim. Trim mercilessly, but also trim artfully. Not all window dressing is pointless. But it must be deliberate, or at the very least, look deliberate in retrospect so you can impress all your friends. If you’re heading into uncharted territory—which in videogames means you might actually be making something of value—these calls will probably come from your gut, not your head. Your gut may be informed by your head, but in the end it’s your gut making the call, and you may not know why until years after the fact. That’s fine.
I am pretty sure I’ve found the trunk of Sunshine, and there’s a lot of extra foliage to trim down. But once I do that, the rest will flourish beautifully. It won’t be as complicated as one might expect for a year-plus development time, but alas, not all of us remain healthy and able. However it turns out, though, it will be worth it, and I hope you enjoy it. Just don’t apply gamer hype. Enter with zero assumptions. That’s what I’ve done as I make it.