Shadowcasting Field of View on Canvas with Javascript

A little while back, somebody asked me if I could turn the shadowcasting algorithm I posted here into a working demo. After a bit of fiddling around I set up a demo using the tag for display (and in the process made a little shadowcasting library-ling [what do you call a miniature library, exactly?] called LightSource). There are two versions, a fullscreen demo and the little one you see embedded below. The fullscreen demo has a bunch of controls that let you control the light output in various ways, and you can click+drag to create walls (click them again to remove them). It’s really a lot of fun to fiddle around with–although it does get a bit slow when you have lights with a radius of over 90 tiles–and you can reach it by clicking here. Happy shadowcasting!

But how do pretty light?

“That’s all very nice,” you say, “but how can I make this happen?” Well, the basic code behind the demo is simple. First, you need create an instance of the LightSource object with a few parameters. There are three parameters that are required initially–the radius of the light source (can be changed later), the size of the map you want to light and a function that will determine whether a particular tile blocks light. Altogether, your initialization script should look like this:

var light = new LightSource({
radius: 6,
mapSize: this.mapSize,
getLightLevel: function(x, y) {
return map[x][y].blocksLight; // whether or not the tile at x, y in your map blocks light

Once you’ve successfully initialized your light source you’ll then need to call light.update(x, y) with the position of your light source. This function will return an array of objects representing all tiles that are affected by the light source as well as their respective light levels in this format:

tile {
x: // x coordinate
y: // y coordinate lightLevel: // the level of light on this tile

The lightLevel of each tile is a value between 0 and 1 and is determined by its distance from the light source (unless specified otherwise by including gradient: false in the initialization parameters). This means that the light fades away nicely from full strength at the center of the light to almost nothing at the borders of the light, until finally we reach 0.

But anyways, I digress. Once you’ve got this list, you can then iterate through it and apply the changes to your actual map data. After that’s done, you’ll want to render your changes. I used to do this, but you’re not limited to that. In fact, the LightSource library is untethered to display as it only handles behind-the-scenes data, thanks to the callback method I implemented. So go ahead and feel free to use whatever display method you want.

Download LightSource

Before you leave, here’s a link to download LightSource.js–hopefully you find it useful. If you do make anything cool with it, please don’t forget to comment and show me what you’ve come up with!

I hope you find LightSource useful, and as always, feel free to comment and tell me if I’ve missed anything or made any mistakes in this post or in the LightSource algorithm.