Asylum Dev Diary 91 – Light Casting

This week saw a 5 day development cycle that allowed me to concentrate on more tweaks to the lighting system in Asylum.

The first thing I wanted to do was to see if switching out the surface based lighting engine (Aura2) with a shader based engine would yield any performance improvements. After taking a day to try out the code and apply alternative lights I discovered that there was no real difference between the two and so I returned to the surface based lights instead, and over the coming weeks I will run the debug profiler to see if I can identify any areas that can be improved.

One of the aspects of the lighting that has bugged me a little from time to time is the inability for the player sprite to be affected by the lights. This was because of 2 big factors:

  1. The player sprite is a complex shape and that shape changes with each step taken (shoulder movement, etc).
  2. Because the player has a light aura around him at all times (very dim but used to ensure the player is always at least slightly visible) and can also have a torch a light engine based shadow would experience rendering issues with the shadow origin being at exactly the same spot as the light.

So, I decided to use a trick for the players shadow. I would draw transparent versions (0.1% strength) from the players position at a certain distance and angle.

For this I would need a few things. Firstly, I would have to add a light hint – an invisible sprite that indicates where a main light source is (this is because the actual lights change object and sprite index and that would mean checking multiple instances instead of one). I would then need to check which lights were in range of the player using a reasonable distance of 600 pixels. This would give me a list of the light hints close to the player. Using collision_line() I would work out if the line of site to the light from the player was obscured by a wall and hence not shining on the player. Finally I would get the angle from the light to the player and the distance. This could then be used to draw the shadow using 8 passes of the shadow image from the player along the angle line from the light.

Initial shadow casting with debug lines drawn

This worked really nicely, but there was one problem. As I was only dealing with the closest light as soon as a different light was closer the shadow would snap to a different length and angle.

In order to get around this I set an object variable for the shadowAngle and shadowLength. With these values I could lerp() between the current shadow settings and the ones from the closest light. Visually this would allow the shadow to sweep into a new position.

The final effect was much better and I’m very pleased with the outcome. It may need adjusting as I continue development of other areas but so far so good.

Here’s some more screen grabs of the final shadow cast: