Crunch and Burn(out)

If you’ve been following the development of Where Shadows Slumber, then you know that we’ve been working on it for a while. It was early 2015 when the core concept first came to me. Three years ago this month was when I put together the first proof-of-concept to show to Frank. The demo version of the game has been out for over a year and a half.

Game development takes a long time, especially with a tiny team, little to no funding, a full-time job, and, the biggest time-waster of all, life itself. As Frank discussed in a previous blog post, we are holding ourselves to a pretty high standard for Where Shadows Slumber, which makes development even slower.

Fortunately, after all this time, we’re finally closing in on the end. As happy as that might make you, the fans of the game, there are two people who are definitely happier about it than you are: us. As frustrated as you might be about how long it’s taking, we’re even more frustrated. Frankly, as much as we love Where Shadows Slumber, neither of us can wait until the moment it’s over.

“But Jack”, you ask incredulously, “if you love it, why do you want it to be over? You’ve managed to work on it for three years – what’s another few months?”

There are two phenomena that often creep up at around the same time in the development cycle of a game (or any project, really). Here they both are, followed by something I’ve said in the past week that represents each of them:

  • Crunch – “There’s only a little bit of work left, but there’s even less time left!”
  • Burnout – “I’ve spent so long on this game, I’m just sick of it!”

 

Night.jpg

Crunch

I’ve discussed before the “ninety-ninety” rule, so I’ll just summarize it quickly here, since it’s relevant: not only does software development take a long time, it takes significantly longer than you think it will. This is an issue when you first start your project (“it’ll probably only take 18 months or so”), but there’s no scheduled release date or external pressure at that point. Nobody really cares yet! However, it becomes a bigger issue when dealing with shorter time periods. For some reason, people have a hard time realizing that their estimates are wrong and adjusting (at least, we do). Because of that, we’re still making poor estimates for how long something will take!

This is the reason that developers inevitably end up in the dreaded state known as crunch time. We thought there were about 6 weeks of work left, but it turns out there were 12 weeks of work left. Too bad we already gave a bunch of outside parties a solid release date! Since they’re now depending on us to meet those deadlines, we have to do 12 weeks worth of work in 6 weeks!

This is the phenomenon that leads to crazy overtime, too many all-nighters, and an incredible amount of stress. If you follow game design, you’ve probably heard about it, because it somehow ends up happening to pretty much every game. If you’re involved in game design, then you’ve probably gone through it, and you know how awful it can be.

It’s a little better for us than for bigger, more established studios – we don’t have employees to pay, stockholders to appease, or a public release date to hit. That said, we don’t want Where Shadows Slumber to turn into an indie game for which development takes forever that people are perennially waiting for. It’s now or never!

 

Burnout.png

Burnout

Cascading into crunch time at full speed is pretty bad, but it’s not the worst thing in the world – we’re been working on Where Shadows Slumber for a long time, and we are both willing to put in a little extra time as we reach the end. However, one of the biggest problems is that crunch time is also usually accompanied by burnout.

When you’re just starting out on a project, everything is pretty exciting. You enjoy working on interesting problems like pathfinding and game mechanics, and you don’t even mind fixing any bugs that come up. On the other hand, once you’ve been working on a game for a long time, you’re pretty much sick of it. All of the interesting stuff is already implemented, so the only things left to work on are tiny quality improvements (“does this look better when the position is 0.4 or 0.41? How about 0.42?”), annoying, subtle, or hard-to-reproduce bugs (“this was working last week, but a change to a different piece of code is somehow causing it to break, but only ~10% of the time”), and tasks that you intentionally avoided because they aren’t interesting or fun (“how many setPass calls will this scene render when running on a 6-year old Android phone? Is that too many?”).

None of these tasks are really very enjoyable – so not only has your excitement about the work decreased, but so has the objective fun-ness of the work that’s left to do. This leaves you in a state of never actually wanting to work on the project. Combine that decreased drive with the increased amount of work you have to do, and it starts to become pretty obvious why the end of development for a game tends to get pretty hairy, and why we’re looking forward to being done with it.

 

Tunnel.jpg

The Light at the End of the Tunnel

Don’t worry, though – it’s not all bad! We’re both still really excited about Where Shadows Slumber, because of the amount of work we’ve put into it. We’re both dedicated to the cause, and we’re not gonna let a little extra work put a stop to it (even if it ends up slowing us down).

The purpose of this blog post is two-fold. On one, more selfish hand, I want to offer up to our adoring fans an explanation for why we haven’t finished the game yet. We know a lot of you love the game, and are really looking forward to it, and many of you have shown us that by popping up and saying hi at various conventions. The past 8 months or so have been a real whirlwind, both personally and professionally, and our timeline has been shifting around quite a bit as a result. So I wanted to offer a bit of an explanation, as well as reassure you that we’re still working on Where Shadows Slumber, and we’re not gonna let it fall by the wayside!

The other reason for this post is to serve as a sort of warning, albeit a likely redundant one. For anyone working on their own game (or any project, really), it’s very important to take time management seriously. Ending up in the crunch time/burnout trap is an awful place to be. Despite this, most developers (indie and AAA alike) end up here, because it’s hard for people to grasp how time-consuming the last 10% of a project can be. So, if you take away anything from this post, I hope you do your best to allow enough time at the end of development to get your game out without ending up there. You’ll end up there anyway, but maybe by knowing about it ahead of time, you won’t be there for long.

 

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

You can always find out more about our game and how freaking long it’s taking us to finish it at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebookitch.io, or Twitch, join the Game Revenant Discord, and feel free to email us directly with any questions or feedback at contact@GameRevenant.com.

Jack Kelly is the head developer and designer for Where Shadows Slumber.

Unity’s Performance Debugging Tools

Last week I discussed some of the basics of how rendering works in Unity. As I mentioned, all of that was setup for this week’s blog post. Since I’m working on rendering optimization now, I figured it would be a great time to go over the debugging tools Unity provides in order to aid rendering performance. Online resources can be a little scarcer for rendering than they are for other aspects of coding, so hopefully anyone who’s working on their own game might glean some useful information from this post. And even if you’re not working on anything right now, I hope you follow along and maybe learn a bit!

Unity is a nice little game engine, and, as such, it does a lot of the work for you. For the most part, when making a game, you don’t have to worry about the nitty-gritty stuff like rendering. When building for mobile, however (especially when you have specific graphics/lighting customization), you might have to descend into shader-land. Fortunately, Unity provides a few tools that can help you to deal with optimizing your rendering pipeline.

 

4-24-Profiler.JPG

Profiler

The first step in fixing rendering performance issues is to know about them. The best way to do that is with the Profiler window (Window -> Profiler). While you’re running your game, the Profiler keeps track of a lot of incredibly useful information, like how long each frame takes to render, split up by category. For instance, the Profiler will tell me that a frame took 60 milliseconds to run, 40 of which were due rendering and 15 from script execution, etc. This is the first place you should check when trying to improve performance – there’s no point in optimizing your rendering if it’s actually your scripts that are running slowly!

