How to compare values for every child of a specific node?

Godot Version

4.2

Question

I’m trying to figure out lighting mechanics so that my player will go invisible when it’s not touched by light. I’ve got the mechanic working… but only for one light source. When I duplicate the object (my light source) that holds the script, my player’s alpha value only accounts for the most recently added object, not all.

var light_distance = global_position.distance_to(player_animation.global_position)
player_animation.modulate.a = player_animation.curve.sample(light_distance / 60) * point_light_2d.energy

I’m fairly certain this is because my code sets a definite value for the player’s alpha rather than adding and subtracting from it which I decided against trying since that wouldn’t quite work in all scenarios. If there were 10 light sources nearby, each shining a value of 10 on the player, that would then be read as a light level of 100 rather than just 10 like I would want. I also don’t just want to take the value from the nearest light source though because I want the flexibility to have light sources with different ranges. For example, if I had a light source with a range 100 and a light source with range 2 and say my player is 10 units away from the weaker light source and 11 units away from the stronger one, I would want it to calculate based on the stronger one rather than the weak one considering the player isn’t even within range of the weaker source. I also want it to depend on energy levels since my lights flicker by changing the energy level in an animation.

So I want to keep my code that sets a definite value for the player alpha, but I want to change it so instead of finding the distance to a specific light source, it finds the distance to the light source that shines brightest on the player. I’m assuming this would be possible if I made a simple formula like “(1 - (distancefromplayer / range)) * energy” and then compare the outputs that this yields for each child in my LightSources node and select the highest output, however, I’m unsure of how to go about plugging the information in for each node without specifying each node in the code. I found this forum post from 2016:
https://godotforums.org/d/17565-get-the-nearest-object
but I wasn’t able to figure out a way to get the code to work. Is this possible? Is there a better way of doing this? Thanks in advance for any help.

You could check if the player’s alpha already set to a higher value, and only apply the new value if it isn’t.

var light_distance = global_position.distance_to(player_animation.global_position)
var alpha = player_animation.curve.sample(light_distance / 60) * point_light_2d.energy
if player_animation.modulate.a  < alpha:
    player_animation.modulate.a = alpha:

You’d have to reset the player’s alpha to 0 every time before you check the light sources though.

1 Like

This seems to work for what I need but how would I go about resetting the value to 0 without it overriding the code that comes after? As it stands, I’ve just added a line that says player_animation.modulate.a = 0 before the if statement because I assumed it would process the if statement after and replace the 0 but it doesn’t. It just keeps the value at 0 for the entire runtime. Maybe I’m just thinking about this wrong but I don’t see what my problem would be?

You could put player_animation.modulate.a = 0 in the player’s _process() function, so every frame when the player’s script runs it will reset and then the scripts on the light sources run and it’ll be set to the right amount.
But it will only work if the player node is “higher” in the scene tree than the light sources, because the player’s script needs to run first.
This solution is a little more wonky than I initially thought :slight_smile:

edit:
Or you could try adding all the light sources to a “light_source” group, and handling it from the player’s script:

player’s script:

func _process():
	animation.modulate.a = 0
	for light_source in get_tree().get_nodes_in_group("light_source"):
		var alpha = light_source.get_alpha()
		if animation.modulate.a  < alpha:
			animation.modulate.a = alpha:

light source’s script:

func get_alpha():
	var light_distance = global_position.distance_to(player_animation.global_position)
	return player_animation.curve.sample(light_distance / 60) * point_light_2d.energy
1 Like

Ah. Yeah this was my original idea, I just wasn’t sure how to check each child in a given node. I’m going to go ahead and try the first way you suggested though since that seems to be simpler.

Edit: I wasn’t able to get the first solution working with resetting the alpha value every time, but I tried the new one you gave and it works perfect! I hadn’t worked with groups before so I had to look up how those work but now my light sources seem to all be working as intended. Thank you!

1 Like