How to reuse this code in stage/world two?

Godot Version

4.7 (I am up to date)

Question

What is a good way to reuse this code in stage/world two?
The code is there to manage which of the texture_rects are shown and checks in the button_pressed function if this level is unlocked, the button should change the scene.



@onready var texture_rect_1: TextureRect = $NinePatchRect/GridContainer/Button1/TextureRect1
@onready var texture_rect_2: TextureRect = $NinePatchRect/GridContainer/Button2/TextureRect2
@onready var texture_rect_3: TextureRect = $NinePatchRect/GridContainer/Button3/TextureRect3


func _ready() -> void:
	File.load_game()# this is to load the level data from a json file
    # file is a global scipt for saving and loading game data
	if File.stage1[0] == true:
		texture_rect_1.hide()

	if File.stage1[1] == true:
		texture_rect_2.hide()

	if File.stage1[2] == true:
		texture_rect_3.hide()

func _on_button_1_pressed() -> void:
	if File.stage1[0] == true:
		get_tree().change_scene_to_file("res://scenes/levels/stage1/level_1.tscn")


func _on_button_2_pressed() -> void:
	if File.stage1[1] == true:
		get_tree().change_scene_to_file("res://scenes/levels/stage1/level_2.tscn")


func _on_button_3_pressed() -> void:
	if File.stage1[2] == true:
		get_tree().change_scene_to_file("res://scenes/levels/stage1/level_3.tscn")

What I’d probably do is make the script take the stage as an export and loop the buttons instead of writing each one out. Then the same script and the same scene work for stage 2 with one value changed in the Inspector.

@export var stage_number: int = 1

@onready var buttons: Array = $NinePatchRect/GridContainer.get_children()

func _ready() -> void:
	File.load_game()
	var unlocked: Array = File.get("stage%d" % stage_number)
	for i in buttons.size():
		if unlocked[i]:
			buttons[i].get_child(0).hide()
		buttons[i].pressed.connect(_on_level_pressed.bind(i))

func _on_level_pressed(i: int) -> void:
	var unlocked: Array = File.get("stage%d" % stage_number)
	if unlocked[i]:
		get_tree().change_scene_to_file("res://scenes/levels/stage%d/level_%d.tscn" % [stage_number, i + 1])

File.get(“stage1”) reads the variable by name, so stage_number picks the array without you writing a match on it. If you’re able to change the File script, keeping them as one array of arrays (File.stages[0], File.stages[1]) would be tidier than separate stage1 and stage2 variables.

get_child(0) is assuming the TextureRect is the button’s only child, so reach it by name if there’s anything else under there. And if the pressed signals are already connected in the editor, remove those or they’ll fire twice.

You can reduce this code by using the present pattern, every texture rect/button is numbered in sequence matching the File.stage1 index + 1

func _ready() -> void:
	File.load_game()
	
	for i in 3:
		# get_node allows use of dynamically created strings
		# with string formatters %d is replaced by the index + 1
		var button: Button = get_node("NinePatchRect/GridContainer/Button%d" % (i + 1))

		# bind lets us use the same function for signal pressed
		# while adding the index as an argument
		button.pressed.connect(_on_button_pressed.bind(i))

		# using index to check the saved data
		# though I didn't fit in special case for File.stage2[0]
		if File.stage1[i] == true:
			# again get_node allows dynamic paths
			# this time starting from the button
			var texture: TextureRect = button.get_node("TextureRect%d" % (i + 1))
			texture.hide()


# the bound value is passed into 'index' and we use it similarly
# to the above examples
func _on_button_pressed(index: int) -> void:
	if File.stage1[index] == true:
		get_tree().change_scene_to_file("res://scenes/levels/stage1/level_%d.tscn" % (index + 1))

I like @Baz 's example better, using more techniques than getting children by get_node with a formatted string, the get_children() function is great when you can use it as an array directly which I would assume is the case.

Okay guys thank you, but i am kinda confused.
It wil take some time for me to uderstand this (And some tests and research) because I am not an coding expert…
But I have an idea wat is going on in those scripts(I thought the only way to get a button input is with a signel LMAO).
I may have some questions tomorow.

We are using signals! Anything done through the editor can also be done in scripts, including connecting signals. Both examples use button.pressed.connect to connect to the signal in a more dynamic way.

It’s certainly a different mindset to program as a grouping of objects instead of thinking individually, so do take your time, the bulk of the trick is using for loops.