How to Increment a Path Name

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Neestrid
@onready var ExplorerWhiteUI00 =  $CanvasLayer/ExplorerList/ExplorerWhiteUI00
@onready var ExplorerWhiteUI01 =  $CanvasLayer/ExplorerList/ExplorerWhiteUI01
@onready var ExplorerWhiteUI02 =  $CanvasLayer/ExplorerList/ExplorerWhiteUI02
@onready var ExplorerWhiteUI03 =  $CanvasLayer/ExplorerList/ExplorerWhiteUI03

@onready var Portrait00 =  $CanvasLayer/ExplorerList/Portrait00
@onready var Portrait01 =  $CanvasLayer/ExplorerList/Portrait01
@onready var Portrait02 =  $CanvasLayer/ExplorerList/Portrait02
@onready var Portrait03 =  $CanvasLayer/ExplorerList/Portrait03

@onready var PathToExplorer00 =  $Explorer00
@onready var PathToExplorer01 =  $Explorer01
@onready var PathToExplorer02 =  $Explorer02
@onready var PathToExplorer03 =  $Explorer03

I need to access those path for my code. It is working for now… BUT
My question is : is there a way to loop this, so I can add 50 explorer and my code is not unreadable ?

Thanks !

Hmmm… Yeah, this seems quite inefficient, but it’s not clear what you goals are. How do you expect to access these variables later? With the method you’re using now, you’ll still need to reference each individual variable in code, by its unique name. So, by somehow creating the references automatically, you streamline that process, the access to them will still be labor intensive and error prone.

Knowing nothing about what you’re doing here, I might suggest that you organize them in some manner that allows you to find and reference them programmatically. That organization could be done by (for example) common parents in the scene tree or group assignments.

Either of those would allow you to find the nodes via code…

I’d recommend that you provide more details about what you’re trying to do here as there’s likely a better approach.

jgodfrey | 2023-05-29 15:06

I would like to move “explorers” throught a world.

Just like in Rimworld, when I click on the portrait it should move the good explorer. In the same time I would like to turn the dark UI to the white UI so the player can see which explorer is currently selected.

Each Explorer and UI has its unique number so I know which one to acess.
UI00 = Explorer00, UI01 = Explorer01 etc…

In my opinion I need to access the UI (Dark to White), the Texturebutton of the UI, and the Explorer to match the Explorer with the UI selected.

I am currently working on a solution to my problem, I think I find something that should work. I am surely not a pro of coding games so if there is a better alternative I am not against it

Screenshot of the game :
Screenshot by Lightshot

Neestrid | 2023-05-29 15:44

I think your implementation is a bit confusing. It would be perfect to create multiple classes, like

class_name Explorer

and Set variables with properties to set the UI if it’s different between explorers

And then create some type of Factory Pattern to create new Explorers and set their properties programmatically or get them from resources. You can label each one with a tag “explorer” and find all of them with get_tree().get_nodes_in_group(“explorer”).

Personally, I like to create one class where I define what the object/character would do, and a resource script with the data. From there, I create all the resources with specific data that I would like to set if I don’t want them to be random. I put those resources in an array in the factory (the factory instantiates the class and sets the properties of the class by looking at the resource). This way, the factory can create them automatically, and then you can set some type of index to know which explorers you have already created.

crossbito | 2023-05-29 21:02

Ok, thank you for you advice.

For now I have 2 explorers which have the exact same properties but their number (and color). I have one script “Explorer.gd” which is used by both of the explorers. It contains the movement, the pathfinding and the animation.

On the other hand I have a 2D UI which contains TextureRect and TextureButtons. The 2D UI export a boolean “isSelected” with the number of each TextureButtons.

Both Explorers and 2D UI are attached to a 2D node “world” which is used to set true or false to the isSelected boolean, and to change the UI dark or white accordingly.

Do you think in my case that it is revelant to use class for explorers and texturebuttons ?

Thank you @crossbito

Neestrid | 2023-05-30 09:21

It depends on whether you expect these explorers to have a lot of customization. If your “explorers” are data-driven, meaning their behavior or visuals can be changed by modifying information in the explorer, then yes. If you don’t expect that in the future, then no. If the answer is yes, I would create a class where you can modify the data and create resources to store the data. The class would be responsible for changing the data. Additionally, if you use resources, it will be easier to save the data when you save the game. You only need to store the data of the resource and have the explorer load the data from the resource when you load a game.

crossbito | 2023-06-04 05:31

:bust_in_silhouette: Reply From: Neestrid

I found a solution, first create Dictionary that contain start of the path, then add an index to it. Once done, convert every Dictionaries to Lists :

#Variables that contain path, need to be converted to List to work
@onready var WhiteUI_Dictonary = {}
@onready var Portrait_Dictonary = {}
@onready var Explorer_Dictonary = {}

#Variables that are usable to replace $Path/To/Something00
var WhiteUI_List = []
var Portrait_List = []
var Explorer_List = []

var i : int = 0
# Called when the node enters the scene tree for the first time.
func _ready():
	#Load every useful path
	for i in range(MAX_EXPLORER):
		var Index = str(i).pad_zeros(2)
		var pathToExplorerWhiteUI = "CanvasLayer/ExplorerList/ExplorerWhiteUI" + Index
		var pathToExplorerPortrait = "CanvasLayer/ExplorerList/Portrait" + Index
		var pathToExplorer = "Explorer" + Index
		
		var dynamic_WhiteUI = get_node(pathToExplorerWhiteUI)
		var dynamic_Portrait = get_node(pathToExplorerPortrait)
		var dynamic_Explorer = get_node(pathToExplorer)
		
		WhiteUI_Dictonary[pathToExplorerWhiteUI] = dynamic_WhiteUI
		Portrait_Dictonary[pathToExplorerPortrait] = dynamic_Portrait
		Explorer_Dictonary[pathToExplorer] = dynamic_Explorer
		
	#Convert Dictionnary to Path
	for value in WhiteUI_Dictonary.values():
		WhiteUI_List.append(value)
	
	for value in Portrait_Dictonary.values():
		Portrait_List.append(value)
	
	for value in Explorer_Dictonary.values():
		Explorer_List.append(value)

However it seems like there is a better alternative, I am begining to code games so check the comments, if you are interested.

:bust_in_silhouette: Reply From: godot_dev_

You could also organize your scene to iterate over 3 parent nodes that store the ExploreWhiteUI, Portrait, and PathToExplorer nodes, respectively. With the scene tree organized as follows:

CanvasLayer

ExplorerList

ExplorerListPortraits

ExplorerPortrait0
ExplorerPortrait1

ExplorerWhiteUIs

ExplorerWhiteUI0
ExplorerWhiteUI1

ExplorerPaths

ExplorerPath0
ExplorerPath1

You could just iterate over each children and populate the 3 lists as follows
var whiteUIs =
var portraits =
var explorerPaths =

func _ready():
    for c in $"CanvasLayer/ExplorerList/ExplorerListPortraits".get_children():
        portraits.append(c)
    for c in $"CanvasLayer/ExplorerList/ExplorerWhiteUIs".get_children():
        whiteUIs.append(c)
    for c in $"CanvasLayer/ExplorerList/ExplorerPaths".get_children():
        explorerPaths.append(c)

Hello,

I get this error when testing : Parser Error: Unable to iterate on object of type “Node”.

Neestrid | 2023-05-30 14:27

Sorry, forgot to add the get_children call.

Edited the answer

godot_dev_ | 2023-05-30 18:39