-
Notifications
You must be signed in to change notification settings - Fork 0
Algorithm Overview
This is an algorithm for computing which tiles can be seen by a player in a 2D grid, where some of the tiles contain a body (an object that obstructs vision and nearly fills the tile), and where there are some walls occupying the edges between tiles.
A naive way to determine any field of view would be to check each tile one by one, casting a ray from the player to the tile. Shadow-casting is a more efficient method. It works by processing the map outwards from the player, keeping track of the angles which are in shadow: those that been occluded by bodies or walls seen earlier.
The smirking yellow guy is the player. The red and orange boxes are the bodies. Blue lines represent the angles that bound the shadows. Blue shaded regions represent the shadows themselves. Dark shaded tiles are not in the field of view (i.e. not seen by the player). The dashed blue lines will take some explaining.
Tiles that are only partially in shadow are considered visible. WallyFOV considers a tile to be visible if there exists a line from the center of the player's tile to any point in the target tile. Even if the player can only see the slightest sliver of the tile, it can be seen. This is most notable near the edges of the shadow created by the orange box.
Bodies in WallyFOV do not completely fill their tile but are just slightly smaller, so the orange box does not occlude the tile just north-west of it. This is important for a corner case which we'll discuss in the next section. The dashed lines indicate angles which have been shifted by a tiny amount in one direction, because they were generated by a body.
The 2D grid can occasionally create some unexpected artifacts. Look at the two boxes in the lower-left quadrant; the player can see the tiles just on the other side of them, but some tiles farther away are occluded.
Here we see what happens when bodies are adjacent to one another. The three red blocks in a row on the south-west side form a kind of wall because their occlusion angles overlap. This is a normal way to make walls in a field-of-view algorithm without explicit wall support.
There's an important corner case when using bodies to form walls. In the corner of the room it's important that the bodies on either side of the corner not occlude the corner body. This is demonstrated in the example image by the orange block. If the red blocks in front fully occluded the orange block, then the player wouldn't be able to see it, which spoils the shape of the room. Because WallyFOV considers bodies just a little smaller than the tile, the player can see through a very small crack between those blocks.
In the top-right, this means the player can see beyond the diagonally-adjacent blocks. Since a tile is considered visible if any ray reaches any point inside it, the player can actually see quite a few tiles behind those blocks.
When you add a wall to a map in WallyFOV, you specify a tile and a compass direction. It will automatically add the corresponding wall on the other side.
While bodies do not fill the entire tile, walls do fill the entire edge. This is represented in the above diagram by the blue lines without the dashed lines beside them. The wall just to the east of the player in this diagram covers a slightly wider angle than the body just to the easy of the player in the first diagram. That small extra width is enough to put more tiles into shadow.
Unlike the case of diagonally-adjacent bodies, there will never be a small crack between two wall which touch.
This final example shows some cases where walls and bodies interact. A wall diagonally-adjacent to a body (such as the orange block here) will leave a narrow crack, just as in the body-body case. But here, note that only one side of that crack (the one on the body side) has the dashed line, which changes which tiles on the other side are visible.
For more field-of-view goodness, check out the successor to this algorithm, WarpField, which supports portals.