Mechanic Spotlight: Shaders

Last week I promised I would write a more technical post. So this week, rather than talking about something I do know about, I’ll be talking about something I don’t know anything about, and then you can all tell me how wrong I am! Which brings me to the topic for this week – shaders!

Where Shadows Slumber has a relatively distinct visual style – the bright solid colors, the crisp black shadows, and the sharp line that separates them. Much of the artistic style is due, of course, to Frank’s art. However, a lot of it is also due to the custom shading that we set up.

screen_1920x3412_2017-03-20_22-04-51

Bright colors and sharp edges!

What is a Shader?

Unity describes a shader as a ‘small script that contains the mathematical calculations and algorithms for calculating the color of each pixel rendered, based on the lighting input and the Material configuration’. Basically, shaders determine how the rendering will happen, and how the look of your scene will be affected. Shaders give you a lot more control over exactly how everything will be calculated and rendered – lighting, shadows, gloss, reflections, etc. It’s a lot, and shaders get very complicated very quickly, but they allow you to craft a very distinct visual style.

Shaders are (generally) used by creating a material and specifying what shader that material should use for rendering. This allows you to use a shader for multiple materials, with potentially multiple different configurations.

Now, let me give you a quick disclaimer – I know enough about shaders to put together this one for Where Shadows Slumber, but I am definitely not an expert. So take everything I say with a grain of salt, and if you are an expert on shaders, feel free to let me know, because I’m sure there are some things I could be doing better.

I should also mention that, while I believe you can write CG shaders for some other engines, any specifics in this post will refer to shaders as they are used in Unity. Similarly, since Where Shadows Slumber uses forward rendering, this shader will also will be set up using forward rendering.

 

How real light works, and why that’s bad

Unity comes with something called the standard shader, which lets you get a lot of different visual effects without creating your own shader. It’s very powerful and very useful – so why not use it here?

The problem with the standard shader is that it’s too realistic. It calculates lighting based on the way that lights actually work, which is not what we want. A light in real life fades over distance, so it’s brightest at its center and much darker at the edges. While this is accurate, we want all areas that are in light to be the same brightness. Otherwise, the player would be too bright, but the edges of the light would be too dark.

shadercomparison2

The Unity standard shader (left), and the Where Shadows Slumber shader (right)

Enter our custom shader – in order to get the lighting right, we had to write our own shader, with a custom lighting model. This was a daunting task, but I’ll go through the overall steps we took to get there.

 

Not the most difficult shader

There are two types of shaders in Unity – Surface, and Vertex/Fragment shaders. Surface shaders are a little easier to write and understand, but they give you less control, as they do a lot of the calculations themselves (in reality, a surface shader is just a wrapper that gets compiled down to a vertex/fragment shader). Fortunately, we don’t really need to get too deep into the calculations for lighting and stuff – we’ll just let the surface shader calculate the lighting, and then we’ll use the results to determine what to draw.

So, we know that we have to make a surface shader. What exactly does that mean? How do we actually go in and start changing things? What does a shader really look like?

Drumroll please…

 

Our surface shader

Shader "CrispLightBasic_NoDir" {
  Properties {
    _Color("Color", Color) = (1, 1, 1, 1)
    _MainTex("Albedo (RGB)", 2D) = "white" {}
  }
  SubShader {
    Tags {
      "RenderType" = "Opaque"
    }

    CGPROGRAM
    #pragma surface surf TestForward addshadow fullforwardshadows
    #pragma target 2.0
    fixed4 _Color;
    sampler2D _MainTex;

    struct Input
    {
      float2 uv_MainTex;
    };

    void surf (Input IN, inout SurfaceOutput o)
    {
      fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
      o.Albedo = c.rgb;
    }

    half4 LightingTestForward(SurfaceOutput s, half3 lightDir, half atten)
    {
      half4 c;
      c.rgb = s.Albedo * _LightColor0.rgb * min(floor(300*atten), 1);
      c.a = 1;
      return c;
    }

    ENDCG
  }
  FallBack "Diffuse"
}

This is the simplest shader that we use in Where Shadows Slumber. It’s pretty self-explanatory, so I’ll let you figure it out.

Alright, I guess we can take a look at what’s actually happening here.

Anatomy of a shader

