DaveTheCoder I got it to work but the animation doesn't look like the one in the video the buttons instead fall when selected


extends Control

@export var save = load("res://Data/Stages/Menu/SaveMenu.tscn")
@export var encore = load("res://Data/Stages/Menu/EncoreMenu.tscn")
@export var time = preload("res://Data/Stages/TZ/TestZonetime.tscn")
@export var options = preload("res://Data/Stages/Menu/OptionsMenus.tscn")
@export var Extras = preload("res://Data/Stages/Menu/ExtrasMenu.tscn")
# Go back to title 
@export var back = preload("res://Data/Stages/Title/Title.tscn")

# Variables for button management
var buttons: Array = []
var selected_index: int = 0
var tween

# Called when the node enters the scene tree for the first time.
func _ready():
	buttons.clear()  # Clear any existing values (good practice)
	
	# Create a Tween instance
	

	# Loop through all child nodes of the Control node
	for i in range(get_child_count()):
		var button = get_child(i)
		
		# Check if the child is a TextureButton
		if button is TextureButton:
			buttons.append(button)  # Add it to the buttons array
			button.set_meta("index", buttons.size() - 1)  # Store the button index as metadata
			
			# Connect the pressed signal using a lambda to pass the button
			button.pressed.connect(Callable(self, "_on_button_pressed").bind(button))

	# Set the initial selection
	update_button_selection()

func _input(event):
	# Handle input for navigation
	if event.is_action_pressed("gm_up"):
		move_selection(-1)
		$"../../CanvasLayer/Sprite2D".frame = 0
		$"../../CanvasLayer/AnimationPlayer".play("tv")
		$"../../SFX/MenuBleep".play()
		
	elif event.is_action_pressed("gm_down"):
		move_selection(1)
		$"../../CanvasLayer/Sprite2D".frame = 0
		$"../../CanvasLayer/AnimationPlayer".play("tv")
		$"../../SFX/MenuBleep".play()

	# Handle 'gm_action' for triggering the selected button
	elif event.is_action_pressed("gm_action"):
		if selected_index >= 0 and selected_index < buttons.size():
			buttons[selected_index].emit_signal("pressed")  # Manually emit the pressed signal for the selected button

	elif event.is_action_pressed("gm_action2"):
		Global.main.change_scene_to_file(back, "FadeOut")

func move_selection(direction: int):
	var prev_index = selected_index  # Store the previous index
	selected_index += direction
	
	# Wrap around selection
	if selected_index < 0:
		selected_index = buttons.size() - 1  # Wrap to the last button
	elif selected_index >= buttons.size():
		selected_index = 0  # Wrap to the first button
	
	# Update button visuals and start tween animation
	update_button_selection()
	
	# Stop any ongoing tweens to avoid conflicts


	var selected_button = buttons[selected_index]
	var previous_button = buttons[prev_index]
	if selected_button != null and previous_button != null:
		# Move using `rect_position` for UI elements
		var selected_target_pos = selected_button.position + Vector2(0, -10)
		var previous_target_pos = previous_button.position + Vector2(0, 10)
		
		# Tween to move the selected button slightly upward and the previous button downwa
		tween = get_tree().create_tween()  # Create a new Tween instance
	# Tween the selected button's position
		tween.tween_property(selected_button, "position", selected_target_pos, 1).as_relative().set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
		tween.tween_property(selected_button, "position", previous_target_pos, 1).as_relative().from_current().set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)

func update_button_selection():
	# Update button visuals based on selection
	for i in range(buttons.size()):
		var button = buttons[i]
		var anim = button.get_node("MainAnimator")
		anim.play("default")

		# Check if this button is the currently selected one
		if i == selected_index:
			# Play the hover animation
			var start = button.get_node("MainAnimator")
			start.play("click")
			var animation_player = button.get_node("ShadeBlink")  # Adjust the path if needed
			animation_player.play("blink")  # Play the hover animation
			$"../../CanvasLayer/Sprite2D".frame = 4
			
func _on_button_pressed(button):
	# Retrieve the index from the button's metadata
	var index = button.get_meta("index")
	
	# Play the press animation
	var animation_player = button.get_node("MainAnimator")  # Adjust the path if needed
	animation_player.play("blinkLabel")  # Play the press animation

	# Handle button press actions based on the index
	match index:
		0:
			$"../../SFX/MenuAccept".play()
			await $"../../SFX/MenuAccept".finished
			Global.main.change_scene_to_file(save)
		1:
			$"../../SFX/MenuAccept".play()
			await $"../../SFX/MenuAccept".finished
			Global.main.change_scene_to_file(encore)
		2:
			$"../../SFX/MenuNotReady".play()
		3:
			$"../../SFX/MenuNotReady".play()
		4:
			$"../../SFX/MenuAccept".play()
			await $"../../SFX/MenuAccept".finished
			Global.main.change_scene_to_file(options)
		5:
			$"../../SFX/MenuAccept".play()
			await $"../../SFX/MenuAccept".finished
			Global.main.change_scene_to_file(Extras)

I don't understand what you're trying to do with a tween. You haven't explained it clearly.

I suggest that you create a new project for learning tweens. Keep it simple. Add a sprite, and experiment with using tweens on it until you fully understand how tweens work. Use the project only for testing tweens and nothing else. Keep the project as a reference.

    DaveTheCoder I am trying to make what is seen in the video where when up or down is pressed it scrolls the buttons up or down

    You want the button to move a short distance, and then move back? Then you need two tweens.

    Example:

    var tween: Tween
    
    tween = create_tween()
    # Move Sprite's position from (0,100) to (100,200) over 0.5 second.
    tween.tween_property($Sprite, "position", Vector2(100.0, 200.0), 0.5).from(Vector2(0.0, 100.0))
    
    # Wait for tween to finish.
    await tween.finished
    
    tween = create_tween()
    # Move Sprite's position from (100,200) to (0,100) over 0.5 second.
    tween.tween_property($Sprite, "position", Vector2(0.0, 100.0), 0.5).from(Vector2(100.0, 200.0))

    References:
    https://docs.godotengine.org/en/4.3/classes/class_tween.html
    https://docs.godotengine.org/en/4.3/classes/class_propertytweener.html
    https://docs.godotengine.org/en/4.3/tutorials/scripting/gdscript/gdscript_basics.html#awaiting-signals-or-coroutines

      No, that code used only one tween. It may have been intended for Godot 3.

      ChatGPT is useful for pointing you in the right direction, but you can't assume that its code is 100% correct. You have to go through it line by line and make corrections if needed.

        DaveTheCoder The example code you gave me works but it breaks the selection code

        
        extends Control
        
        @export var save = load("res://Data/Stages/Menu/SaveMenu.tscn")
        @export var encore = load("res://Data/Stages/Menu/EncoreMenu.tscn")
        @export var time = preload("res://Data/Stages/TZ/TestZonetime.tscn")
        @export var options = preload("res://Data/Stages/Menu/OptionsMenus.tscn")
        @export var Extras = preload("res://Data/Stages/Menu/ExtrasMenu.tscn")
        @export var back = preload("res://Data/Stages/Title/Title.tscn")
        
        var buttons: Array = []
        var selected_index: int = 0
        var tween
        
        func _ready():
        	buttons.clear()
        	for i in range(get_child_count()):
        		var button = get_child(i)
        		if button is TextureButton:
        			buttons.append(button)
        			button.set_meta("index", buttons.size() - 1)
        			button.pressed.connect(Callable(self, "_on_button_pressed").bind(button))
        
        	update_button_selection()
        
        func _input(event):
        	if event.is_action_pressed("gm_up"):
        		move_selection(-1)
        		$"../../CanvasLayer/Sprite2D".frame = 0
        		$"../../CanvasLayer/AnimationPlayer".play("tv")
        		$"../../SFX/MenuBleep".play()
        
        	elif event.is_action_pressed("gm_down"):
        		move_selection(1)
        		$"../../CanvasLayer/Sprite2D".frame = 0
        		$"../../CanvasLayer/AnimationPlayer".play("tv")
        		$"../../SFX/MenuBleep".play()
        
        	elif event.is_action_pressed("gm_action"):
        		if selected_index >= 0 and selected_index < buttons.size():
        			buttons[selected_index].emit_signal("pressed")
        
        	elif event.is_action_pressed("gm_action2"):
        		Global.main.change_scene_to_file(back, "FadeOut")
        
        func move_selection(direction: int):
        	var prev_index = selected_index
        	selected_index += direction
        
        	# Wrap around selection
        	if selected_index < 0:
        		selected_index = buttons.size() - 1
        	elif selected_index >= buttons.size():
        		selected_index = 0
        
        	# Update button visuals and tween their positions
        	tween_buttons(prev_index, selected_index)
        
        func tween_buttons(prev_index: int, selected_index: int):
        	if tween:
        		tween.kill()  # Remove previous tween to avoid conflicts
        
        	
        
        	var selected_button = buttons[selected_index]
        	var previous_button = buttons[prev_index]
        
        	# Define target positions (adjust this as per your desired offset)
        	var selected_target_pos = selected_button.position + Vector2(0, -20)
        	var previous_target_pos = previous_button.position + Vector2(0, 20)
        
        	tween = create_tween()
        	# Move Sprite's position from (0,100) to (100,200) over 0.5 second.
        	tween.tween_property(selected_button, "position", Vector2(selected_button.position.x, 100.0), 0.5).from(Vector2(selected_button.position.x,selected_button.position.y))
        	# Wait for tween to finish.
        	await tween.finished
        	tween = create_tween()
        	# Move Sprite's position from (100,200) to (0,100) over 0.5 second.
        	tween.tween_property(previous_button, "position", Vector2(0.0, 100.0), 0.5).from(Vector2(previous_button.position.x,previous_button.position.y))
        
        	# Ensure the selected button plays the bounce animation
        	selected_button.get_node("MainAnimator").play("click")
        
        func update_button_selection():
        	for i in range(buttons.size()):
        		var button = buttons[i]
        		var anim = button.get_node("MainAnimator")
        		anim.play("default")  # Reset all buttons to their default state
        
        		if i == selected_index:
        			# Play hover animation for selected button
        			var start = button.get_node("MainAnimator")
        			start.play("click")
        			var blink_anim = button.get_node("ShadeBlink")
        			blink_anim.play("blink")
        			$"../../CanvasLayer/Sprite2D".frame = 4
        
        func _on_button_pressed(button):
        	var index = button.get_meta("index")
        	var animation_player = button.get_node("MainAnimator")
        	animation_player.play("blinkLabel")
        
        	match index:
        		0:
        			$"../../SFX/MenuAccept".play()
        			await $"../../SFX/MenuAccept".finished
        			Global.main.change_scene_to_file(save)
        		1:
        			$"../../SFX/MenuAccept".play()
        			await $"../../SFX/MenuAccept".finished
        			Global.main.change_scene_to_file(encore)
        		2:
        			$"../../SFX/MenuNotReady".play()
        		3:
        			$"../../SFX/MenuNotReady".play()
        		4:
        			$"../../SFX/MenuAccept".play()
        			await $"../../SFX/MenuAccept".finished
        			Global.main.change_scene_to_file(options)
        		5:
        			$"../../SFX/MenuAccept".play()
        			await $"../../SFX/MenuAccept".finished
        			Global.main.change_scene_to_file(Extras)
        
        It selects 2 options and moves them at the same time

          The numbers I used in that code were only examples to show how to use tweens. Replace them with whatever fits your situation.

          Raptorkillz again, stop using chatGPT. this is something very simple and you are not learning anything from it.
          chatGPT spews shit, and the process of making chatGPT code work is akin to polishing a turd.

          I told you how to do this in one of the first posts, here's an even easier solution, but you have go and use your own "human hands", not wait for magic solutions.

          1 - create a VBoxContainer, make it as big as it needs to be to accommodate the number of buttons.
          2 - put your buttons in there
          3 - try shifting the buttons horizontal position inside the VBoxContainer
          4 - set next and previous buttons for each button

          5 - to add animation, on each button, connect the focus_entered and focus_exited signal through code and play an animation with a tween

          func _ready() -> void:
          	focus_entered.connect(selected)
          	focus_exited.connect(unselected)
          
          func selected() -> void:
          	var tween : Tween = create_tween()
          	tween.tween_property(self, "scale", Vector2(1.1, 1.1), 0.1)#change size, or whatever animation you want
          
          func unselected() -> void:
          	var tween : Tween = create_tween()
          	tween.tween_property(self, "scale", Vector2(1.0, 1.0), 0.1)#reset size

          and then you would have to setup a theme to change the button focused, hover, pressed, etc visuals for your buttons.
          for more complex animations like that shadow, you would have to add more nodes to each button, make them scenes and use the tweens to hide/unhide the shadow.
          tweens can also be use to start or stop a loop of color change.

            Jesusemora Okay then how would I make it work with custom inputs

            Oh and the script that chatgpt made did work But the movement code to make the buttons slide like in the video was done with tweens but the tweens weren't animating like the video

              Raptorkillz you never answered what you mean by custom inputs, and continue to go on tangents and create new posts.
              If what you mean is setting custom inputs, focus_next and focus_previous use the default input maps like ui_left, ui_up, ui_right, ui_accept, etc.

              a quick search shows that these can be modified from the InputMap singleton
              https://docs.godotengine.org/en/stable/classes/class_inputmap.html#class-inputmap

              I guess action_add_event and action_erase_event can be used to rebind keys. where the action would be ui_left and the event would be the key press/button press.

              another way appears to be through project settings, you can set the default actions used for focus_next, focus_previous, etc by setting a different action, like a custom one:
              https://docs.godotengine.org/en/stable/classes/class_control.html#class-control-property-focus-neighbor-top
              https://docs.godotengine.org/en/stable/classes/class_projectsettings.html#class-projectsettings-property-input-ui-focus-next

              Raptorkillz This is why I decided to ask chatgpt its because you didn't answer my question

              we have other things to do, this isn't a chat, it's a forum. so when asking a question you have to try and put as much information as posible and explain well, because the answer WILL take a while, specially a good one.
              there are forums where questions go unanswered for decades, here it's pretty fast.