GAME DEVELOPER / MOVEMENT COACH

Blog

Lighting/Vision Algorithm

Lighting a key part of atmosphere in games, especially when you consider the horror genre. In 3D games, lighting is a logical extension of the real world. Light behaves as you would expect and, for the most part, that just works. In 2D, however, the player has a unique perspective that allows them to cheat by seeing beyond the character's view frustum. Lighting is no longer just an aesthetic detail, but an informative one. How do we give the player the same information that the character has? The solution comes, unsurprisingly, in the form of a lighting algorithm.

Darkwood_06.jpg

This effect was popularized by games such as GishMonaco : What's Yours Is Mine and more recently, Darkwood. As you can see, the effect can be used aesthetically, mechanically, and atmospherically. Its versatility makes it a very powerful tool in top down horror.

So how do you accomplish it? I started by defining what I wanted my own lighting algorithm to accomplish.

  • Atmosphere - Create a daunting, claustrophobic feeling for the player.
  • Environment Visibility - Give the player visual environment information only if it is lit by a source of light.
  • NPC Visibility - Give the player knowledge of NPC's only in their personal view frustum.
  • Enemy Behavior - Alter enemy behavior based on light.

In order to accomplish these things, the algorithm needs to be able to do a couple things. Firstly, it needs to define a shape that will be used to determine which parts of the screen are lit and which aren't. Second, that shape needs to be transferred to actual light. Third, that shape needs to be able to collide with game objects in a way that it can communicate to them whether or not they are in the light.

The Shape:

In order to define the shape, we need to know which objects we are looking at. These objects can be placed on a Layer Mask in Unity to separate them from the rest of the world. This will speed up the process as we're not looking at the whole world. More to that, let's only look at objects on that layer that are within the light radius.

Now we know which objects we want to test against, so we need to figure out how the light wraps around them. To do this, we need to define the actual shape of an object apart from it's visual representation. For example, a player's hit box will not likely trace the exact shape (nor do we want it to because that's too complex). Let's use 2D Polygon Colliders for this. These are nice because we can define exactly which vertices we want to represent the hit box.

Now that we have the objects and their shape, we need to test the light against it. In order to ensure the light wraps nicely around an object we'll fire a ray at each vertex of its collider. Wherever the ray hits will determine a vertex on the finished light shape.  That sounds too simple. Unfortunately it is. A couple problems come along with that.

  1. The ray will stop on the edge of a shape even if it's shorter than the light radius.
  2. Unity has a pesky rounding error that causes ray casts to sometimes miss edge points causing the shape to jitter.

In order to solve 1, we're going to identify edge vertices before testing. By doing this we can have a special case for these points. To figure that out, we'll sort the vertices by increasing angle with the light. The highest angle will be our left most point and the lowest, our right. (TODO: explain quadrant issue)  Now, when we test these points, instead we'll add them to the shape by default and then we'll cast a ray PAST that point to see if it collides with anything beyond the shape. If not, then add a point at the light radius. Conveniently, by doing this we also avoid casting directly at the edge of the shape which solves our rounding error too! Huzzah!

Okay, the last step of the shape, we simply have to sort the vertices by angle an then draw triangles to build a mesh. Now we get to look at it and feel good about ourselves...

(TODO: explain radius out of range issue)

lighting.gif

 

To be continued...

Masking, Shaders, Collision

Resources:

https://www.redblobgames.com/articles/visibility/

http://ncase.me/sight-and-light/