profiler

So much information!

For the purposes of rendering, there’s an entire Profiler section! The Rendering Profiler keeps track of the number of batches, setPass calls, triangles, and vertices in each frame. Looking here for inconsistencies, spikes, and just high numbers in general is a good way to get an idea of why your game is taking so long to render. The Profiler also has a lot of other info that’s useful for diagnosing and debugging performance problems. I really recommend profiling your game and thoroughly looking through the results to get as much information about how your game is running as possible.

 

android_debug_bridge

Android Debug Bridge

While profiling in the editor is pretty useful, it doesn’t tell us much – of course our game will be fast on a great big computer, but how does it run on a crappy phone?

The is where ADB, or the Android Debug Bridge, comes in. ADB allows your computer to communicate with your Android phone about all sorts of stuff. Specifically (for our use cases), it allows you to profile your game while it’s running on a device. If you plug your phone into your computer, build the game directly to your phone, and open the profiler, you should see some results. This is the information we want, because it tells a much truer story about how your game runs on a phone.

Where Shadows Slumber, for instance, runs at ~200 fps in the Unity editor. When I plug my phone (the Google Pixel 2) into the profile, I get a framerate of ~60 fps. This is pretty good, so I know our game can run on newer devices. However, when I plug in my old phone (a broken HTC One M8), I get closer to ~12 fps. Looking at the profile during this run will give me much more useful information about what I should fix, since this is the device where performance is actually suffering. If you’re making any big decisions or changes based on profiler results, make sure those results come from your actual targeted device, and not just from the editor.

ADB usually comes with the Android SDK – if you have the Android SDK set up with Unity (which allows you to build to Android devices), then you should be able to use ADB with the profiler pretty painlessly.

I should also mention that there might be an equivalent tool for iOS debugging, but, as I do all of my development on a Windows machine, and all of my testing on an Android phone, I wouldn’t know what it is. Sorry!

 

4-24-Header

Frame Debugger

The next most important tool for rendering performance is the Frame Debugger (Window -> Frame Debugger). While the Profiler tells us a lot about what’s happening during rendering as a whole, it still treats the rendering process as a black box, not letting us see what’s actually happening. The is where the Frame Debugger comes in – it allows us to see, step by step, exactly what the GPU is doing to render our scene.

As I mentioned last week, the GPU renders the scene through a bunch of draw calls. The Frame Debugger allows us to see what each of those draw calls is drawing. This allows us to determine which materials/shaders are causing the most draw calls, which is one of the biggest contributors to rendering lag. It also provides a bunch of information about each draw call, such as the properties passed to the shader or geometry details. The important thing that it tells you is why this draw call wasn’t batched with the previous draw call.

frame debugger

All of this happens in a single frame

Batching is Unity’s first defense against rendering lag, so it makes sense to batch as much stuff into a single draw call as possible. Because rendering is such a complex process, there are a lot of reasons why draw calls can’t be batched together – certain rendering components simply can’t be batched, meshes with too many vertices or negative scaling can’t be batched, etc. The frame debugger will tell you why each draw call isn’t batched with the previous one, so you can determine if there are any changes you can make that might reduce the number of draw calls, thereby improving rendering performance.

For example, in Where Shadows Slumber, we re-use meshes in certain places. Sometimes, if we require a “mirrored” look we’ll reuse a mesh, and then set the scale to -1. This was before we really looked into rendering performance, and, unfortunately, it causes problems – a mesh with negative scaling can’t be batched with a mesh with positive scaling, so this ends up creating multiple draw calls. Rather than setting the scale of the object to -1, we simply import a new, mirrored mesh and update the object, allowing these draw calls to be batched and improving performance.

 

4-24-Stats.JPG

 

Stats

That’s it for the heavy-hitters; between the Profiler, Frame Debugger, and ADB, you should be able to get a pretty good idea of what’s going on in render-land. Unfortunately, digging through them can take a while – sometimes you just want a quick indicator of what’s going on in your scene. Enter the Stats window.

The Stats window (click “Stats” in the Game View) is a small overlay in the game view which gives you a quick rundown of various rendering indicators in real time. It’s not as in-depth, but it gives a much quicker picture of performance.

stats

That’s a lot of batches!

While it sounds like the stats window doesn’t add much – after all, the Profiler can give you the same information – I’ve found it to be very useful. The Profiler is probably better when you’re actively debugging rendering performance, but the stats window allows you to notice places where rendering performance might take a hit, even when you’re doing other things.

When I’m testing some other part of the game on my computer, I’m not going to notice any rendering lag, because my computer is so much more powerful than a phone. I’m also not going to be looking at the Profiler or Frame Debugger, because I’m not worrying about rendering at the moment. However, if I have the stats window open and I notice that the number of draw calls is in the hundreds, then I know something is going on. At that point I can get out the Profiler and see what’s happening – but I wouldn’t even have known there was anything amiss if it weren’t for the stats window.

 

4-24-SceneView.JPG

Scene View Draw Mode

As we get further and further down the list, we’re moving from “debugging all-star” to “it’s useful, but you probably won’t use it much”. Scene View Draw Modes fall into this category, but they’re still good to know about. You can access different Scene View Draw Modes by clicking the drop down menu at the top right of the scene view window.

The Scene View in Unity is one of the main windows that you use to make your game – it shows everything in the scene, allowing you to move around through the scene and select, move, rotate, scale, etc., any game objects. Usually the Scene View just displays the objects exactly as they would be displayed in the game. However, it has a bunch of other modes, and some of them are actually pretty useful. The two that I find the most useful when considering rendering concerns are listed below, although they’re all worth checking out:

Shaded Wireframe: This is my default draw mode, as it looks pretty similar to the normal shaded mode. The difference is that it also shows all of the triangles and vertices that you’re drawing. This is useful because certain shader operations are performed once for every vertex. Decreasing the number of vertices in your scene can give you a bit of a performance boost, and the shaded wireframe draw mode helps you see when you might have too many vertices.

3-4toomanytris

The shaded wireframe shows that there are too many polys.

Overdraw: This mode draws each object as a single transparent color. This makes it very easy to see when multiple objects are being drawn in the same spot on the screen. Since the GPU has to draw every pixel of each object (even if that pixel will be overwritten later), it ends up wasting some calculations. Areas that are very bright will waste even more calculations. Switching to this draw mode every so often lets you know if there are any places where you might want to remove some meshes.

 

161004-worst-hacks-history-feaure

The Internet!

It should pretty much go without saying, but one of your best resources for debugging performance is the internet. Unfortunately, when it comes to rendering in Unity, the information out there is pretty scarce. Unlike with normal imperative coding, where you can simply Google “how to pathfinding” and get 30 implementations, you have to work a bit harder with rendering stuff. I find it’s best to do what you can and only resort to the internet with very specific questions. That said, there is still a lot of helpful information out there. You just have to know going in that only one of every three stack overflow questions makes any sense, and only one of every four Unity forum threads are using the most recent APIs. It’s like “Googling: Nightmare Mode”!

For anyone reading this post who is actually working on rendering stuff – I’m very, very sorry. I hope that this post and the tools I discussed help to shed at least a little bit of light in the dark underworld that is shader-land, and I hope you can achieve your rendering goals and make it back to the mortal realm before your soul is forever lost.

For everyone else who hasn’t done any rendering stuff, I hope you learned a bit, and that maybe I inspired you to get involved with some rendering code! It’s really not that bad, I promise!

 

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

If you didn’t already have a working knowledge of rendering, I hope this post helped! If you do know about rendering stuff, I hope you don’t hate me too much for my imprecision! You can always find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebookitch.io, or Twitch, join the Game Revenant Discord, and feel free to email us directly with any questions or feedback at contact@GameRevenant.com.

Jack Kelly is the head developer and designer for Where Shadows Slumber.

Rendering in Unity

As you probably know, Where Shadows Slumber is starting to ramp up toward a release this summer. It’s an exciting, terrifying time. We can’t wait to share the entirety of what we’ve been working on with the world, but there’s also a daunting amount of stuff to do, and not much time to do it.

If you’ve played any of the recent beta builds, hopefully you like what you’re seeing in terms of design, functionality, polish, art, and sound. Unfortunately, if you’ve played the beta on anything other than a high-end device, you’ve probably noticed something that you don’t like: lag.

Lag is annoying. Lag is something that can take a great game and ruin it. It doesn’t matter that your level design is perfect, your models are beautiful, and your music is entrancing if it only runs at 10 frames per second. If that’s the case, nobody is going to enjoy playing it. And, regrettably, that happens to be the case for Where Shadows Slumber.

LikeButta

Like butta’!

So, one of my biggest tasks before we release is to optimize the game, making it run faster and allowing us to have higher frame rates. The area with the most opportunity for improvement is during rendering. A game consists of a lot of logic – Obe’s location, things changing in shadow, etc. – but rendering is the process of actually drawing the scene onto the pixels of your screen.

Earlier this week, I started a post about the different tools you can use to help optimize your rendering performance. It seemed like a good idea, since that’s exactly what I was doing. However, I realized that if you don’t know how rendering works in the first place, most of it is complete gibberish. So I’m gonna leave that post for next week, and this week I’ll give a quick introduction to how 3D rendering works in Unity.

Blog-Render.JPG

Rendering

Rendering is the process by which the objects in your game are drawn to the screen. Until it’s rendered, an object in your game is just a collection of information about that object. That information gets translated from information the game engine understands into information the GPU can understand. There are a few important concepts to understand here:

  • An object’s mesh describes the shape of the object. It consists of a collection of vertices and triangles.
  • An object’s material is a description of how that object should be drawn. It encapsulates things like colors and shininess.
  • Every material uses a shader. This is the program which calculates exactly what color each pixel should be, based on the information in the mesh and material.
  • World space is the 3D coordinate space in which all of your game objects live.
  • Screen space is a 2D coordinate space that represents the screen to which the game is drawn.

The basics of rendering are pretty easy to understand, at least from a high-level view. The meshes for the objects in your game are translated from world space to screen space, based on the camera that’s doing the rendering. For instance, in Where Shadows Slumber, objects that are further away in the x-axis will be higher up and more to the right when viewed on the screen. Fortunately, we don’t have to mess with this too much – Unity’s cameras do a good job of making this translation.

Once we know where each pixel should be drawn, we need to determine what color that pixel should be – this is where the material and shader come in. Unity provides a whole bunch of information to the shader (position, angle, information about lights in the scene, etc.). The shader uses that information, plus the information from the material, to determine exactly what color the given pixel should be. This happens for every pixel on the screen, resulting in a beautiful picture of exactly what you expect to see.

The GPU

Now that we understand the basics of rendering, let’s take a deeper look into how it actually happens: the GPU.

The GPU, or graphics processing unit, is the part of the computer in charge of calculating the results of our shaders to determine a pixel’s color. Since modern phones have over 2 million pixels, our shader code must be run over 2 million times per frame – all within a fraction of a second.

How does the GPU manage to do so many calculations so quickly? It’s due to the design of the GPU, and can be summed up in one very important sentence: the GPU is good at performing the same operation, a bunch of times, very quickly. The key thing to remember here is that it’s good at performing the same operation; trying to perform different operations is what slows it down.

Specifically, switching from one material to another causes a bit of a hiccup in terms of speed. The properties of the material are passed to the GPU as a set of parameters in what is known as a SetPass call. SetPass calls are one of the first and most important indicators when it comes to optimizing rendering performance, and are often indicative of how quickly or slowly your game will run.

Because SetPass calls take so long, Unity has a strategy for avoiding them called batching. If there are two objects that have the same material, that means they have the same parameters passed to the GPU. This means that those parameters don’t need to be reset in between drawing the two objects. These two objects can be batched, so the GPU will draw them at the same time. Batching is Unity’s first line of defense against rendering slowness.

The CPU

While the GPU is the star of the show when it comes to rendering, the CPU, or central processing unity, still does some important stuff that’s worth mentioning (even if it doesn’t have a huge bearing on the optimization steps we’ll be taking). Of course, the CPU is in charge of running your game, which includes all of the non-shader code you’ve written for it, as well as any under-the-hood things Unity is doing, like physics and stuff.

The CPU does a lot of the “set up” for rendering, before the GPU comes in and does the heavy number-crunching. This includes sending specific information to the GPU, including things like the positions of lights, the properties of shadows, and other details about the scene and your project’s rendering config.

One of the more important rendering-related things the CPU does is called culling. Since the CPU knows where your camera is, and where all of your objects are, it can figure out that some objects won’t ever be viewed. The GPU won’t know this, and will still perform calculations for those objects. In order to avoid doing these unnecessary calculations, the CPU will first remove any of the objects that won’t be drawn, so the GPU never even knows about them.

Image

All of these Hitlers would be culled by the CPU (image credit: smbc-comics.com)

Since we’re talking about performance, it should be noted that the GPU and the CPU are two different entities. This means that, if your game is experiencing lag, it’s likely due to either the GPU or the CPU, but not both. In this case, improving the performance of the other component won’t actually make your game run any faster, because you’ll still be bottlenecked by the slower process.

So, now that we know a little bit more about how rendering actually happens, maybe we can use that knowledge to improve performance! At least, that’s what I’m hoping. If Where Shadows Slumber never comes out, then you’ll know I’ve failed. Either way, I’ll see you next week for a look into the tools you can use to help you optimize rendering performance in Unity!

 

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

If you didn’t already have a working knowledge of rendering, I hope this post helped! If you do know about rendering stuff, I hope you don’t hate me too much for my imprecision! You can always find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebookitch.io, or Twitch, join the Game Revenant Discord, and feel free to email us directly with any questions or feedback at contact@GameRevenant.com.

Jack Kelly is the head developer and designer for Where Shadows Slumber.

Creating a Level: From Concept to Finished Product

For a long time, I’ve wanted to write a post about how we make Levels when working on Where Shadows Slumber. The only problem was a lack of documentation. I forgot to take screenshots of the early stages of the Levels we’ve completed so far. What I really wanted to do was show our audience the growth of a Level, from it’s earliest conception and then show the various stages of the design process along the way.

When I thought of this idea, I tabled the blog and decided to wait until I started on a new batch of Levels… and here we are! We’re going to take an inside look at Level 3-1, Noria, the first Level of the Aqueduct World.

 

Maker:S,Date:2017-8-17,Ver:6,Lens:Kan03,Act:Lar02,E:Y

Step 1: Draw The Level

Every Level has a reason for being in the game. Noria is the first Level in the Aqueduct World, which makes it extra special. Whenever we design the first Level of a World, we like to communicate to the Player:

  • Why the World is going to feel different from the other Worlds in the game
  • What mechanics you’ll be dealing with in this World – especially new ideas

For the Aqueduct, we wanted to make it all about mechanical devices, switches, rotating things and whirring machines. Our game doesn’t exactly have a precise historical setting, but it’s fair to say it isn’t modern day. This gives us some leeway with technology. It has to work, but it can look really old.

MVIMG_20171025_141620.jpg

Jack’s notebook!

The Aqueduct World is all about Buttons. Buttons are Nodes that do something when you step onto them. There are all kinds of Buttons, but the most basic Button does a thing every time you step on it, no matter how many times you step on it.

To show that off, Jack designed a Level (above) where the only way to cast shadows and move the light was with a single Button. In addition to that, there are Buttons near each light in the Level to turn them on and off. The proximity of the light to the Button it’s attached to is an intuitive connection. These Buttons work like regular domestic light switches too, so it’s a cheap way of using existing Player knowledge about the real world and transmuting it into knowledge of our game.

When a Level exists in this form, the only thing we can really do is discuss it. Jack will attempt to guide a very confused Frank through the mechanics of the Level. I’ll try to poke holes in it (literally, with my pencil) and find problems with the design. We’ve never shown these sketches to testers because it’s too high-level for them to understand. If we like the idea of the Level, Jack makes a grey box prototype of it in Unity for us to test.

 

Noria-Greybox

This Level doesn’t look too special yet, huh? Just wait!

Step 2: Make A Grey-Box Prototype Level

With a design solidified, now we’re ready to make a version of the Level that can be played and tested. It doesn’t need to look pretty yet, so we use basic template cubes to represent walkable space. Affectionately called grey box prototypes, this technique is how we prototype every Level in the game. Watch a video of me beating the Level below:

As you can see, it’s playable in this stage, and everything works. You can solve the puzzle, which means testers can assess the strength of our design. (We just tell them to ignore the visuals.) We brought this Level, in this format, to AwesomeCon 2017 looking for feedback from players. When we show grey box prototypes to people, we want to make sure they can complete the puzzle. More than that, we want to make sure that they solved it on purpose instead of just by brute force. If we get good feedback, we proceed to Step 3.

 

Noria.png

Step 3: Draw Some Concept Art

This might seem backward, but this is the time when I draw a concept image of the Level. Why do I do this after the Level has been prototyped, and not before? It’s because Jack knows best which Nodes need to go where, and I don’t. I need to take cues from him about where everything must be, which often includes the actual length and width of shadow casting objects.

This is actually beneficial. It gives me good constraints to work with. I draw a paper sketch and say, “OK, if everything absolutely has to be in this location, what can I do with it? What makes sense for the setting [Aqueduct] whether it’s man-made or organic?” As you can see in the drawing, the following ideas have been spawned:

  • Obe should enter from a pipe (bottom right) to match the cutscene that plays directly before this Level.
  • The pillar now looks like it belongs – it’s a crumbling structural element of the Aqueduct, a man-made structure in disrepair.
  • The mechanism by which the lamp moves left to right is not just a magical back-and-forth switch. Now it’s a waterwheel! Why a wheel? Google “Noria”…
  • The lights need to look like actual man-made lights since they are powered by Buttons on the ground. Why not lamps?
  • There are stone pathways going horizontally that have crumbled over time. Those need to be repaired by shadows.
  • The bridges going vertically are metal grates that allow water to pass under them. This is an Aqueduct, we can’t just have standing water blocked in!
  • There’s a back wall with a door. I like to give the Player as many visual cues as possible that the finish line is an actual exit.

The concept art phase is another chance for us to critique the design. If we know the puzzle is good, but it produces an awkward-looking Level, we have the opportunity to reconfigure things. Perhaps the exit needs to be in a different place? Maybe objects should be closer or further apart? Now is the time to match the design to the intended context, the Aqueduct. Once I have good concept art to work from, I proceed to Step 4!

 

DesignBlog-Noria-FirstPass.png

Step 4: First Aesthetic Pass

Now it’s time to take that ugly grey box prototype (sorry Jack) and make it look and sound beautiful! I’m ready to apply my toolkit of Aqueduct paths, walls and bridges to the design. Once the art is laid down, Alba and Noah have their first chance to put some audio effects into the Level and set the mood. It makes a huge difference: now the Level doesn’t sound like it takes place in a silent death vacuum! Creepy chimes and rushing water converge to give the Level a sense of place. Here’s a video of it all in action:

The Level doesn’t look grey anymore! That’s awesome. But… it also doesn’t look finished, does it? This kind of art would pass for a student game or something in a game jam, but we want to be an App Store Editor’s Pick and win a ton of awards. That means the art needs to be worth the price people paid to download the game. It needs to be extraordinary! It needs to be… polished.

 

DesignBlog-Noria-Polished

Step 5: Aesthetic Polish

Polish is a game design term for taking your finished product and finishing it again so it’s even better – much like shining a shoe with shoe polish. You want to make your Level shine! If you’re making an island paradise, it needs to be the most relaxing paradise the player has ever experienced. If it’s a scummy slum in a city, you need to make that slum as dirty as possible. Everything needs to be pushed to the extreme.

My personal philosophy is that I want to turn every Level in the game into my favorite one. Obviously, I know that can’t happen. But at least while I’m working on it, I can take something boring and give it life. Speaking of which, this is usually where animation enters the picture.

animate (verb)

1530s, “to fill with boldness or courage,” from Latin animatus past participle of animare “give breath to,” also “to endow with a particular spirit, to give courage to, enliven,” from anima “life, breath”

Animation is the most time-consuming part of aesthetic design, and it requires a lot of setup as well. It makes sense for this to come last. But it’s definitely the most important artistic layer. Bad video games tend to feel frozen and stale: great games are always in motion, even when everything appears still. I think our modern brains are conditioned to assume that a screen containing no motion is frozen, as if the app crashed. If you look at games with a high level of polish (Blizzard’s Hearthstone comes to mind), there’s always something moving around to give the player the illusion of life. The goal of polish is to make your game appear to crackle with the spark of life. See for yourself:

Pretty different, huh? Our water shader adds some much needed liveliness to the water, and makes it feel like a rushing stream. Buttons now move and bounce under Obe’s weight. An animated glyph on the ground lets you know where you’ve just clicked. The lamp posts are now chains dangling from the ceiling, which lets them sway gently on a loop.

The other perk of animation is that it allows you to add a third sense to the game: touch (or, feel). In a very real sense, players can only experience your game using their eyes and ears. But if you do your job right as a game designer, certain elements in your game will make the player feel things. Have you ever gotten hit in a video game and exclaimed out loud “ow!” after seeing what happened to your avatar? You didn’t actually feel pain, but something about the experience was immersive enough that it made you connect with your character. That’s what polish is for. That’s how games rise to the top!

 

yellow-happy-smile-526968

forever and ever and ever and ever and ever and ever and ever

Step 6: You Never Finish, This Goes On Forever

Here’s the dirty little secret about my strategy for artistic polish: I’ll never be finished. I will never finish this game. I will work on this game every day until I am dead. It doesn’t even matter if I’m improving the artwork, even if I’m actively making everything worse I will never finish anything in this game.

Whoops! That’s not what I meant to say. Where was I?

Eventually, you need to stop working on a Level so you can move on. This is always a heartbreaking moment in game development. If I could choose any superpower, I would choose a very specific one – the ability to do things on my computer without time slipping through my fingers like grains of sand into an endless void.

[  . _ . ]

You have to move on so you can finish the rest of your game, so when do you do that? It’s at the point where your hours of input are only reaping very marginal gains. People won’t spend an eternity looking at your Levels, so you shouldn’t spend an eternity working on them either. If anything looks truly awful at launch, you can always sneakily patch in fixes that you missed. Just say you’re fixing bugs. and blame the programmer!

Besides, I can always improve the artwork again when we remaster Where Shadows Slumber for BlackBerry…

 


 

I’ve been working on this blog post for too long, and now my hours of writing input are reaping only marginal gains. Time to end this post. Thanks for looking at this inside scoop into our process! If you’re wondering why game development takes so long, imagine doing this for all 38 Levels in the game. That’s not even including the cutscenes…

Say, that gives me an idea for another blog post!

 

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

We hope you enjoyed this deep dive into our development process. You can find out more about our game at WhereShadowsSlumber.com, ask us on Twitter directly using the handle @GameRevenant, find us on Facebookitch.io, or Twitch, and feel free to email us directly at contact@GameRevenant.com.

Frank DiCola is the founder of Game Revenant and the artist for Where Shadows Slumber.

 

Unity 2018!

For those of you who haven’t been keeping up with current events in the indie game development space, there’s something really important that’s happened recently that you should probably know about.

It’s 2018!

Which leads me to another topic that we can spend some time discussing – Unity 2018!

 

Unity

Before we talk about Unity 2018, let’s discuss Unity itself. Unity is the game engine in which we’ve been developing Where Shadows Slumber for the past two and a half years, and even longer ago, when we were working on SkyRunner. Developing in a game engine makes things a lot easier for the little guys like us, because we don’t have to worry (as much) about things like platform-specific dependencies, rendering pipelines, mipmap implementations, etc. Without having to worry about that nitty-gritty stuff, we can spend our time focusing on the more grandiose parts of the development of WSS.

So the question is – how has working with Unity been?

1200px-Unity_Technologies_Logo.svg

Unity!

Overall, Unity is awesome. It has somehow managed to find the right balance between an engine that you could use to make a AAA game, and one that you can use in a small, bureaucratically-challenged team. This alone is a great reason to use Unity – compared to using more complex engines like Unreal, it’s much easier to get up and running from scratch.

Of course, there are trade-offs, and this is a particularly big one. In order to avoid inundating newer users with game development intricacies and high-level concepts, Unity does a lot of that stuff for you, behind the scenes. While this is awesome in a lot of cases, there are some cases where it can be more of an issue. Imagine you’re an experienced game developer, with a sizable team, who wants to do something very specific in the backend. There’s a decent chance that Unity will have hidden that part of the engine from you, or at least made it difficult to interact with.

This tradeoff is, at its core, the reason that you would or wouldn’t want to use Unity. The next most important feature is the ease with which Unity allows you to develop on multiple platforms. All of your development is platform-agnostic, and you only choose the platform as you’re compiling. Is your Android game a success, and you want to build it for PC? Simply hit a different button, and Unity takes care of the rest. I don’t have too much experience with other engines, but this seems to be a place where other developers give Unity a lot of credit, and I think it’s deserved. I can’t imagine having to go through all of the development we’ve done multiple times for different platforms.

Beyond these bigger points, there are a few other things that might sway you, though they’re probably a little less important:

  • Unity is very UI-based, which means that it might be a little annoying for a hardcore programmer, like myself, whereas this probably makes it easier for someone with less coding experience, like Frank.
  • Unity is a sort of one-size-fits-all solution, whereas some other engines are ready-made to create certain types of games. For example, Unreal has good support for creating FPS games. If I were to make an FPS game, using Unreal would probably give me a bit of a head start on Unity.
  • The only language Unity supports is C#. C# is a pretty awesome language, but for those of you who hate C#, or strongly-typed languages in general, it may take some adjusting.

Again, I want to say that Unity has been great for us, and I would probably use it again if I were to start another game. Frank and I wouldn’t have gotten to where we are with Where Shadows Slumber if it weren’t for Unity.

 

Unity 2018

I mentioned earlier that Unity does a lot of stuff for us, and I specifically brought up rendering pipelines. The danger of using a game engine (that you didn’t make yourself) is that other people are making decisions for you, and those decisions are set in stone to a certain degree. On one hand, we didn’t want to mess with the collision system, so we were glad to have it. On the other hand, we ended up in a position where we did want to mess around with the rendering pipeline, and we weren’t able to.

Enter Unity 2018.

image5_rs

The Unity UI, blatantly stolen from one of their blog posts.

I normally don’t pay too much attention to the ins and outs of the various updates that Unity makes. They’ve been marching out updates, both major and minor, for a while now, and we’ve just been going with the flow. Unity 2018, however, has managed to catch my eye. Unity recently released a blog post describing the updates they’ve been making to graphics and rendering in Unity 2018, and I have to admit that I’m pretty excited about it.

As I mentioned before, Unity does a good job of riding the line between too-complicated-for-new-users and not-powerful-enough-for-power-users, and the updates described for Unity 2018 somehow manage to play to both sides. If you’ve ever held a conversation with me about Unity and Where Shadows Slumber, then you know that I’ve been struggling with getting shadows to render the way I want, while also maximizing the efficiency of the rendering pipeline. Fortunately, Unity 2018’s focus on graphics and rendering has provided two huge features in this area, one for each of the two camps.

Scriptable Render Pipelines is the feature that I’m excited about, as it’s the feature aimed toward the entrenched coder. Rather than using the hard-coded rendering pipeline that we’ve been wrestling with for the past two years, we can create our own rendering pipeline that does exactly what we need it to.

“Programmers can now write custom renderers tailored specifically to their project.”

