BlackWindBooks.com | Newsletter! | risingthumb.xyz | achtung.risingthumb.xyz | github.com/RisingThumb | site map

risingthumb.xyz "True friend stab you in the front."

Quiver Fluid Fog of War Effect

This blog post is a textual version of my video on the same topic. You can find that here.

This effect is taken directly from Teleglitch, though I did not refer to any of their code to achieve it. Teleglitch's code is available if you look through its files.

=> Sample project provided under MIT License
=> Video demonstration

To achieve this I create a Node2D and give it a Sprite child with the sprite I want to use. I then give the Node2D a Polygon2D and create this polygon which will be where the fog of war is casted from. It is recommended to cover the whole sprite, as we will use an offset to give it the motion we see. We then add this Node2D to a group called walls. We attach a script to it with the following text.

extends Node2D


func getPool():
	var vecsCurr = $Polygon2D.polygon
	var vecs = []
	for vec in vecsCurr:
		vecs.append(global_position + vec.rotated(global_rotation))
	return vecs

What this script does, is define a function called getPool() which we can call to get an array of the global positions of the vectors with their rotation properly accounted for. We save this scene as Wall.tscn

We create a new scene called LightCaster.tscn which will be where the light is cast from, and attach a script with the following text.

extends Node2D


var vectorObjects = []
const offset  = 10

func _draw():
	for vectorObject in vectorObjects:
		var importantVectors = []
		for vector in vectorObject:
			var offsetVector = (vector - get_global_mouse_position()).normalized()* offset
			importantVectors.append(vector + offsetVector)
			importantVectors.append((vector-get_global_mouse_position()).normalized()*1600+vector)
		var important = Geometry.convex_hull_2d(PoolVector2Array(importantVectors))
		draw_colored_polygon(important, Color.black)

func _ready():
	var walls = get_tree().get_nodes_in_group("walls")
	for wall in walls:
		vectorObjects.append(wall.getPool())

func _process(delta):
	if Input.is_action_pressed("mouseClick"):
		update()

The function _draw() is called whenever update() is called, and in this draw function we handle the drawing of the Fog Of War as this is an additive method. By additive method, I mean that we draw the shadows on top of everything. The function _process(delta) can be replaced in your code, as what is key is that you call update() somewhere. You will notice towards the top we have an empty array named vectorObjects. What we do with this is in the _ready() function that is called when the node enters the tree, we get all the vectorArrays of all the walls. For your game, this may cause an issue with memory if you have too many walls, so you could create a timer to get all the relevant arrays of vectors within however many units of your central point.

We shall now discuss the _draw() function, repeated below.

const offset  = 10

func _draw():
	for vectorObject in vectorObjects:
		var importantVectors = []
		for vector in vectorObject:
			var offsetVector = (vector - get_global_mouse_position()).normalized()* offset
			importantVectors.append(vector + offsetVector)
			importantVectors.append((vector-get_global_mouse_position()).normalized()*1600+vector)
		var important = Geometry.convex_hull_2d(PoolVector2Array(importantVectors))
		draw_colored_polygon(important, Color.black)

What this does is loop over vectorObject in vectorObjects. Remember that vectorObject is just an array of Vectors. We then create a new empty array which will store all vectors we use for drawing the coloured polygon on top of everything. We then loop over every vector in vectorObject and add the vector that has been offset slightly, and the vector that has been extrapolated far out of the screen. We use get_global_mouse_position() as our central point here, but any Vector2 will work just as well. Normalization is where we take a vector and change it to have a scalar value of 1 but an unchanged angle. As a result, it effectively gives us the direction which we can multiply by. We next use a function Godot provides called convex_hull_2d. Explaining the convex hull algorithm is outside of the scope of this text, but effectively what it does is get the minimum points required to draw a line from point to point to capture all points within. With this, we then draw a black coloured polygon with the points returned from this function.

That's how you achieve a fluid fog of war effect without relying on Light2D or anything else.

Published on 2020/08/22

Articles from blogs I follow around the net

BAT-EYES #18

BAT-EYES "You’re blind, idiot." Roald had apparently entered while Saito sat on his bed, running his hands along the edges of his visor, collating his sorrows. Call it archive fever. Roald ran his own hand through his frizzy red hair (which Saito c…

via I'm not really Stanley Lieber. December 19, 2024

Neurodivergence and accountability in free software

In November of last year, I wrote Richard Stallman’s political discourse on sex, which argues that Richard Stallman, the founder of and present-day voting member of the board of directors of the Free Software Foundation (FSF), endorses and advocates for a ha…

via Drew DeVault's blog September 25, 2024

reblog - Moments of Introspection: Fun With AI: Cute Doggies

Moments of Introspection: Fun With AI: Cute Doggies: I am starting to get into creating graphics with AI. The following doggies, I created with  Idyllic . I was trying to get a god that is simi...:::Feed:::

via Filozofia September 24, 2024

Generated by openring