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:
- The player sprite is a complex shape and that shape changes with each step taken (shoulder movement, etc).
- 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.
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: