Proper way to tween a control node's size inside a container

Godot Version

Godot 4.5 Mono

Question

Hi, I’m trying to tween the size of a button inside a HBoxContainer, I’m tweening the scale property because size and custom_minimum_size dont respect the pivot offset, which is set at the center of the button. It mostly works but I notice that the animation has minor jittering and is less smooth comparing to tweening the size property. So what is the correct way to achieve this?

It might be that the control node is trying to overwrite the scaling you are setting.

Whenever I need to do something like this, I put the item that requires tweening into a margin container and I tween the size of that instead. Although in truth I try to avoid tweening sizes in control nodes as it often leads to complexities that are just not worth trying to deal with. For buttons appearing, I tend to keep them in the structure for layout purposes, and tween their modulation rather than their position. The only problem with that is when the button becomes active if you are tweening slowly. Can lead to missed clicks if you do.

I am not saying you cannot do it. You can. But you might need additional surrounding control structures like a margin container so you can tween that instead.

Not the best or clearest answer, sorry, but control nodes are supposed to actively control the size and position of nodes for you (which they do brilliantly) but it does mean that trying to manually override these things can be problematic.

Make sure you don’t have multiple tweens active on the same property at the same time.

Hi, thanks for your reply. I settled with tweening the scale of button since it’s the most straightforward for my simple project. I do want to ask though, when you say “tweening the size of a margin container”, do you mean the actual size property or scale? If it is size then you have to handle pivot and font size of the button label yourself right?

I did a quick test, and TBH I was surprised at the result. Short answer is that I was wrong and adding the container made no difference at all.

(All default except button has text “Test Button” and Contol node is anchored to screen center)

Here was the testing script:

extends Control

@onready var test_button: Button = $VBoxContainer/MarginContainer/Button
@onready var test_button_container: MarginContainer = $VBoxContainer/MarginContainer

const TWEEN_DURATION: float = 2.5

func _input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_up"):
		scale_node_to_zero(test_button)
		tween_node(test_button)
	elif event.is_action_pressed("ui_down"):
		scale_node_to_zero(test_button_container)
		tween_node(test_button_container)


func scale_node_to_zero(node_to_scale: Node) -> void:
	node_to_scale.pivot_offset = node_to_scale.size / 2
	node_to_scale.scale = Vector2.ZERO


func tween_node(node_to_tween: Node) -> void:
	var container_tween: Tween = create_tween()
	container_tween.tween_property(node_to_tween, "scale", Vector2.ONE, TWEEN_DURATION)

If you change the scale of the button or the container slowly it is equally jittery. Changing the tween duration to 0.3 makes it appear nice and smooth.

So TBH I don’t think it matters if you do the container or the object. I do recall in my last game UI wrapping things in containers that I then animated, but perhaps the structures in the containers were more complex, or playing with the settings of the containers and structures helped (like shrink center etc) but yes, you always need to deal with the pivot points anyway.

So it looks like my original suggestion was wrong. Sorry. Perhaps this is why I avoid tweening in this way entirely, and just fade things in and out, or slide them onto or off the screen.

If anyone else has any suggestion I would also be pleased to hear them.

I reduced the tween duration to 0.1s so it visually made no difference to me.

As for non-scale solutions, I’ve come up with 2. One is putting the button inside the margin container and tweening the 4 margins of the container, the other one is writing a method to change the size and then subtract half of the delta size from position to account for centered pivot.

1 Like

Good ideas there, and 0.1 is certainly fast enough to get rid of the jitter.

Now you say it, I do recall having to tween both the scale and position too! Although to be fair I think just setting the pivot point works just as well. And now you have said that I also now recall it was for upgrade cards that got bigger on rollover. I could probably dig it out now I have remembered that!

I never thought of tweening the margins. That is an interesting idea.

Any way, glad you got it working for your particular example. In the next few days I have a UI to create with animations, so this was an interesting exercise for me - thank you.

1 Like