Necroing post in case it saves someone a few hours in the future.
After trying to figure out this, came across another solution using shadow_item_cull_mask layers and shadow_item_cull_mask for the player's light. It works with 1 Tilemap along with an Area2D for detecting if the player is behind the wall or not. The process takes 3 steps.
Step 1: Setting up tilemap.
When setting up your tilemap, include the following layers.
1) An occlusion layer with a light_mask set to layer 1 (adjust as needed).
2) 3 tile layers:
- Ground layer (z_index = 0)
- Object layer (z_index = 2)
- Ceiling layer (z_index = 3)
After setting up your layer, Create a tileset and assign the occlusion mask to the TOP of the wall.
It should look something like this:
2) Setup collision and collision for tiles.
Note: Adjust as needed. Rough example.
Step 2: Setup PointLight2D for the player.
1) Next step is to create a PointLight2D for the player.
2) Create a texture of gradient. I chose a radial gradient.
3) Important. Set shadow_item_cull_mask to layers 1 AND 2. Layer 1 will be for environment and 2 for player specific occlusion.3
4) Important. Set the range_z_max to 3. This is the current layer of the ceiling. (i.e., the light shines on the wall from the front)
End Result:
You will notice the lamp from the player is cut off from the edges of the wall and shines against the ceiling portion of the wall. This is due to Item Cull Mask Layer 1 matching the occlusion layer from the TileMap as well as the range being the same layer as the ceiling layer.
Step 3: Create LightOccluder2D node for when player is behind the wall.
1) Create a LightOccluder2D around the bottom of the wall.
2) Set the polygon around the base of the wall.
3) Important. Set the occluder_light_mask to layer 2. This causes it to occlude light from the player's light but not environment lights.
End Result:
Note: I angled the occluder to make it more of a gradual change. Play with whatever shape works best.
Finally for step 3, set the visibility to false. You'll use the Area2D to toggle the occluder on and off.
Step 4: Area2D for detecting behind the wall and code stuffs.
1) Create an Area2D to detect if the player is behind the wall.
2) Set the area above the collision area for the wall using a CollisionPolygon2D (shapes work too).
Result:
3) Attach the body_entered and body_exited signals to a scene script.
4) Setup the script so that:
a) On entering the area behind the wall:
- Set TileMap z_index to 1 (this prevents the light shining on the wall from behind due to the range of 3 we set).
- PointLight2D from step 2, removes the shadow_item_cull_mask for layer 1 (the environment light occluders).
- Sets the LightOccluder2D from step 4 to visible to restrict the player's light bleeding through the wall.
b) On existing the area behind the wall: - Set TileMap z_index back to 0.
- PointLight2D from step 2, adds back shadow_item_cull_mask for layer 1 (the environment light occluders).
- Sets the LightOccluder2D from step 4 visible to false to allow the player's light to shine against the wall when in front.
Example Script:
func _on_area_2d_body_entered(_body):
%TileMap.z_index = 1
%WallLightOccluder2D.visible = true
var lamp_light:PointLight2D = %LampLight
var cull_mask = lamp_light.shadow_item_cull_mask
if cull_mask & (cull_mask << 1):
lamp_light.shadow_item_cull_mask = cull_mask - 1
print("cull mask ",cull_mask," changed to:",lamp_light.shadow_item_cull_mask)
func _on_area_2d_body_exited(_body):
%TileMap.z_index = 0
%WallLightOccluder2D.visible = false
var lamp_light:PointLight2D = %LampLight
var cull_mask = lamp_light.shadow_item_cull_mask
if not (cull_mask & (cull_mask << 1)):
lamp_light.shadow_item_cull_mask = cull_mask + 1
print("cull mask ",cull_mask," changed to:",lamp_light.shadow_item_cull_mask)
Note: LampLight is the player's light. Also, the cull_mask logic uses bitwise operators. Basically checks if the layer is active since layers are stored as a bitwise (int).
Visual of how the z_index works for the TileMap:
Final Result:
Player's light will shine on wall from front and then from the sides from behind.
TLDL; Use an Area2D to shift between occluders for in front and behind wall. Use shadow range and light mask layer.