There are a lot of cool parts to a shader; let’s take a look at them from the top down.

  • Shader "CrispLightBasic_NoDir"

    Starting with an easy one! This just means that we’re making a shader, and giving it a name.

  • Properties {
      _Color("Color", Color) = (1, 1, 1, 1)
      _MainTex("Albedo (RGB)", 2D) = "white" {}
    }

    I like to think of the properties as ‘inputs’ to your shader. When you examine a material using your shader in the Unity inspector, these are the values that you will be able to change in order to get a different look.

    shaderproperties

    A material with our shader in Unity

    The line for each property consists of a name, an identifying string (which is what you’ll see in the inspector), a type, and a default value, in order. So our color variable has the name _Color, the description "Color", the type Color, and the default value (1, 1, 1, 1).

    The possible types for a property are Int, Float, Range, Color, Vector, and 2D (which represents a 2-dimensional texture).

  • SubShader {

    This just means that we’re actually starting the real shader block.

  • Tags {
      "RenderType" = "Opaque"
    }

    Tags are a way of telling Unity some stuff about the shader we’re writing. Unlike the properties above, these are constant to the shader. So, for this shader, we are telling Unity that this shader will always have a RenderType of Opaque.

    There are a few different tags you can use, and each of them have a few different options. In the interest of shortness, I won’t go into all of them here.

  • CGPROGRAM
    ...
    ENDCG

    These directives indicate that the actual CG code is contained between them. The CG code is what does the actual shading.

  • #pragma surface surf TestForward addshadow fullforwardshadows
    #pragma target 2.0

    #pragma statements indicate which shader functions to compile into your shader.

    The target pragma indicates the shader compilation target level – higher targets allow the use of more modern GPU functionality, but may prevent the shader from working on older GPUs. 2.0 is pretty low, since we aren’t going to end up doing anything fancy.

    The #pragma surface directive indicates information about our surface shader, and is always of the form:

    #pragma surface surfaceFunction lightModel [optionalparams]

    Thus, our surfaceFunction is surf and our lightModel is TestForward (both of which we will define later). The optionalparams which we provided are addshadow and fullforwardshadows, which allow meshes using our shader to both receive and cast shadows when using forward rendering.

    This concept of ‘optional parameters’ is kind of vague. Basically, it’s just another way to give information about your shader – this time, the information is about how the actual rendering is done. There are a lot of different options that you can put here, and, unfortunately, it’s not incredibly obvious when you might need one. If you’re not doing anything funky with your shader (lights, shadows, depth-testing, etc.), you’re probably fine. If you are, you might want to see if there are any optional params here you should be using.

  • fixed4 _Color;
    sampler2D _MainTex;

    Remember those properties we declared earlier? Those guys are cool and all, but these are the real variables used by the shader. Any of the properties you declared needs a variable (of the correct type) here, so that your shader can actually use the value you provided! In this case, we’re creating a fixed4 variable for our color value, and a sampler2D variable for our main texture. The data types for these variables are kind of strange, so let’s take a look:

    float, half, and fixed – these all represent floating-point numbers, with different precisions. The precisions are (generally) 32, 16, and 11 bits, respectively.

    – float4, half4, and fixed4 – these are 4-dimensional vector versions of the above types. They’re used for vectors (duh), but also for colors, which are of the form (r, g, b, a)

    sampler2D, sampler3D, and samplerCUBE – these sampler types represent textures; 2D is a 2D texture, 3D is a 3D texture, and CUBE is a cubemap.

  • struct Input
    {
      float2 uv_MainTex;
    };

    The Input structure is yet another representation of information passed to the shader, and generally contains texture coordinates. Texture coordinates must be named uv followed by texture name, and indicate positions of pixels on your textures. There are a bunch of other values you can put here, but, once again, I’m not going to list them all.

  • void surf (Input IN, inout SurfaceOutput o)
    {
      fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
      o.Albedo = c.rgb;
    }

    Ah, finally, here we are! We have made our way to the actual surface shading! This is the surface function that we specified in the #pragma surface directive. This function, at its core, describes the properties of a surface. It takes an Input, which we defined above, and a SurfaceOutput, which actually contains those properties (color, normal, emission, etc.). For our very simple shader, we only care about the color, so that’s the only value that we will provide. Note that it’s marked as inout, meaning that it’s both input and output – it comes in, we make changes to it, and then it gets used later, with those changes.

    The inside of this function is the important part, as it’s telling us what the shader will do at any given pixel position. Fortunately, this is a pretty simply one:

    In the first line, we’re calling tex2D, a function which performs a texture lookup. So we’re saying we want the color of _MainTex at the pixel coordinate provided by IN.uv_MainTex. This should make sense – after all, we created IN.uv_MainTex as a way to point to positions within _MainTex, which is exactly what we’re doing. Once we have the pixel color from the texture, we’re multiplying it by our _Color variable, which will result in a ‘tinted’ version of the texture. Finally, we are storing the result in a fixed4 variable, or a 4-dimensional vector of fixed-precision floating-point numbers.

    In the second line, we’re simply assigning the value we just calculated to the Albedo property of the SurfaceOutput variable o. The albedo color of an object is just the color of that object without any external influences (mainly, light). Since we haven’t applied any lighting yet, this is the property we want to set.

    So this function is pretty simple – it just gets the colors from the texture and tints them with the color we provided from the Unity inspector. Note that this function doesn’t return anything – it simply sets values on the SurfaceOutput object, which is used later.

  • half4 LightingTestForward(SurfaceOutput s, half3 lightDir, half atten)
    {
      half4 c;
      c.rgb = s.Albedo * _LightColor0.rgb * min(floor(300*atten), 1);
      c.a = 1;
      return c;
    }

    When we declared our surface shader using the #pragma surface directive above, we also specified a lighting model, which I so cleverly never renamed from TestForward. This function is where we apply our lighting, and it describes how light affects things. In most cases, the surface shader will handle this for you. However, since we want to give our lighting a somewhat special look, we need to mess around in here too.

    This function takes in our SurfaceOutput object (so we can know stuff about our surface), lightDir (a vector indication the direction the light is hitting the surface), and atten (a number indicating the strength of the light at this point). It returns a vector which indicates the color of the surface after the lighting has been applied. This function will run for every pixel on the surface, which allows us to return different values for each pixel.

    Since our shader is pretty simple, the logic in this function is simple as well. We create a vector, c, which we end up returning. We set its rgb values based on the color of the surface (and some other stuff), and set its a (alpha, or transparency) to 1 (completely opaque).

    The interesting part of the lighting model (and the whole shader) is the single line of calculation here, so I’ll go through it step by step.

    • c.rgb – This is the actual color value of the variable c, which is what we want to mess with.
    • s.Albedo –  This is the value we set in our surface function. It’s the actual color of the object at this point.
    • * _LightColor0.rgb – Ah, a piece of magic! We’re multiplying the color by something here, but what? Our lighting function will be called on any pixel once for each light that hits it. These are called passes. In forward rendering, _LightColor0 represents the color of the light that this pass is applying. So, we’re just tinting our surface’s color by the color of the light.
      There are two things to note here. These lighting passes only apply to per-pixel lights. Lighting is expensive, so the Unity quality settings will max out the number of per-pixel lights you can have. In order to create our look, we needed every light to be per-pixel, so we had to increase the cap.
      The other thing is the concept of blending. Since we may have multiple lights hitting the same spot, we’ll have two different color values for that spot. Unity needs to know how to combine them, and the default behavior is additive. This means that overlap between lights will be twice as bright, which may give it a ‘washed-out’ look. I won’t cover it here, but there are ways to change the blending behavior to achieve the look you want.
    • * min(floor(300*atten), 1) – Here’s the interesting part. atten tells you how bright the light is at this point; it gets lower as you move away from the source of the light. A normal lighting model would multiply the color by atten, which would result in a nice fading look. However, we don’t want any values in between 0 and 1. We want the light to be either on or off. So, this funky piece of math basically says ‘if the attenuation is above 0.003, show the whole color. Otherwise, show a shadow’. This is how we disregard the ‘fading’ of the light without disregarding where the light actually reaches.
  • FallBack "Diffuse"

    We started with something simple, and it looks like we’re gonna end that way too. The fallback shader is the shader that should be used if, for whatever reason, our custom shader is unable to be run on the GPU. This could happen if we’re running on older hardware, we specified too high of a shader compilation target level, or we simply made a mistake in the shader code. I find that the latter is almost always the case, as writing shaders correctly is so confusing as to be near-impossible.

    screen_1920x3412_2017-03-21_08-18-43

    The beautiful color of a broken shader!

    Note that the fallback should be inside the shader block, but outside of the subshader block.

Putting it all together

Going through the shader piece by piece took a lot longer than I thought it would, so I won’t go too in-depth here. Most of the shader is boilerplate, so there’s not too much happening anyways.

Basically, we’ve built a surface shader which accepts a texture and a color. We tell that shader that it’s opaque, that it should use shadows, and that it should compile to a very low set of GPU requirements. We also tell it to use a custom surface function to describe the properties of the surface, and a custom lighting model to figure out how light affects that surface. Together, these functions will tell us exactly what color each pixel should be rendered as.

Within the surface function, we simply grab the color from the provided texture, tint it with the provided color, and pass it along. Within the lighting function, we either return the color of the surface, tinted by the color of the light (if the pixel is within the light), or return the color black (if the pixel is in shadow). In this way, everything that is at all touched by light will show up as its full color, and anything in shadow will show up as a crisp, dark black.

Additional resources

Hopefully this adventure into shader-land has given you an idea of how shaders work, and what it was like to work with them. Like I said, I’m not a shader expert, so there may be some stuff you still want to know about shaders. Here are a few links that helped me out in my travels:

There are probably a hundred other pages I ended up reading on my quest for shader mastery, but I can’t find/remember all of them now. Anyways, sorry for going on about shaders for a metric year. I hope you learned a bit about the mysterious world of shaders, and if not, I just hope you didn’t die of boredom. Either way, if you got to this part of the post, well done!

As always, let us know if you have any questions or comments about shaders (or anything else)! You can always find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebook, itch.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.

Advertisements

Where Shadows Slumber at PAX!

The Where Shadows Slumber team has just returned from our biggest event yet. That’s right, this past weekend was PAX East! If you’re just starting to read this blog because you found out about us at PAX, then welcome!

PAx2

An awesome sign for an awesome show

For those who don’t know the details, we were accepted for the PAX East Indie Showcase, which showcases the “best indie [mobile] games you’ve never heard of”. As Frank mentioned when we first found out, we were totally honored to have been chosen, and the showcase really delivered. It was a wild weekend, and I’m here to tell you all about it!

 

What Happened?

We got to the convention center early on Friday morning, and it totally blew away our expectations. Despite knowing the scale of the event, it didn’t really hit us just how big it was, and that was just the main Expo Hall. We set up at our table, and before we knew it, PAX East had begun!

PAX3

Even this shot doesn’t do justice to the size of the hall

We spent the next eight hours showing off Where Shadows Slumber, talking to hundreds of people about the game, getting a ton of feedback, and completely losing our voices in the process. We’ve done this a lot in the past, but it’s always very refreshing to see new people playing our game. It just feels great meeting people and getting our game in their hands.

Once the main expo floor closed at 6 pm, we took some time to catch our breaths – but before we knew it, we were informed that the members of the Indie Showcase were going to be putting on a panel!

Despite all of the awesome things that happened this weekend, I think the panel was my favorite part. Since I do game development as a side project to my actual job, and I haven’t made any money from it, I never really consider myself to be an ‘expert’ of any sort. It was incredibly validating to have people seeking my advice, and I was surprised to find that I had good answers for (most of) their questions. It’s almost as though I’ve been working on indie games for the past three years or something.

After a passable Boston meal (what’s with all the seafood?) and an almost-full night’s sleep, we were back and ready for more! Saturday is always the busiest day at these conventions, and PAX did not disappoint. From the opening at 10 to the closing at 6, we consistently had a full booth, which was awesome. Fortunately, we didn’t have any obligations on Saturday night, so we hung out with some friends before heading back to the hotel early, in preparation for daylight savings time.

We had been taking Uber to the convention center on Friday and Saturday, but since we were leaving on Sunday, we decided to drive in from the hotel. Apparently, a lot of other people had the same idea, and Frank ended up sitting in traffic for over an hour; I ditched him and walked the last mile, and I was still late.

Despite the inauspicious start, Sunday was a great day too. One of the biggest problems with these shows is that we’re at this awesome event, but we spend the whole time at our own booth. It’s great telling people about Where Shadows Slumber, but it’s nice to see some other stuff. Fortunately, our web developer, Caroline, worked the booth with us for two hours or so, so Frank and I took turns exploring the expo floor. There were a lot of awesome games, and I still wish we had had time to see more of them!

After a great three days, we packed up and headed home! The weekend was incredible, and it felt so good to share it with our fellow indie game developers and show off Where Shadows Slumber.

 

What Did We Learn?

The main thing we learned from this show was that, while people may say less is more, in reality, more is more. This was the biggest PAX East ever, and it was definitely the biggest show we’ve ever been to. To be honest, we really weren’t ready for the scale. We brought five test devices and no power strip, which led to some battery problems toward the end of the day.

PAX1

With only five devices, we often had people watching and waiting for their turn!

The devices and the batteries weren’t the only things we didn’t have enough of. We brought 400 drop cards and 300 Where Shadows Slumber buttons, but we didn’t bring nearly enough. We only had a few business cards left when Sunday started, and we were out of buttons halfway through the day. If we had to do it again, I would make sure we brought a lot more – it’s better to have some left over than to leave anyone empty-handed.

Other than that, the other lessons were things we’ve learned before, but they’re still worth mentioning:

  • Bring hundreds of cough drops – continuously talking to people over the ambient sound of a convention for eight hours a day is a real strain on the voice. I went through almost two bags this weekend.
  • Don’t expect to get anything done – for some reason, I always assume I’ll be able to do some work after the convention ends for the day. Between finding food, getting back to the hotel, and planning for the next day, there’s never time for anything else.
  • Daylight savings time is the worst – yeah, it started this past weekend. Sleep is the most valuable commodity at a convention, and it seems totally unfair that we had to lose an hour of it.
  • Plan ahead as much as possible – we had a lot of trouble finding food on Saturday night, because every restaurant in the area was completely booked. Frank has mentioned it before, but I want to mention it again – plan ahead!

 

_Extra

What’s Next?

I definitely consider PAX East to have been a success, which is a good thing – it’s probably the last big event we’ll be doing for a while. Everyone really seems to enjoy our demo, but they also want the full game, and that means that we have to actually make it! So, the next thing on our schedule is to simply get to work and start putting Where Shadows Slumber together. There are really four big things going on in the immediate future:

  • Cutscene – The final step in creating the demo is to give you all a taste of the storyline. Every show we go to, people ask about the game’s story. As of yet, the demo does not contain any discernible storyline, but Frank is working hard to change that. We’re planning on adding a short cutscene to the end of the demo, which will server as a little teaser for the kind of story you can expect to see in the full game.
  • Testing – Over the last two months, we have designed all of the levels for the final game. However, we don’t know if the players will like our levels, and the best way to find out is to ask them! So, we’re going to be creating very basic versions of the levels we have planned, and send them out to our dedicated volunteer testers to tell us what they think! If you want to sign up to be a tester, simply let us know – you can email us at contact@gamerevenant.com, or send a private message with your email to the official Game Revenant Facebook Page.
  • Art – One of the most important parts of Where Shadows Slumber, I must begrudgingly admit, is the art. As such, we are going to be putting a whole lot of work into the art for the final game! The levels we send out to our testers will not have any art on them, since that’s the part that takes the longest. Once we know that the design of a level is pretty good, we’ll start putting some beauty onto it!
  • Refactoring – This is kind of boring to you non-technology folks, but it’s still important. As projects advance, a lot of technical debt and scope changes cause codebases to become a little unwieldy. Right now, Where Shadows Slumber is a house carefully constructed out of sticks; it’ll stay up as long as we don’t blow too hard. So, in the coming months, I’ll be working hard to redesign the code into a strong mansion of stone (or whatever mansions are built out of) that will serve for a full game.

Aside from these main four tasks, we will of course be updating this blog and trying to keep up on social media. We might also swing by a few smaller shows, but we don’t have any plans bigger than that for the next few months.

A few weeks ago, a fan of the game requested that my next blog post touch on the technical side of our process. As much as I wanted to do that this week, we really felt the need to talk about PAX – it was an awesome whirlwind of an experience, and we wanted you to know all about it! But fear not; I’ll be back again next week with a deep dive on one of the most important and most technical parts of Where Shadows Slumber – the shaders.

 

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

Were you at PAX East 2017? Tell us about your experience in the comments below! You can find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebook, itch.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.

Where Shadows Slumber: Finding the Time

 

Time for part three of my three-part miniseries! This week’s topic is Finding the Time – you can find part one on adversity here, and part two on motivation here.

One of the questions I get most often from developers starting their own projects is ‘where do you find the time?’ This is a very good question. Finding time to work on your game is very difficult – there are a lot of things in life that you can spend your time on, and you can only choose so many! No matter how important your game is to you, other things often take over, and you don’t work on it as much as you want (or need) to.

I think that I do a pretty good job with time management, and I hate wasted time so much, I want to make sure you never waste any time either! Below, in the style I have apparently developed, are some tips I have for making the most of your time, and finding the time to work on your game (or anything else you might need the time for).

 

Abandon All Of Your Responsibilities

running-away-from-home-laura-corebello

This kid knows how to make an indie video game.

We all have responsibilities – your game is important, but so is your job! However, if you want to make any progress on your game, you need to commit a certain amount of time to it. The best way to do that is to set aside time to work on your game.

In my last post, I mentioned that I spend an hour before work every morning working on Where Shadows Slumber. That’s the time I’ve set aside for my game – even if there’s a bunch of stuff going on in my life, I only ever use that time for my game. That way, there’s always a minimum of time I work every week.

Maybe your schedule doesn’t have a nice time slot like mine does, or maybe five hours a week is too much time to commit. Either way, you have to decide what time you can commit to your game, and then decide when that time will be. With a time block in place, you will find yourself consistently working on your game.

The most important part of this plan is to respect the time you set aside. Consider that time completely booked – if someone asks you to do something then, don’t do it. You already have plans! Setting aside time to work on your game is only useful if you consistently make use of that time.

 

Learn To Predict The Future

1487636747crystalball

I can see your future, and it is… Grongus.

It’s pretty obvious why this is helpful – you can already know the time you’re going to spend on your game! While that’s not exactly possible (yet), we have something close enough. If you can look into the future and know how long it will take you to do something, then you can know how much time you need to dedicate.

What I’m trying very poorly to describe is the concept of project management. If you’ve taken some computer science classes, then I’m sure you’ve heard of it. I’m sure you also scoffed at it and started coding anyways, which is exactly what I did. And then, four years later, I realized I had wasted six months working on a project, because I hadn’t planned it out correctly.

I don’t want to lecture you on the importance of project management (maybe in another blog post…), but I do want to mention how useful it is for time management. For Where Shadows Slumber, Frank and I sit down every week and discuss what we did, why it took so long, and what we’re going to do in the coming week. In this way, we keep ourselves accountable – it’s a lot harder to blow off your work when you’ve committed to doing it.

Another boon of project management is time-boxing, or estimating how long a task will take. If I know I have an hour to work on something, I don’t want to start working on a three-hour task. When I have to stop, I’ll lose my train of thought, which makes it that much harder to start again. That is an inefficiency that can be avoided through time-boxing. Whenever you go over your tasks, look at how long it took to complete each task, and then use that information to decide how long it will take to complete your upcoming tasks. In this way, you can always work on the task that makes the most sense, and you don’t lose any time to context-switching inefficiencies!

 

Feed on the Scraps

screen_2044x3636_2017-02-20_19-52-18

Delicious!

Scraps are the lifeblood of the rodent community. Despite how some people might view the indie gaming community, this is not the point I’m trying to make. Rather, I want you to feed on the scraps of your day.

Let’s go through my (theoretical) 24-hour workday. I sleep from 11PM – 8AM and work from 10AM – 6PM. Together, that’s 17 hours, during which I am fully occupied with something important. That leaves seven hours, during which I am free to do as I please.

That sounds pretty decent, but I’ll tell you that it certainly doesn’t feel like seven hours – it feels more like three. There are so many smaller tasks that we don’t even consider that take up our time. Even if I spend two hours on all the little things (grooming, eating, transit, etc.), the five remaining hours still feel like three. Where did the last two hours go?

Those last few hours just get lost in the shuffle. There’s seven minutes waiting for my roommate to get out of the shower, nine minutes waiting for the train, two minutes waiting for the elevator, on and on and on. These minutes really add up to a lot of wasted time. This time is the hardest to get back – if I decide to go to the train later, I might miss it!

Rather than trying to get all of these minutes back into a two-hour block, you have to appreciate them for what they are – tiny little pauses in your day. Once you’ve accepted that, you can figure out how to make use of them. Personally, I carry a notebook and pencil around, and write down things I think about. While I’m waiting for the train, I think about level design. On the elevator, I consider algorithm implementations. If I get home at 6:30, but I have to leave at 6:45, I jump on my computer and tackle the smallest task I can find.

By taking advantage of all of these ‘scraps’, I don’t get the full two hours back – it’s just hard to be that efficient. However, I do get a solid 30-45 minutes of drudge-work done, which means I don’t have to spend a block of time doing it later! If you develop little habits to try and use up these wasted minutes, you’ll find that you can knock off some of your tasks without even sitting down at your computer.

 

Become Conceited

148763957888023

Nobody loves a Grongus like another Grongus!

This is along the lines of ‘nice guys finish last’ – you have to be conceited in order to be successful!

I firmly believe that is not the case – however, this tip is still true, and applies to time management even outside of game development. The core tenant here is commonly phrased like ‘if you don’t value your time, no one will’. In this case, we don’t care about how others value our time, but we do care about how we value it.

Your time should be important to you! If you want to finish your game, you need to spend time on it. Wasting time that could be spent on your game just delays your release. I loathe every minute of wasted time – even if I wasn’t going to work on Where Shadows Slumber, I would be doing something better with my time than wasting it.

This can be hard to apply to everyday life – a lot of minutes slip through the cracks every day, and there’s no real way to get them back. But if you can prevent it, you should. If you’re waiting on work from someone, let them know! If you’re always waiting for someone who is consistently 30 minutes late, tell them the meeting was moved up by 30 minutes!

These are just examples, but the key is to keep in mind the fact that your time is valuable – you could be doing anything with it, so why are you waiting around for someone or something else?


 

These are my four tips for managing your time. I also want to mention that there’s really only one of these that I practice with regularity, and thus it is the one I consider the most important. It is, of course, the last one. This shift in mindset is so important, as it’s hard to really apply any time management strategy if you don’t value your own time.

 

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

As always, let us know if you have any questions, feedback, or topic requests! You can find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebook, itch.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.

Where Shadows Slumber: Staying Motivated

One of the most difficult parts of game development is staying motivated. I can’t tell you how many projects I’ve started, a great idea and achievable goal in mind, only to have those projects fall by the wayside, almost but not quite finished. Last time I talked about dealing with adversity; this week, I’m going to talk about how to stay motivated when working on a game development project.

As game developers, we love games, and we love developing games. When you first come up with a great concept for a game, you’re excited about it. You have so many great ideas, and you just can’t wait to implement them. You have an image of what your game will look like in 2 years, and with that pristine goal in mind, you simply feel driven to work on it.

As you work on your game, however, that drive begins to falter. Where you once looked forward to sitting down for an hour or two of coding, you find yourself shying away from your computer. You look at your game and all the effort you’ve put into it, and you realize how far away you are from the perfect game you had imagined. Rather than tackling cool, big-picture things like core mechanics, you find yourself slogging through your levels, double-checking initialization values.

Basically, there comes a time in the development of a game where the fun parts are over. Your motivation is at its lowest, the work is the least interesting it’s been so far, and your noticeable progress has slowed to a crawl. You find yourself with a solid, but definitely half-finished game, and it feels like it will never be any more than that.

Depressing, huh? Let’s find out how to avoid letting your game succumb to this fate!

 

webcamp-2016-pm-bpa-rd-17-638

“The first 90 percent of the code accounts for the first 90 percent of the development time. The remaining 10 percent of the code accounts for the other 90 percent of the development time.” – Tom Cargill, Bell Labs

The Ninety-Ninety Rule

 

The ninety-ninety rule is a saying that describes a lot of the difficulties associated with software development. It works on two levels, both of which are relevant here.

First, the shrewd reader will notice that the total development time in the quote adds up to 180%. This, of course, cannot be true in a literal sense; rather, this is a reference to the fact that estimates of development time for a project are almost always woefully low. If this is to be believed, then these projects take almost twice as long as estimated! In my experience, this is very accurate.

Secondly, we can look at the values used above. We see that the last ten percent of the code accounts for just as much time as the first ninety percent! While this seems nonsensical, it is perfectly true. Anyone who has made it 90% of the way through a software project can attest that the last 10% always drags on and on. When developing Where Shadows Slumber, for instance, I found myself with a game in which every core game mechanic was completely developed within 10 months of starting! And yet here we are, nearly two years into development, and the game is still not complete (and not just because I’ve been slacking off this whole time).

The ninety-ninety rules helps explain why we start to feel so depressed as we reach what appears to be the 90% mark of our game. We feel like our game is almost done, and it’s taken just as much time as expected – awesome, we should be done in a few more weeks! What we don’t realize is that we’re really only halfway done. Since we don’t realize that fact, we don’t understand why our expected release date has came and gone. We missed our deadline, our project is dragging on, we aren’t really enjoying the work anymore, and we still don’t understand why the last 10% of the work is taking forever. With all of these things weighing down on us, it’s understandable when we start to lose faith in our game.

So, now that we understand some of the reasons behind this phenomenon, lets look at some ways to deal with it.

 

climbing_2651239b

 

Set Realistic Expectations

A big part of the problem is feeling like you’re falling short of what you should be doing. The problem, however, isn’t with your work – it’s with your expectations. While you may be falling behind the schedule you set for yourself, you’re actually right on track – with the actual schedule for the game.

I’ve worked on a lot of software projects, and I would estimate that only around one in a hundred are actually completed by the original deadline. These types of projects are simply hard to estimate, and often take much longer than you would think. That’s why, whenever I have to estimate the time for a task, I always take my best, most realistic guess. And then I double it. Even after all this time, my best guess falls far short of reality, and the doubled timeline is far more accurate.

In addition to schedule expectations, this tip also applies to your game itself. If you start your one-man project, aiming to create the best MMORPG the world has ever seen, of course you’re going to fall short! You have to decide what you can reasonably accomplish, and at what level of quality, and then aim for that. If your game is starting to look like your goal, you’ll be much more motivated than if your goal is a perfect game that you’ll never be able to make.

 

Avoid Distractions

let_go

Credit: xkcd.com

I’ve spent a lot of time doing a lot of fun activities – game jams, NaNoWriMo, Ludum Dares, etc. But, since we started the development of Where Shadows Slumber, I have refrained from participating in any of them. It’s not that I no longer enjoy these things, it’s simply that I want to avoid distractions.

As you work on your game, you feel less and less excited about it – it’s only natural. This loss of excitement can be very dangerous to your game. Other projects are still out there, and they probably still seem very exciting to you. But it’s a slippery slope; it’s all too easy to take a few days off for a game jam, then you take a week off for something else, and before you know it, you’ve put your game on hold so that you can spend a few months working on a prototype for a new game. Betrayal!

I find the best way to avoid letting other things take over is to avoid those other things altogether. Perhaps some of you with stronger willpower or more time might be able to risk it a bit more, but be careful – it really is a slippery slope.

On the other hand, you don’t want to take this too far. Getting burnt out is very easy to do, especially when you’re spending a lot of time on a game. Sometimes I’ll sit down at my computer with the intention to work on Where Shadows Slumber, stare dejectedly at the screen for a few seconds, and then boot up StarCraft instead. If other game jams are your StarCraft, then go for it. As long as you’re continuing to work on your real game, and you don’t spend too much time on other things, it’s healthy to give yourself the night (or the weekend) off every once in a while.

 

Calendar with pushpins

 

Scheduling

This tip is something that I simply stumbled upon, but it has proven very helpful in forcing myself to work on Where Shadows Slumber. A year or so ago, I got a new job. My body still wakes me up by 8 am, but I don’t have to leave for work until 9:30 am! Woe is me!

This was actually an awesome development. Previously, I would work on my game whenever I could find the time – an hour here, twenty minutes there, etc. Now, I have an hour and a half every morning with nothing else to do. That time has become game-time; now I work on Where Shadows Slumber every morning for an hour or so.

One of the hardest parts of game development when you have a ‘day job’ is getting consistent time to work on it. I’m pretty fortunate in that the time I need was basically forced on me, but the principle holds. Find a schedule that works for you, and set that time aside as game-time. Don’t let anything else cut into that scheduled time – after all, it’s already booked! Whether it’s thirty minutes every Saturday morning, or two hours every night, blocking off a chunk of time for game development work will help you make consistent progress on your game.

 

Buckle Down

My last tip is less of an actionable item, and more of a mindset. There will be times when you sit down to work on your game, and you find that you simply do not want to. This happens, is perfectly normal, and is nothing to be worried about. As I mentioned earlier, when this happens to you, it’s absolutely fine for you to just take the night off and do something relaxing.

However… If you take a night off every once in a while, it’s fine. If you find yourself taking off multiple nights every week, you might be in a bit more trouble. Sometimes you don’t want to work on your game, but you have to anyways. You have to sit down, open up your game, and force yourself to work on it. If you never push your game forward, you’ll never get it into a spot where you want to work on it, and it will stagnate. This is an opportunity for your game to die, and you don’t want that to happen.

 


 

There you have it! These are my four biggest tips for staying motivated and continuing your game’s development. There’s obviously a lot more to keep in mind, and a lot of stuff I mentioned that’s hard to do, but I hope you’re able to put some of this to good use, and I wish you all successful, completed games!

 

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

As always, let us know if you have any questions or feedback! You can find out more about our game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebook, itch.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.

Where Shadows Slumber: Adversity

FRIEND. Hey Jack, what’s up? You’re usually up to something interesting – are you working on anything right now?

JACK. Hey man – yeah, we just started working on a mobile puzzle game based on shadows! Basically-

FRIEND. Mobile? People are still doing that? I thought that mobile gaming was over [and anyone who decides to make a mobile game is a complete idiot!]”

 


 

I don’t think I quoted the above conversation exactly right, but I will say that it is exactly what you do hear as a game developer when these types of conversations occur. Deciding to go into indie game development can be a big risk, and while these conversations are important, they really aren’t that much fun.

In this post I’m going to delve into the concept of adversity and how to deal with it. This will be the first in a three-part series of blogs, all about staying focused and productive.

 

Dealing With Criticism

Criticism is one of the most important aspects of game development, especially for indies. You need to know what people don’t like about your game, so that you can fix it. As such, people tend to be very forthcoming with their criticisms.

However, after endless hours of hard work, it’s easy for a developer to have trouble dealing with criticism. And it’s easy for a friend, intending to offer constructive criticism, to end up simply insulting or demotivating a developer.

Throughout the development of a game, us developers put a lot of thought and work into creating something we can be proud of. When someone else picks apart our creation, we often wonder – why does everyone make sure that us developers find out everything they dislike about our game?

Game development is a field that lives and dies by the opinions of players. The best way to find out what you need to change about your game is to ask your audience. And the best way for a gamer to ensure that a game ends up being good is to tell the developers what they don’t like. This relationship is a very good one, so don’t take it for granted.

 

Types of Adversity

How can game developers prepare to deal with adversity? By knowing what to expect.

Handling Detractors

 

grongus

This was an early review of the Where Shadows Slumber demo for Android.

This is the most obvious type of adversity, and the type we have come to expect. No matter how awesome your game is, there will always be people who simply do not like it, and you will always hear from them. Something about your game is not good enough for them, whether it’s too short, or the graphics aren’t good enough, or the gameplay is too simple.

“You game is a big ol’ stupid!”

– Some dude who hates your game

The best way to deal with this type of adversity is to learn what you can from it, and then to let it go. Unfortunately, it’s impossible to please everyone. You game may be made for many different people to enjoy, but you still have a target audience, and a lot of people will fall outside of that audience. If you focus too much on trying to please every person who says something bad about your game, you’ll just drive yourself crazy. Just accept that this person will probably never love your game, and continue trying to make it the best it can be for those people who will enjoy playing it.

 

Handling Constructive Criticism

img_2738

(Above) The  incorrect way to respond to constructive criticism.

Constructive criticism is the lifeblood of the indie gaming community, and any developer who really wants to do well is always on the lookout for it. Constructive criticism tells you what parts of your game need improvement, and it comes directly from the mouth of your target audience.

This is a very important point – I can’t tell you how many times we implemented a feature that we thought would be cool, only to find that our fans didn’t like it. Sometimes you make the wrong decision (especially when working in a small team), and constructive criticism helps you find out what things you need to change before it’s too late.

“Tell us what you hate about our game. We have thick skin, we can take it!”

– Frank, at every convention we go to

This is the easiest type of adversity to deal with, since we are constantly seeking it. This person likes your game, and they’re just trying to make it better, so they can enjoy it even more! The most important thing about constructive criticism is to always be ready for it, and to always listen to and learn from it. The player told you exactly what they want – try to give it to them!

 

Handling Friends Who Are Trying To Help

“You can do this, but to be more accurate, you probably can’t.”         – Barney Stinson

The third type of adversity I’ll talk about today is one that I wouldn’t really have expected, when I first went into game development, and is the main reason that I decided to write about this topic. That is the adversity that you receive from your friends.

“But wait, didn’t we just talk about that? Your friends are giving you constructive criticism, right?”

Yes, your friends are often a good source of constructive criticism. Maybe my friends are just the worst, but I’ve also noticed another, more sinister type of criticism.

“I’m only saying this because I care about you – you are literally the worst.”

– Your ‘friends’

Your friends love you, and having them in your life is awesome. However, they don’t always share your passions, specifically about game development. Many of them might think that you’re getting your hopes up and stressing yourself out for no reason. Maybe you don’t spend as much time with them as you used to. Maybe they’re just jealous of how awesome your game is. Whatever the reason, they’ll probably let you know.

I’ve heard a lot of different comments, but most of them begin with some form of “I’m saying this because I care about you…” This is the ultimate way a friend will disguise a negative comment. A lot of times you’ll hear something like “You know your game isn’t going to take off, right? I just don’t want you to get your hopes up,” or “Why are you wasting so much time on that – I mean, it’s just a hobby, right?”

Perhaps they are saying it because they care about you, and perhaps they mean well. Game development requires a lot of motivation and momentum, and hearing these things from the people who most care about you can be very disheartening. Sometimes you need to hear these things, but if you’re simply committed to creating something you can be proud of, you don’t need that kind of demotivation.

So how do we best deal with this type of adversity? To be honest, I wish I knew. The easier strategy is to simply nod along with them – “yeah, I know my game isn’t that great, but it’s a fun hobby.” This doesn’t seem fair to you, as you’ve put a lot of work into your game, but it’ll get them off your back. The other strategy is to explain to them that you’re doing everything you can to make this game a success. You’re putting a lot of work into it, and you would appreciate their support. If they have any constructive feedback, you would love to hear it.

Honestly, I think the second strategy is probably better, but as an introverted developer, I find myself utilizing the first more often. This is something I’m working on, but I think this is the type of adversity that is the most difficult to overcome. If you have any tips or thoughts about this one, we would love to hear from you!

 

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

Hopefully this post gives you a little bit of insight into some of the types of adversity you will most likely see as a game developer, and how to deal with them. Next time I’m going to discuss another topic that I find plagues me and many other game developers: staying motivated.

Until then, let us know if you have any questions or feedback! As always, you can find out more about the game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebook, itch.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.

Mechanic Spotlight: Shadows, Part 2

Where were we before we were so rudely interrupted by my extreme laziness? In my last post, we went over the basics of how shadows operate in Where Shadows Slumber. This week, we’ll pick up where we left off, and I’ll describe the way I actually implemented shadows, and the reasons for doing so.

Last time, I described two different ways to think about objects changing in shadow. Unfortunately, I did so in a sentence that, in retrospect, looks simply confusing:

[Things] can always change when put into shadow, or they can only change when you move around the object casting the shadow, so you’re on the other side of the casting object, relative to the changing object.

Yeah, that’s no good. So let’s figure out what this means, in a way that’s a little longer, but easier to grasp. We’ll use the classic pillar / bridge problem, where the pillar is casting shadow, and the bridge is changing with that shadow.

If I walk past the pillar, the shadow will overcome the bridge. If I continue walking, the shadow will move, the bridge will be revealed, and at this point, it should have changed. This is exactly what we want.

shadowtransition

Not only is the pillar / bridge problem less violent than the trolley problem, it’s more relevant!

Now consider the scenario where I start to walk past the pillar again. The shadow overcomes the bridge again, but this time, I stop walking, leaving the bridge in shadow. Instead of continuing forward, I turn around and go back. The shadow moves, so we can see the bridge again, but we’re on the same side of the pillar as we started. Now the question arises – should the bridge have changed?

This is a very important question when considering this mechanic. Thinking about it from a ‘pure’ standpoint, of course the bridge should have changed – it was in shadow. After all, that’s the rule, right?

This was exactly my thought process, and is why I implemented the mechanic in the way I shared in my last post. The early prototype we made behaves in exactly this way. However, as I got further into level design, I realized that this is not what we want. In order for many of our level designs to work, the above scenario would need to result in the bridge not changing.

When designing levels for a game like this, there are a number of considerations to make, but one of the most important is to remember that the player will not always do what you want. I may want the player to walk around the pillar, but the player may instead decide to walk behind the pillar, and then turn around. If I need the player to end up on the far side of the pillar (for a story event, part of the puzzle, etc.), that becomes hard to accomplish with the current version of the shadow mechanic.

So, it seems that we need to update the implementation of our mechanic. The way we want it to work has more to do with what side of a shadow-casting object we’re on – the bridge can only change when we move around the pillar.

Fortunately, this is actually an easier problem than the previous one. When we think about it this way, we don’t even need to use shadows – what we’re really checking is when we pass the object. When the light (player), the blocking object (pillar), and the shadow object (bridge) are all in a row (collinear), we can simply know that the object is in shadow rather than checking. This is true when we make a few assumptions:

  • Both the pillar and the bridge are about the same size. This means that we may have to break the bridge up into a number of 1×1 ‘shadow objects’.
  • Each light involved originates from a single point (so point/spot lights, not directional lights).
  • The bridge is further away from the player than the pillar.

When all of these conditions are met, we can ignore the shadow itself, and just change the bridge when the player passes the pillar. It’s a little hard to conceptualize, but a picture is worth a thousand words!

passingshadowobject

Alright, maybe like 500…

At the moment the player passes this ‘collinear point’, we trigger the shadow object to change (note that at that moment, the shadow object will be entirely in shadow). But the shadow is just there for cosmetic purposes, like a magician’s illusion – it’s so you don’t see the trick!

As I said before, this problem is much easier to solve – every frame, we simply compare the angle from the player to the blocking object with the angle from the player to the shadow object. When those angles switch, it means that the shadow object is in shadow and should change.

In this way, we can easily keep track of when a shadow object should change. There are a few ways in which this situation can become more complicated – if there are multiple lights or blockers that should affect a single shadow object, if there are multiple shadow objects that should use a different set of lights or blockers, etc. These are all very important things, but they’re all things that can be implemented by carefully extending the system we laid out above. As such, implementing them is left as an exercise to the reader : )

There are still ways we can use the previous implementation to help out with the shadow system. There are a few cases where we might need to actually know if an object is in shadow, rather than just making the assumption that it is. Thus, our shadow system includes a sort of ‘back-up’ shadow-detection – in certain cases, we fall back on the more accurate, more expensive shadow detection we worked on in my last post.

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

That finishes up our high-level overview of our implementation of the shadow mechanic – I hope you enjoyed it. Let us know if you have any questions or feedback! As always, you can find out more about the game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebook, itch.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.

Mechanic Spotlight: Shadows, Part 1

Throughout this blog, I’m planning on doing a number of posts which outline the mechanics of Where Shadows Slumber, and how they work. Now, there are plenty of very interesting mechanics that I can (and probably will) go over. However, there are probably a lot of blog posts and tutorials out there describing path finding, object pooling, shaders, and everything else. So, the mechanic I’m going to start with is the one that is the most unique to Where Shadows Slumber – the mechanic behind the shadows.

A quick disclaimer on the nature of this post – please note that this is not an in-depth description of the exact code we used for the shadows, nor is it an attempt to tell you the correct way to think about or implement such things. I’m sure a seasoned veteran of coding and game design will be able to point out a few inconsistencies or inefficiencies in our shadow system. Rather, this is meant to be a high-level overview of my thought process while I created this system, and how those thoughts changed throughout the process. Also, since we have been working in Unity for the production of this game, I will probably be mentioning how Unity does stuff pretty often.

When playing Where Shadows Slumber, you may have noticed that sometimes, things change when they’re in shadow. In fact, you shouldn’t have been able to beat the game without figuring that out.

shadowtransition

I think I’m just gonna use this GIF in every post…

Things change when they’re hidden by shadow and then revealed, but there are two (basic) ways to think about it – they can always change when put into shadow, or they can only change when you move around the object casting the shadow, so you’re on the other side of the casting object, relative to the changing object. One of these methods ended up making more sense to use in the game, but I implemented both of them on the way there, so I think it only makes sense to go over them both (even if it means stretching this post into two parts).

Now, these are both pretty simple problems at their cores, but there are a few interesting lessons. Let’s start with the first type of shadow, using the naive approach, which is exactly where I started a year or so ago.

So when an object is covered in shadow, the next time you see it, it should be different. The steps involved should look something like:

  • Detect if the object is in shadow now
  • Check if it was in shadow before (last frame)
  • If it wasn’t, change it!

Using these steps, the object will change every time it’s put into shadow and then revealed. So, clearly, the most important thing to be able to do is detect when an object is in shadow.

Since the light in the game comes from the player’s lantern, everything that’s in shadow is essentially ‘blocked’ from the player’s view by some obstacle. Thinking about shadows in this way leads to the first pass at detecting when an object is in shadow – basically, just draw a line from the player (or the lantern) to the object. If it hits anything along the way, that means that the light isn’t going to reach the object, which means it’s in shadow.

