Fast clicking a button with Tween animation problem

Godot Version

v4.5.dev1.official [97241ffea]

Question

I thought I’d start a simple new project that has a button which would have scaling up & down Tweening animations when clicked but after 2 days of trying I’m in need of some help.

My first hurdle was fixing the blurry “test” text when increasing the size of the button, this turned out to be because I needed to scale the font size instead of the Button node.

That seemed to do the trick though I needed to use the _process function for it since I can’t use the add_theme_font_size_override inside the tween itself.
This also made sure that the scaled up button properly worked with resizing the vboxcontainer to not overlap my second button, using scale didn’t do that.

Then I tried to trigger the animation a couple of times by clicking on it fast and noticed it blew up in size or shrunk down a lot, not the regular values(50 and 250) that it should have as start/end values.

I thought perhaps this had to do with the way it works inside the _process function but printing out the current font_size_value each button pressed signal without using the _process function also showed the values varying wildly.

I tried a lot from using different tween objects, to awaits, to passing the value to the Tween animation a different way, to if tween.is_processing() or tween.kill(), but nothing seems to solve it.

Is there any reliable way to get this working so I can fast-click the button as fast as I want and it always returning to one of 2 font size states while awaiting each other’s animations?

Here’s my current code that I ended up with:

extends Button

var big = true
var font_size_value = 50

func bigger_tween(tween):
	tween.tween_property(self, "font_size_value", font_size_value + 200, 0.2).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_OUT)
	tween.tween_property(self, "font_size_value", font_size_value + 200, 0.3).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)

func smaller_tween(tween):
	tween.tween_property(self, "font_size_value", font_size_value - 200, 0.2).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
	tween.tween_property(self, "font_size_value", font_size_value - 200, 0.3).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_OUT)

func _on_pressed() -> void:
	print(font_size_value)
	print(big)
	var tween = get_tree().create_tween()
	if big:
		bigger_tween(tween)
	else:
		smaller_tween(tween)
	
	big = !big

func _process(_delta: float) -> void:
	self.add_theme_font_size_override("font_size", font_size_value)

I think the only way to properly fix it is by reacting to the finished signals with a bool:

extends Button

var big = true
var is_tweening = false
var font_size_value = 50

func done_tweening():
	is_tweening = false

func bigger_tween():
	is_tweening = true
	var tween = get_tree().create_tween()
	tween.tween_property(self, "font_size_value", font_size_value + 200, 0.2).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_OUT)
	#tween.tween_property(self, "font_size_value", font_size_value + 200, 0.3).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
	tween.finished.connect(done_tweening)

func smaller_tween():
	is_tweening = true
	var tween = get_tree().create_tween()
	tween.tween_property(self, "font_size_value", font_size_value - 200, 0.2).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
	#tween.tween_property(self, "font_size_value", font_size_value - 200, 0.3).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_OUT)
	tween.finished.connect(done_tweening)

func _on_pressed() -> void:
	if is_tweening:
		return
	
	if big:
		bigger_tween()
	else:
		smaller_tween()
	
	big = !big

func _process(_delta: float) -> void:
	self.add_theme_font_size_override("font_size", font_size_value)

It also felt that the finished signal was very slow before I could press the button again but I guess that’s because I’m trying to tween 2 different transitions at the same time.
Commenting out one of them makes it feel responsive again ánd no longer introduces the scaling problems.

You should be able to use is_running but you need a reference to the running tween. For this you can declare it as a member of the class:

extends Button

# declare the variable referencing the tween here so we can access it
# when the function is called again
var tween: Tween

# ...

func _on_pressed() -> void:
     # now we can check if there is a running tween
     if tween and tween.is_running():
       return
	
    # use Node.create_tween to bind the tween to the lifecycle of the node
    tween = create_tween()

    if big:
        bigger_tween()
    else:
       smaller_tween()
	
	big = !big

Instead of setting the property and then calling the function in _process, you can tween functions with tween_method. Alternatively you could also specify a setter for font_size_value that calls the function.

The tweeners are not executed ‘at the same time’. They are executed one after the other by default (this can be changed). The tween is only finished, when all tweeners are done (after 0.5s in your case).

1 Like

I noticed the set_parallel method indeed and thought it took the full 0.5 seconds to run.

Thanks for the suggestions! I’ll definitely look into the tween_method and use the tween reference to check if it’s running :slight_smile: