I want to flicker a light based on an array that the parent node has

Godot Version

4.4.1

Question

I want to make some lights flicker in this scene, the way the scene is setup is the parent node is a control and a child is a Node3D, the 3D node has spotlights in them, the parent control node has a array called active_entities that holds all the enemies in a room, all I want to do is make the lights red and make them flicker over time if there are any entities active.

I have tried to use get_parent() but that just returns the Node3D not the root node, and I tried to make an export and directly reference the root control node, but it does not change the colour at all.

there’s a lot wrong here.

1 - you are defining an array and 3 variables that then go in the array. you could just have the array and assign the nodes in ready.

doing $Node is the equivalent of doing get_node(“Node”)


chosen_lights = [get_node(“BaseRoom/Lights/StopLight3D”)]#etc

2 - infected is an int but you are treating it like a bool, just make it a bool.

3 - you are calling methods in process. process runs every frame.
the way to call something like this is through signals. you connect the method to a signal and when the signal is emitted it triggers the function ONCE.
if you need the lights to flicker, you must use a Timer. A common way is to create a timer with get_tree().create_timer(time).timeout and use an await. this halts execution of the code for X seconds. doing so with small numbers like 0.2 can be used to create the flicker effect.
another way is to use a Tween.
but either needs to happen only once.

4 - inside those methods there are calls to random, that’s not going to work with it running in process.

Solution:
you could create a signal and emit it if infected becomes true, then after the animation finishes, set it to false.


signal becomes_infected
var infected : bool = false

func _ready() -> void:
	becomes_infected.connect(infected_flicker)

func _process(delta : float) -> void:
	if not infected:
		if room.active_entities.size() > 0:
			infected = true
			becomes_infected.emit()

func infected_flicker() -> void:
	var tween : Tween = create_tween()
	var light = chosen_lights.pick_random() 
	tween.tween_property(light, "light_energy", 0.05, 0.1)
	tween.tween_property(light, "light_energy", 1.0, 0.1)
	tween.tween_property(light, "light_energy", 0.05, 0.1)
	tween.tween_property(light, "light_energy", 1.0, 0.1)
	tween.tween_property(light, "light_color", Color.RED, 0.1)
	tween.tween_property(self, "infected", false, 0.1)

then you would do something similar for when going out of the infected state.

Use owner instead of get_parent() to access the root control node, then flicker the lights based on active_entities in _process.