Image result for unity raycasting

Looks like Unity’s ray casting…

 

This process is pretty much the description of Unity’s ray casting: draw a ray from a point until it hits a Collider. So we just add a Collider to any object that might get in the way, and we have a simple ‘IsObjectInShadow’ function!

However, you may have noticed that there are a couple of reasons this won’t work, the most important being that it doesn’t behave correctly. Since casting a ray will only target one point, the shadow detection will only work for the exact position of the object. Anything with any amount of width or depth (so, anything) will say it’s in shadow when the center is in shadow, but the edges are not. This happens when the object is at the edge of the shadow, when it’s only partially shadowed. This is a pretty big problem if we’re going to be changing the object at that time, since the whole point is that the player won’t see the object when the change happens.

So we can detect when a point is in shadow, but just checking the exact position of an object isn’t enough. The easy solution is to simply check more points! By casting two rays, one toward the leftmost side of the object, one toward the rightmost, we can check if both of them are in shadow. If they are, then the whole object is in shadow. This version of our theoretical ‘IsObjectInShadow’ function works much better – as we move a character around a pillar, the object will more accurately determine whether or not it’s in shadow.

We can get the object’s leftmost/rightmost positions (relative to the player/light) by getting the objects dimensions, which we can either get from the Renderer component on the object (Unity will measure the visible object), or simply by placing some restriction on the size of the objects. Since Where Shadows Slumber uses a grid system, everything that changes with shadows is restricted to a 1 x 1 x 1 unit cube, in order to make shadow calculations easier.

