I want to implement fog of war. I sort of need to implement fog of war. The player can currently see too far:
The player could be standing miles away in terms of actual walkable distance, but somehow see everything through the walls. I think that’s fine if they have visited the place before. But it removes some of that blackness mystery exploration factor (and makes secrets un-implementable). The old school “is there anything in this black void?”
I am not 100% sure yet how I will actually do the “fog” — just hide the tiles and entities or have a gradual fog overlay or some fancy shader layer or something else. But I know there are a couple things I need to do before this.
For one, my walls are eventually going to be destructible. It’s not too hard to implement, but it adds that feeling of “this world is up to the player” and they can “break rules” if they want. (Of course, they would need rare limited explosives that are likely best spent elsewhere.) The problem is, of course, that there is nothing beyond the walls and there are occasional gaps (even with my temporary room layouts):
So what I am going to do is add an additional tile types to form a filled border area around the map:
And use it to fill everything around the world (and make my Unity scene very slow) including an impenetrable border:
Since I will be needing a way to test my fog of war consistently, let’s just make the walls destructible now. Firstly, I cannot have a binary selection for this, since bedrock and floors are indestructible but only one of them collides (technically, floors could be destroyed, but they would get replaced by a different “destroyed” floor):
Then I need to specify what actual tile replaces the destroyed tile (that won’t be destroyed further):
And for testing purposes, I’ll just destroy my walls with projectiles:
Up to bedrock, that is:
Now I have to make the destroyed walls drop ores that I can smelt into ingots used for crafting armor.
Another thing I need is actual doors. What I have are just differently-sprited tiles that act like floors. What I need is a non-walkable, collideable door tile that gets replaced with an open door floor-like tile once the player is near (or opens it somehow):
For now, I will just do it when the player is in proximity:
The tricky bit is here is just detecting and gathering the right tiles.
So this gives me the design needs (sort of in terms of corner-cases) for my fog of war. It has to be able to (1) hide unexplored areas, (2) reveal rooms, and (3) reveal around removed tiles. I am going to be very generous with tile reveal, showing pretty much everything on-screen as long as the player is in the relevant walking area — no realistic line of sight algorithms or anything. If there’s a tunnel corner or something, it’s fine that the player sees it all.
So, first of all, let’s fog-of-war everything (well, tiles anyway):
Now I need to reveal rooms, starting with the spawn room.
My first attempt was a naive room reveal logic, where I stored the room index in each of my tiles when generating them. Then grabbed all the room’s tiles upon request and told them that they have been seen:
Spawn room worked really well, so I thought I was onto something. So now when a door was opened, I could just reveal all the connected tiles (rooms on all sides of the door) immediately:
However, the “room index” was a naive method that only quickly gave me the immediate node/room and not any of the connected ones. So tunnels and arenas didn’t get fully revealed:
So I looked at the tiles bordering the immediate rooms to check if there was any “vision” between them. If so, I just ran the room reveal on the neighbouring tile. And this looked like it worked:
Except, my rooms overlap by 1 row/column, which means rooms have “parts” that are not part of the room:
And to solve this I need to go through every tile anyway. Which means, there is no actual benefit in trying to go room-by-room as I might as well just gather all visibly-connected tiles to begin with. This is slower and trickier too. I need to (non-stack-overflowing) flood-fill search all the connected tiles. First, I can find all adjacent tiles that can propagate vision. But that just gives me the tiles I can “light”:
I also need to have the search include the tiles that are “lightable” but not necessarily can “light through” (and I need to check all 8 neighbours, because diagonal neighbours should also be visible):
And this finally works (after lots of finicking and debugging and a couple dumb bugs):
Here, the spawn room is lit properly. Once the door opens, any connecting nodes are lit, including down the connected door-less tunnels. Note also the “dark room” in top-left that stay dark, because it’s not connected and the player has no idea it’s there. Of course, no tiles outside the walls (fillers) are revealed.
Now, for destroyed tiles, I can immediately mark any destroyed tile as visible. This implies the player could see the tile, but that should always be the case. I don’t really expect things blowing up by themselves somewhere in the dungeon. (And, if they do, I can just mark them as being part of the adjacent room and reveal them later.) If I just reveal the immediate tile, this happens:
So I need to apply the same logic as for the room check and reveal — to reveal neighbouring tiles as well (and anything they may connect to):
And this works great. I’ve pretty much covered all the immediate cases.
Now the question is how to do the actual fog. I am just fading out the tile sprites for debugging purpose, but I cannot do that in-game. For one, this doesn’t affect other entities:
At this point, I have to rethink my sprite shader. It can tint things and it can fade things, but it can only do one or the other. I don’t have enough channels I can use for the shader to control all the variations. And Unity sprite renderer can only directly set the color. I really don’t want to do reflection or have unbatchable shader instances, so I will have to do with the color channel. I think I will forego tinting to every shade imaginable and just have the white tint/overlay amount as the red channel. Then the alpha channel can fade the sprite properly, instead of controlling the tint level. And green and blue are unused for now. This means I can make any of the white-flashed and faded combinations:
So I can fade out the entity sprite renderers when they are not in range:
I need a controller for each entity world object and wire it with the main pipeline, then reference all the sprite renderers to fade, and have all entities provide whether they are “visible” or not. I can also provide a fade speed for my visibility controllers, so the transition isn’t abrupt:
I will have it faster in-game, mainly just to avoid the jarring toggle rather than any especial prettiness. I also made the entities closer to the player fade in slightly quicker, making a nice transition:
It’s mere milliseconds and a few percent difference, but the eye notices it and I think it feels much better, especially since it doesn’t take a whole lot of time to do.
And that about does it. I obviously don’t have art yet. So there are some decisions I cannot make yet in terms of fog-of-war presentation. The worst case scenario is fading in every entity and that already works decently. So I won’t do any more fanciness for this until I have some art direction.