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.
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!
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.