Now comes the question – why is this version not good enough? We have to do a little math up front to get the left/right bounds, but after that, we simply have to cast a few rays, and we know whether or not our object is in shadow. Seems pretty good! And it is pretty good. It only works in two dimensions – if you move upward, above the object, the object will still think it’s in shadow – but that’s not too bad, and most level designs don’t involve a lot of vertical movement, so we can ignore it for now. The biggest problem with this version is that we have to add a Unity Collider component to every object that might cast a shadow. Then, every ray cast will test collision against every collider every frame (the reality is not quite this bad, but that’s the idea). This can become a problem in a scene with a lot of shadow objects and a lot of shadow casters, especially if you want different casters to affect different objects. We can improve upon this version with a little math and some clever thinking.

If we think about the way that shadows are cast, we can come up with a better way of determining if something is in shadow:

shadow-radii

(There’s a reason Frank’s the artist, and I’m not.)

 

If we specify that every object is restricted to a 1 x 1 box (in the two non-height dimensions), then we can use some trigonometry to determine whether something is in shadow. I won’t get into the details of the actual math, just the overall conceptual parts. No matter the angle, the radius of the blocker will always be at least r (0.5). In the same way, no matter the angle, the radius of the shadow object will always be at most R (√2). Thus, by taking distance into account, we can always tell if the entirety of the shadow object (everything within the bigger circle) is put into shadow by the blocker (everything in the smaller circle).

