There are lots of FoV algorithms out there for roguelikes. Here's a non-exhaustive listing, with several dead links and incomplete descriptions, and also here and here. So, why carefully search through everything and pick one, when you can make your own? I had an idea several years ago, that I finally managed to implement in C#, as that's what I'm using now for the game.
The idea is very simple (and certainly not novel, as I've seen a few other similar examples around), and it's based on:
- Processing an ordered list of cells, sorted by distance to the viewer. This list, if represented relative to origin (0,0), it can be calculated once in the game
- At every cell, we sample up to 2 previous cells towards the direction of the viewer, and based on relative angles (demonstrated below), we add their contributions together. Diagonals and straight lines sample just a single cell: the one before.
- Visibility can decay with distance, for lighting as well as other purposes (e.g a creature at a low visibility area can appear as a question mark)
- Grid cell visibility can be any value in [0,1], so partial blockers are possible
The percentage contributions from the previous cells are calculated based on the projection of the normalized vector to the longest axis:
That's it really. The visibility function is used up to twice per cell, so we can cache it as we go at some temporary storage. I'd be happy to put it in an existing testbed, but I haven't found a nice, easy-to-run one in a language that I'm quite comfortable with (C++, Python, C#). I'm pretty happy with the results as it looks reasonable and should perform well.
Here's a video of walking around the overworld where visibility is affected by elevation difference (we can see higher from a mountain, but we can see little past a mountain when we're in the valley), humidity and vegetation density. Unfortunately, humidity and vegetation density are not very clearly represented with the current tiles, so the result might look slightly arbitrary:
Here are some test images with various test cases for the FoV algorithm, showing continuous visibility (for lighting) and binary (for fov tests). The green gradient is the visibility. Red is the viewer. Dark areas are walls.
And here are the same examples, but the walls obscure visibility by 50% only