How to fix a problem with Timer and the signal Timeout

Godot Version

Im using the version of Godot 4

Question

Hello, I have problems with a Timer and its timeout signal, I am using a system to manage my player’s buffs. When applying the buff it does it perfectly, the problem is when I want to make a Timer so that when the duration of the effect ends it reverts and returns to its original state.

I’m not an experienced GDScript user but here’s my guess

You’re incorrectly connecting your _on_timer_timeout function to the new_timer’s timeout-signal. As far as I know, this is how you connect to a built-in signal:

    var timer = get_node("Timer")
    #timer.timeout.connect(_on_timer_timeout)  # Standard
    timer.timeout.connect(callable)            # Your use-case

If that’s not the issue, maybe it’s because you’re binding a set of parameters to your callable whose function usually don’t have parameters (_on_timer_timeout)

    # Your callable
    var callable = Callable(self, "_on_timer_timeout").bind(new_timer, target, attribute, value)

Maybe your intent is not to call _on_timer_timout but instead revert_effect?
I don’t know. I’m just guessing here.

2 Likes

@Sweatix Is correct, you’re not connecting the sinal correctly, the correct way is: node_that_you_want_connect.signal_name.connect(function_you_want_to_be_called) in your case should be new_timer.timeout.connect(_revert_effect.bind(target, atribute, value))

Another way you can do it put everything in one function something like:

func apply_buff(target, atribute, value, duration)
	# Do the code to apply the buff
	await get_tree().create_timer(duration).timeout
	# Do the code to remove the buff
2 Likes

Hello, I’m sorry I couldn’t answer. I have just tried what they told me but it has not worked, it does not produce the Timeout signal from the Timer. If you can think of any other way, I would like you to let me know. I will also try the other solution that you gave me.

I have tried both solutions and neither has performed the Timeout signal.

I leave screenshots in case there are any errors or something I don’t see.

CapturaMethodsSetTimer

Do you understand what @matheusmdx’s second code snippet does?
It will await for the timer’s timeout-signal before executing the rest of the code.

If this doesn’t work for you, there’s something else wrong.
Are you calling your set_timer(); and if so, when?

For reference:

Something is wrong, this is the way to create a one time timer, can you upload your project somewhere for me take a look?

Here you have the link to my Drive folder where I have the project in a .ZIP

This link asks for authorization, you need to make this as public

Sorry, Videojuego_Proyecto616 – Google Drive

Anything else you see that could be improved I would like to know, since I am a beginner and I would like to improve.

Ok, today i had time to look you code and i found the problem, you’re was doing the timeout signal incorrectly as i said before, but you also was deleting the node before the Timer had time to emit the timeout signal:

func activate_effect():
	print(item_type)
	var effect = effects[item_type]
	match item_type:
		ItemType.SPEED:
			print(effect["amount"])
			player.speed += effect["amount"]
			set_timer(effect["duration"], shared_player[0], "speed", -effect["amount"])
			print(player.speed)
		ItemType.HEALTH:
			player.vida_actual += effect["amount"]
			player.actualizar_vida()
			print(player.vida_actual)
			print(player.vida_corazones)
		ItemType.STRENGTH:
			print(effect["amount"])
			shared_cabeza.daño += effect["amount"]
			set_timer(effect["duration"], shared_cabeza, "daño", -effect["amount"])
			print(shared_cabeza.daño)
		ItemType.FIRE_RATE:
			print(effect["amount"])
			shared_cabeza.fire_rate += effect["amount"]
			set_timer(effect["duration"], shared_cabeza, "fire_rate", -effect["amount"])
			print(shared_cabeza.fire_rate)
		ItemType.HEALTH_MID:
			print(player.vida_actual)
			player.vida_actual += effect["amount"]
			player.actualizar_vida()
			print(player.vida_actual)
			print(player.vida_corazones)
	item_types_available.erase(item_type)
	queue_free()


You need to wait the timeout signal before delete the node:

	item_types_available.erase(item_type)
	# Wrong, if you delete the node now, the timeout signal
	# will never be emmited and the effect will keep forever
	#queue_free()
	
	# You need to first disable the area detection for avoid the same item
	# apply the buff again, also need to do it in the idle step, otherwise
	# you can crash you game when export because you're deleting physic related
	# node in the physics step, so we use set_deferred
	$AreaItem.set_deferred("monitoring", false)
	
	# Also make the node invisible to pass the sensation you already deleted the
	# item
	visible = false
func revert_effect(target, attribute, value):
	if target == shared_player[0]:
			match attribute:
				"speed":
					shared_player[0].speed += value
	elif target == shared_cabeza:
			match attribute:
				"fire_rate":
					shared_cabeza.fire_rate += value
				"daño":
					shared_cabeza.daño += value
	
	# There is the correct moment to delete the node
	queue_free()

I recommend you look more the debbuger tab, during the gameplay lot of errors appear about calling unnexistent signals, add physics related node outside idle step, etc. Also i recommend you read more tutorials about Godot 4, this code looks like you’re porting from Godot 3.

Thank you very much, I hadn’t thought of that. I’ll try to look at what you told me and fix it.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.