By using this method, we can tell if a shadow object is in shadow without ray casts or Colliders, and we can do it for a specific object. In this way, we can specify which blockers affect which shadow objects, which gives us a lot more control over level design.

Now that we’re able to tell if an object is in shadow, the hard part is over. Every frame, we just follow the steps outlined above, for any shadow object. We check if it’s in shadow, then check if it was in shadow (meaning we have to keep track of whether or not it was in the previous frame). We change the object to the next state. The object will only change once, until the user sees it, when it’ll appear differently. Then, if it’s put in shadow again, it’ll change again. This allows us the flexibility and consistency of shadow objects.

As it turns out, this version of the shadow mechanic didn’t end up being the one that we needed for Where Shadows Slumber. The shadow mechanic that we actually did use will have to wait for Part 2. We already did a lot of the heavy lifting this time, so it shouldn’t be too hard to make some small adjustments to the work we did here.

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

I hope you enjoyed this first highlight of the shadow mechanic in Where Shadows Slumber. Hopefully it wasn’t too complex, and I was able to explain it well. Let us know if you have any feedback! As always, you can find out more about the game at WhereShadowsSlumber.com, find us on Twitter (@GameRevenant), Facebook, itch.io, or Twitch, and feel free to email us directly with any questions or feedback using contact@GameRevenant.com.

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