2
\$\begingroup\$

I was wondering if there was a way to make a 2D shader (or use any other method) to selectively black out areas of the screen that are not in a specific region.

I need this shader because in the game I am making, I would like the area outside of the player's current room to be obscured, except when the player is transitioning between rooms, at which time both will be visible for a while, after which the old room fades to black. You can seem a diagram of this below. Mock Up of Room Obscuring

I have tried accomplishing this by simply fading in and out textures depending on which room the player is in, but the problem with this method is that if these textures overlap, while the rooms are transitioning, the areas where they do overlap will be darker than the others. Likewise, attempting to set up these textures to account for all possible room entry/exit scenarios without overlap is complicated, error prone, and time consuming. This is compounded by the fact that certain parts of the map should be visible from multiple rooms. I have also tried using a simple shader that darkens all pixels in the old room, but that doesn't work because, as mentioned before, some areas are visible in multiple rooms.

Thank you for any help you can give! I understand that this might not be a simple thing to make, and I've had a lot of trouble describing what I'm looking for, so I'm totally happy to clarify further if need be.

\$\endgroup\$
4
  • 2
    \$\begingroup\$ This sounds similar to a "fog of war" or "visibility polygon" effect. Have you reviewed existing tutorials or Q&A that turn up with those search terms? \$\endgroup\$
    – DMGregory
    Jul 12 at 2:50
  • 1
    \$\begingroup\$ How are rooms created? Is level space handcrafted, or procedurally generated? Different solutions (or rather "hacks") to the problem may be possible depending on your existing implementation. \$\endgroup\$
    – liggiorgio
    Jul 12 at 8:16
  • \$\begingroup\$ The rooms are created by hand! I'm working on the project with some more art-oriented people so I'd like a solution that doesn't ask too much of them. \$\endgroup\$
    – dahrasz
    Jul 12 at 15:10
  • \$\begingroup\$ In terms of Fog of War, I just looked up some tutorials on the topic and it seems related to what I'm doing. It would have to be heavily modified though, as I am basing what is shown/hidden on the room, not on a single light source around the player, and because I need to account for these regions fading in/out with overlapping sections. I'm not exactly sure how to make those modifications, but I am open to using that method. \$\endgroup\$
    – dahrasz
    Jul 12 at 15:13

1 Answer 1

3
\$\begingroup\$

I have tried accomplishing this by simply fading in and out textures depending on which room the player is in, but the problem with this method is that if these textures overlap, while the rooms are transitioning, the areas where they do overlap will be darker than the others.

Solving this issue should solve your problem. Without seeing your code, it's difficult to give you a perfect solution, but here's a possible solution that uses blend_disabled, a SubViewportContainer (Godot 4), and z-indexing.

Create a shader whose sole job is to disable blending:

shader_type canvas_item;
render_mode blend_disabled;

Attach that shader to your shadow textures (for this example, I'm using ColorRects). This will prevent overlapping textures from having a "darker" color.

Make your shadow textures children of a SubViewport (which in turn will be a child of a SubViewportContainer). Set the size of the viewport to be the same as the size of your game.

example scene tree

This will "enable" blending again, so that the shadow texture can blend with your room textures.

Update your game logic to set the z-index of each shadow texture whenever the player changes rooms, with a high value if the player is in the room and a low value if the player is not. This example is inefficient but conveys the meaning:

for shadow_texture in shadow_textures:
    if contains_player(shadow_texture):
        shadow_texture.z_index = 1
    else:
        shadow_texture.z_index = 0

This will ensure that the room(s) the player is currently in is not darkened by any overlapping textures that belong to another overlapping room.

Here is a clip of this example with ColorRects, treating the mouse as the player and controlling the "thickness" of that shadow with the ColorRect's alpha channel:

video of the solution in action

\$\endgroup\$
1
  • \$\begingroup\$ This is perfect, thank you so much! I was wracking my brain for so long, but this is exactly what I need! \$\endgroup\$
    – dahrasz
    Jul 20 at 22:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .