June 2012, updated Mar 2018, Apr 2020

This page includes interactive diagrams that require your browser to have Canvas and Javascript enabled. In a 2D top-down map it is sometimes useful to calculate which areas are visible from a given point. For example you might want to hide what’s not visible from the player’s location, or you might want to know what areas would be lit by a torch. Drag the circle around to see what’s visible from the player’s location: This algorithm can also calculate what areas are lit given a light source. Run once per light, we can build a light map showing which areas are lit up. Show 24 lights added to the map. The roguelike community has collected several algorithms[1], especially for grids. See this overview[2] for how grid algorithms handle situations differently. Also see Albert Ford’s interactive tutorial about the recursive shadowcasting algorithm[3]. Subtractive algorithms start with everything visible then subtract the hidden areas; additive algorithms start with nothing visible then add the visible areas. I’ll describe an additive algorithm that works with line segments, not only solid blocks or grids.

Ray casting # A simple approach is to cast rays from the center. It’s a reasonable first step to get an approximate answer: To be smarter about it, let’s cast the rays only at angles where the walls begin or end. The triangles produced by these rays are the visible areas: That’s it! The algorithm is: Calculate the angles where walls begin or end. Cast a ray from the center along each angle. Fill in the triangles generated by those rays.

Wall tracking # We could stop there, especially if we have a fast ray-casting algorithm that uses a spatial hash to avoid intersecting with every wall. However, a more efficient approach is to combine the ray casting and wall intersection into a single algorithm. I’ll describe here an algorithm that sweeps a line around a circle, hitting all the points sorted by angle; it’s also possible to expand circles outwards, hitting all the points sorted by radius, but I haven’t tried that approach. For the area between consecutive rays, we want to find the nearest wall. This wall is lit up; all others are hidden. Our strategy will be to sweep around 360° and process all of the wall endpoints. As we go, we’ll keep track of the walls that intersect the sweep line. Move the slider to make the sweep line pass the endpoints: The next step is to keep track of which walls the sweep ray passes through. Only the nearest wall is visible. How do you figure out which wall is nearest? The simplest thing is to calculate the distance from the center to the wall. However, this approach doesn’t work well if the walls are of different sizes, so the demo uses a slightly more complicated approach, which I won’t explain here. Move the slider to sweep the angles with the nearest wall drawn in white and the other walls drawn in black. Whenever the nearest wall ends, or if a new wall is nearer than the others, we create a triangle showing a visible region. The union of these triangles is the area that is visible from the central point. Note that creating a triangle involves intersecting the previously active wall with the sweep ray. As a result, the new edge of the triangle may be longer or shorter than the sweep ray, and the far edge of the triangle may be shorter than the previously active wall. var endpoints; # list of endpoints, sorted by angle var open = []; # list of walls the sweep line intersects loop over endpoints: remember which wall is nearest add any walls that BEGIN at this endpoint to 'walls' remove any walls that END at this endpoint from 'walls' figure out which wall is now nearest if the nearest wall changed: fill the current triangle and begin a new one

Playground # Here’s a playground with more blocks. Drag blocks into the grid area. Move the slider to see the sweep line in action, or drag the center point around to see what would be visible as the player walks around.