This is a huge boon to us, and to game developers everywhere. Rather than hacking together a shader that uses Unity’s shadow-mapping inefficiently, we can (hopefully) create a rendering pipeline that performs shadow-mapping exactly how and when we need it. This should result in more efficient rendering, along with less headache while writing shaders.

Shader Graph is the other great feature Unity 2018 will have, and is targeted toward less code-inclined users. Unity provides a standard shader with a bunch of options, so you can create the materials you want. However, if you need more customization than the standard shader provides (like we do), you’re suddenly thrust into the depths of shader-writing. With a masters degree in computer science, I’ve been just barely keeping up with writing our shaders, and there’s no way that Frank would have been able to do it. This is really a bummer, as the artist tends to know a bit more about the “look” they’re trying to get.

“[I]t’s simple enough that new users can become involved in shader creation.”

Unity 2018’s Shader Graph changes this – rather than writing complex shader code, Unity exposes a simple interface for creating shaders graphically. This would allow an artist with no coding experience whatsoever to build a custom shader to display things exactly as they want – giving the artist the control they need over the “look” of the game, and allowing the programmer to focus on the game itself.

shadergraph

A sneak preview of Unity 2018’s Shader Graph UI

I’m sure that Unity 2018 comes with quite a few quality-of-life updates, as well as some other new and interesting features. For me, however, it’s all about those rendering updates!

 

Beyond Where Shadows Slumber

A friend of mine recently asked if I would use Unity for my theoretical next project, and if I would recommend it to someone just starting on a game. The answer I gave him is one that applies to every question – it depends. In fact, it mostly depends on the factors described in the first section.

Overall, I’m inclined to say that I would use Unity again. After over four years, I’ve come to know it pretty well. It’s powerful, and allows you to create and iterate pretty quickly. That said, there are some exceptions; I would probably pass on Unity for my next project, or at least do some more research, if:

  • I had very specific backend/optimization requirements
  • I were working with people who had a lot of experience with a different engine
  • The scale of the game were much bigger
  • The game involved a lot of networking/server concerns

There are probably other factors that come into play – basically, it pays to do some research before you dive in. I would recommend Unity, but more than that, I would recommend knowing what you’re getting yourself into. There’s nothing worse for your game than getting halfway through it in an engine that won’t work for you in the end.

If you’re anything like me, at this point the word “Unity” no longer sounds like a word. I’m gonna take that as a sign and wrap this post up; I hope I was able to answer any questions you might have had about working with Unity, and that I got you pumped for Unity 2018!

 

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

If you have any questions about working with Unity, or if you have any other questions about Where Shadows Slumber, feel free to contact us! You can always find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebookitch.io, or Twitch, join the Game Revenant Discord, and feel free to email us directly with any questions or feedback at contact@GameRevenant.com.

Jack Kelly is the head developer and designer for Where Shadows Slumber.

Problem Solving: Design and Complexity

Game design and development is a complicated process. Creating an intricate tapestry of player interaction, incentive, and reward can be quite difficult, and you will no doubt run into trouble along the way. This is a simple fact of game development – in fact, this phenomenon represents most of the time you’ll spend working on your game. Therefore, you shouldn’t worry about it when that trouble finds you! However, an important part of how polished your game ends up, how long it takes to make, and whether or not you even get a chance to finish it is how you handle the issues you run into.

At its core, a game can be described by a set of rules which govern gameplay, and a starting game state. A match-three game, for example, can be described by the following rules:

Simple match-three rules

  1. The game starts with a grid of colors.
  2. Any three or more adjacent cells of the same color disappear, granting points to the player.
  3. If there is an empty cell, the cells above it slide down to fill in the space, generating a new cell at the top.
  4. The player may switch the colors in two adjacent cells.
  5. The game may end when the player reaches a certain number of points, or when they make a certain number of moves, or if there are no available moves, etc.

Obviously, these rules don’t encompass everything that happens in a game, and the rules get much more complicated very quickly for more complex games. These simple base rules define your gameplay, but they very quickly become more intricate as you add features and functionality. Let’s look at a few updates to our match-three example:

  • If we want to add a type of cell which can’t be moved, we would have to change rule #4 to “The player may switch the colors in two adjacent cells unless either of those cells is unmovable”.
  • If we want to add an “exploding” cell which eliminates nearby cells, we would have to change rule #2 to “Any three or more adjacent cells of the same color disappear, granting points to the player, and if one of them is an exploding cell, adjacent cells also disappear”.

The base rules handle 90% of the gameplay situations, but we have to add special provisions for exceptions of those rules. In game development (and computer science in general), these exceptions are called edge cases, and, as necessary as they are, they’re super annoying. Your code will include edge cases, and it should, but you have to be careful with them (edge cases may be considered a type of hack, which I discuss in one of my previous blog posts), and you should avoid them when possible. One of the primary ways to do that, depending on your game, is through design – rather than complicating your codebase, you can try to design your game and/or levels in such a way that you don’t need to change your code.

 

An Example from Where Shadows Slumber

Let’s take a look at the inspiration behind this post – a case I ran into in Where Shadows Slumber where I faced such a decision.

1-1 goal

Ominous!

At the end of each level, there’s a ‘goal’ space. When Obe steps on it, it triggers the end-of-level sequence to begin – the lights fade, Obe walks out of the scene, and then the next level loads. The question is, given the game rules, how can I make this happen? I could have added a specific code path for this case, but I realized that I could use some already-existing mechanics to create this effect:

  • The machinery behind buttons can already handle “trigger something when Obe steps on a space”, including a delay for ending the level.
  • The machinery behind Obe walking in at the start of the level allows us to redirect his movement.

This is one way of handling an edge case – try to reduce it into an example of something you already have, thus changing it from an edge case into a normal case. Now we’ve changed the ‘goal’ space into a different-looking button with a redirect space.

Now, there’s another situation involving the goal space where I was given a similar choice. In some levels, there’s a space both to the left and to the right of the goal space. This enables a situation in which the player moves onto the goal space, and then away from the goal space. This creates a problem: the end-of-level ‘button’ will trigger, the lights will dim and the next level will load, but Obe hasn’t left the scene – he’s still just standing there!

ezgif.com-video-to-gif

Well that’s not quite right…

This is a problem I can solve by changing the rules, or by changing the design. The rules for redirecting Obe’s movement only apply when he doesn’t already have a destination. In order to handle this situation, I could add a case that says “if the current node is the goal node, do the redirection”. This requires that I add code to mark a node as the goal node, and to check if the current node is the goal node. While this code would be pretty small and easy to write, it still adds to the overall complexity of the codebase. Is there a way to avoid doing so?

There is, in fact, and it’s quite easy. If we simply remove all of the places where this could happen, then we don’t have to worry it! We’re not “solving” the problem in a conventional sense – if the configuration of spaces were to come up again, the problem would still occur. However, by changing the level design, we remove any chance of that happening.

1-1 goal with boxes

I’ll have Frank make something more on-theme to fill that space

This is another way of handling an edge case – by making a small change to the level design, we’re able to avoid making changes to the codebase. This prevents our code from becoming needlessly more complex, making it easier to understand and maintain. While not every problem can be solved in such a simple way, there are many that can, and keeping an eye out for them is a great way to avoid unnecessary code complexity.

 

Living on the Edge

I keep talking about edge cases and code complexity like they’re bad things. But an entire game is a very complex thing – doesn’t it make sense for the codebase behind it to be complex as well?

There’s nothing inherently wrong with complexity in your code; a well-implemented cache invalidation algorithm is a beautiful thing, complex as it is. What isn’t beautiful is needlessly complex code. The logic in this code is usually hard to follow, makes assumptions, and leaves a lot of small bugs that you’re unlikely to notice right away. This is a recipe for disaster, because every time you try to make a small change, you have to wade through a swamp of half-thought-out code paths, and you end up adding more complexity just so that you don’t have to deal with the complexity that’s already there!

The biggest problem is that it’s very hard to tell the difference between code that’s complex because it has to be (good) and code that’s complex when it doesn’t have to be (bad). The way I deal with this is to try and realize when the code I’m writing is starting to become very complex. Even though I might only be fixing one bug or working on a specific part of the implementation, I try to take a step back and look at the problem that I’m trying to solve, and how I’m solving it. If the problem is a complex one (cache invalidation), then I accept that it’s gonna be a complex algorithm, and keep writing it. If it’s not a complex problem (sorting), I take another look at my code and see if there’s a better way to do what I’m trying to do. In this way, I continuously re-evaluate the complexity of my code, and whether or not I need it.

Hack

Six while loops isn’t too many, right?

I know that “I just know when it’s too complex” might not be the most satisfying answer for those of you who often run into issues of complexity. That feeling is something that you pick up as you do more and more coding, and especially as you revisit your own code – “wow, I can’t believe I wrote such stupid code”. For those who want a more concrete answer, here are some of the ‘red flags’ that I try to keep an eye out for when assessing the complexity of my code:

  • A lot of ‘if’ statements – If your code has a lot (and I mean a lot) of random ‘if’ statements (especially nested ones), then you might want to take another look at the design.
  • “I don’t know…” – If you can’t quickly and easily determine what each piece of your code is meant to be doing, your design might be too complex.
  • Guessing – If you ever find yourself just “trying things” and “seeing if they work”, it’s a clear sign that you don’t understand your code well enough. Take some time and get to know it!
  • Duplicated code – If you have the same block of code copied into a few places, you should revisit your design. Either that block belongs in a helper that you can reference, or the control flow of your code needs to be reconsidered.
  • Asynchronicity – If you’re doing anything asynchronous, you should give your code another look. I know you probably did it right the first time, but asynchronicity is one of the most difficult parts of computer science, and it’s always worth double-checking.

There are a lot of other things that you might notice about your own code and its complexity – these are just a few quick guidelines off the top of my head. Hopefully they help!

 

But Game Development is Fun!

Anyways, I hope I didn’t scare you away from computer science. If anything, I wanted to instill a healthy fear of needless complexity, and I hope that you’ll do what you can to reduce that complexity – whether by redesigning your code or redesigning your levels!

 

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

If you have any questions about code complexity and how to design around it, or if you have any other questions about Where Shadows Slumber, feel free to contact us! You can always find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebookitch.io, or Twitch, and feel free to email us directly with any questions or feedback at contact@GameRevenant.com.

Jack Kelly is the head developer and designer for Where Shadows Slumber

Hacks Versus Designs

I remember back in the day, when computers and programming were first becoming somewhat ‘cool’. Back then, the coolest thing you could be in the computing world was a ‘hacker’. Hackers were awesome renegades who could tear down opposing systems using nothing but their superior intellect. Being able to hack was one of the best skills you could have. Now, after studying and working in computer science for a while, the term ‘hack’ has taken on a very negative connotation.

When you’re writing code, there are several things that you’re aiming for. The two broadest and most important of these are:

  1. The code works – it does what you intend for it to do.
  2. The code is good – it’s efficient, understandable, and easy to use/improve.

It seems like these two things would go hand-in-hand, and for well-designed code, that is often the case. However, the road to that ‘well-designed’ code is often fraught with terrible, terrible code. So, what’s the intrinsic difference between these two goals, and how does it lead to bad code?

 

boolean

Hack First, Ask Questions Later

When you’re working on a large, intricate system, and you need to add something or make a change, these two goals lead to two different types of results – a hack, or a design:

  • A hack is a piece of code with only the first goal in mind – you’re just trying to ‘make it work’. You don’t want to put a lot of thought or time into the implementation, you just want it to work.
  • A design has both goals in mind – you’re spending time to come up with a good solution. You’re willing to work a little harder to end up with a more robust, long-loving solution.

Designing a solution to a task leaves you with good code. It’s easy to understand, easy to use, and easy to update. The algorithm makes sense, not just in terms of “does it do what I want”, but also in terms of “does it make sense with the theory behind it”.

Looking at these two descriptions, it’s pretty easy to see – designs are better than hacks. So why would anyone ever want to use a hack to get something done? There are a few reasons.

Designs take more time. You have to come up with a solution, consider its long-term viability, consider how it will interact with every part of your system, present and future, tweak it accordingly, and make sure that it still matches the theory of your application. A hack, on the other hand, involves simply coming up with a quick and dirty solution, and implementing it.

Designs require deeper understanding. In order to fully understand the impact of your newly-designed code, you have to completely understand the current state of your application, remember all of the assumptions you made when coding it, and ensure that your new stuff won’t interfere with any existing stuff (Note that this is much harder to do on a larger team, as there are areas of the code you may not be as familiar with).

Designs are often much larger in scope. When designing a solution, it will often involve creating a ‘system’ or ‘engine’ of sorts. Not only does this take longer to think through and implement, but it also opens the door to a lot of subtle interactions between systems. Hacks are (usually) much more localized – “I’m gonna make this hack here, but I won’t use it in other places”.

You don’t want to spend a lot of effort on code that will be replaced eventually. This is really just a combination of the above points, but it’s an important reason why hacks exist. If you have to update a small piece of code, but you know that you’re going to come in and change the whole thing next month anyways, why would you put a lot of time and effort into designing a solution when a quick, hacky fix will do the trick?

Looks about right Cropped

This is what happens when you leave hacks in your code!

 

Here’s An Example

Let’s say you’re you’re working on a pretty simple game in a pretty simple game engine, using a pretty simple programming language (hint: this means I’ll be using pseudo-code rather than real code). You’ve got your character on the screen, and you want to make him move back and forth along some flat ground whenever you hit an arrow key. You might start out with something like this:

if (keys.leftArrow) {
  dudeGuy.position.x -= 10;
}

if (keys.rightArrow) {
  dudeGuy.position.x += 10;
}

Pretty simple and straightforward – if you’re pressing the left arrow key, move your dudeGuy to the left, and if you’re pressing the right arrow key, move him to the right.

So, you use this code for your movement, and it works, and you continue working on your game. Then, suddenly, you have an epiphany – what if your dudeGuy could jump? You add a variable and hook it up:

int jumpingTimer = 0;

...

if (keys.spaceBar && jumpingTimer == 0) {
  dudeGuy.position.y += 30;
  jumpingTimer = 3;
}

if (jumpingTimer > 0) {
  dudeGuy.position.y -= 10;
  jumpingTimer--;
}

As you continue making your game, you design some levels where you realize that you want the gravity to be less strong, so you have to account for that:

float gravity = 10;

...

if (keys.spaceBar && jumpingTImer == 0) {
  dudeGuy.position.y += 30;
  jumpingTimer = 30 / gravity;
}

if (jumpingTimer > 0) {
  dudeGuy.position.y -= gravity;
  jumpingTimer--;
}

Then you realize that your back-and-forth movement looks pretty choppy, so you decide to add some ‘smoothing’, so your dudeGuy speeds up and slows down:

int movingLeftTimer = 0;
int movingRightTimer = 0;
int jumpingUpTimer = 0;
int jumpingTimer = 0;
float gravity = 10;

...

if (keys.leftArrow) {
  if (movingLeftTimer < 3) {
    movingLeftTimer++;
  }
} else if (movingLeftTimer > 0) {
  movingLeftTimer--;
}

if (movingLeftTimer > 0) {
  dudeGuy.position.x -= 10 / (4 - movingLeftTimer);
}

if (keys.rightArrow) {
  if (movingRightTimer < 3) {
    movingRightTimer++;
  }
} else if (movingRightTimer > 0) {
  movingRightTimer--;
}

if (movingRightTimer > 0) {
  dudeGuy.position.x += 10 / (4 - movingRightTimer);
}

if (keys.spaceBar && jumpingTimer == 0) {
 dudeGuy.position.y += 30;
 jumpingTimer = 30 / gravity;
}

if (jumpingTimer > 0) {
 dudeGuy.position.y -= gravity;
 jumpingTimer--;
}

And,  before you know it, with only a few changes to what we were trying to do, we end up with a piece of code that’s incredibly messy, almost impossible to understand, and prone to bugs and off-by-one errors. Honestly, I just wrote this thing, and I have no idea what it’s supposed to be doing.

Now, this example is a bit of an esoteric one, just to prove a point. However, it is definitely not the worst code I’ve ever seen (or written), and that’s saying something. What should we have written instead? Well, if you couldn’t guess, the above code is an example of a hack (or a number of hacks put together). Rather than examining what it was we needed in the long run, we repeatedly implemented something that did the job in the short term. So, let’s make a design for this use-case, and think about what we need overall.

We want to be able to move left/right, jump, have different values for gravity, and have smoothing on our movement. This sounds a bit like actual physics, so lets steal some important concepts from them – acceleration and deceleration. We’ll determine some rules that match our design, modify the dudeGuy’s acceleration in each direction based on those rules, and then move his position all at once:

float maxSpeed = 10;
float acceleration = 3;
float jumpAcceleration = 10;
float gravity = 3;
float friction = 5;
float minY = 0;

float vx = 0;
float vy = 0;

...

// If the left arrow key is down, accelerate to the left
if (keys.leftArrow) {
  vx -= acceleration;
}

// If the right arrow key is down, accelerate to the right
if (keys.rightArrow) {
  vx += acceleration;
}

// If the spacebar is down and the dudeGuy is on the ground, accelerate upwards
if (keys.spaceBar && dudeGuy.position.y == minY) {
  vy += jumpAcceleration;
}

// Accelerate downwards for gravity
vy -= gravity;

// Decelerate for friction
if (vx > 0) {
  vx -= friction;
} else if (vx < 0) {
  vx += friction;
}

// If we're going to fast to the right, slow us down to the max speed
if (vx > maxSpeed) {
  vx = maxSpeed;
}

// If we're going to fast to the left, slow us down to the max speed
if (vx < -maxSpeed) {
  vx = -maxSpeed;
}

// Update the dudeGuy's position based on our current velocity in each direction
dudeGuy.position.x += vx;
dudeGuy.position.y += vy;

// If the dudeGuy is below the ground, move him up to ground level
if (dudeGuy.position.y < minY) {
  dudeGuy.position.y = minY;
  vy = 0;
}

While we have a similar number of lines of code here, it’s much clearer what’s happening on each line. Every block serves an easy-to-understand purpose, and making changes to the ‘rules’ of movement is very easy. There are a lot of different ways to improve this code, depending on your game’s overall design, but this is a decent, and most importantly simple, place to start.

Another important feature of this piece of code is that it is well documented. Every block is pretty small, but it still has a comment describing the purpose of the block. This is an extremely important part of programming in the context of larger systems – you want to make sure that you (or anyone else) can quickly understand what your code is doing, especially in complex cases. Even though some complex logic might seem simple to you, it’ll definitely seem more difficult when you come back to it in 6 months!

 

A Necessary Evil

Unfortunately, hacks are a necessary evil. While I would love to only ever have to deal with and implement beautifully-designed code, that world doesn’t exist. There’s always a timeline, there are always changing assumptions and new features, and there’s always someone who wants it to be finished yesterday. Inevitably, you’re going to have to write some code quickly, implement a feature that’s likely to change, or come up with a simple ‘solution’ to a difficult problem. In cases like this, you’re forced to use a hack.

Hack

I mean, it works… technically…

It’s not all bad, though. While hacks in general are pretty bad, they can be manageable if you make sure to use them correctly. In fact, I would be willing to bet that any system currently in production (of a certain size) contains quite a few hacks. There are certain qualities that hacks can have which make them a little bit more manageable, and you should try to aim for them whenever you find yourself implementing a hack:

  • Understandable – It’s important that, whatever your hack is, anyone else looking at the code can understand what you were trying to do, and how your hack works. This means leaving a lot of comments around your hack, as well as simplifying the logic as much as possible.
  • Localized – If you have to hack something in, you want it to only be in one place. Every time that code path is used, there’s a chance that something will go wrong. If your hack only touches a small part of your system, then its negative effects will be much less noticeable. This means that frequently-used code paths should never really have hacks in them, while hacks in rarely-used code paths are more acceptable.
  • Known – This is, to me, the most important part of making a hack. If you hack something in and then forget about it, when your system starts failing, you won’t know where to look. If you make sure you remember it (by writing it down somewhere and then telling every person you know), then you’ll know where to look if something goes wrong. On top of that, you’ll always have that hack in the back of your mind, so you’ll be more likely to think of a good design to replace it.

If you follow these guidelines and make sure to try to go back and fix them, then putting hacks into your code won’t end up destroying you.

I hope this was helpful to those of you just starting out in game development – or anything which involves designing complex systems! For those of you who already know a little something about computer science, I hope this at least reinforced your burning hatred of hacks!

 

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

If you want to know more about how to deal with hacky code, or what kind of hacks are in Where Shadows Slumber so that you can exploit them, feel free to contact us! You can always find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebookitch.io, or Twitch, and feel free to email us directly with any questions or feedback at contact@GameRevenant.com.

Jack Kelly is the head developer and designer for Where Shadows Slumber.