How do you make the child of an instanced scene invisible on every instance using an export button?

4.2.2

I have a scene with a tool script that I’m instancing multiple times across different scenes, these instances have a child that I want to make visible by making an export variable with a bool set to false, I got it to work with a set function but it only makes it visible on one instance, I want to make it happen on all of them, as if I went to the original scene and made it visible there, this is for speed, this way I don’t have to open the original scene everytime I want to change this during development.
I tried using groups but it just crashes the editor, I have no idea on how to do this in a simple way.
I also have two questions about setters, the first one is that it seems as if they run on ready, just to know, this is true right?
And the second one is that unless you set the variable to the desired one, it will just reset to default, so if want to make an export variable that works like a button, one that resets to false everytime I press it, should I write this change in the set function ( variable = false ) or let it happen naturally?
Thanks!

@tool
extends Node2D

@onready var scene_thumbnail:Sprite2D = $SceneThumbnail
@export var show_thumbnail:bool = false:
	set = set_thumbnail_visibility


func set_thumbnail_visibility(trigger:bool):
	
	if not is_node_ready():
		await ready
	
	if Engine.is_editor_hint():
		
			show_thumbnail = trigger
			scene_thumbnail.visible = trigger

I think you’ll need to iterate through all the nodes. If they all happen to be children of the same node something like the following (in the set function) should work. but you’ll want to actually set the value of the boolean OUTSIDE the set func because if you set it inside the function while running a loop like this you’ll end up in an infinite loop. (that’s why this func only sets the visibility of all children, it means sometimes you may have to toggle the bool on and off to get the results you want, but I consider that reasonable given the use case.)

for child in get_parent().get_children():
		if "show_thumbnail" in child:
			if !child.is_node_ready():
				await ready
			if Engine.is_editor_hint():
				child.visible = trigger

That works, but I don’t understand how to set the boolean outside, I hope you can give me an example.
And the problem is that I would like to make them visible or invisible in all the instances, even on different scenes, this is just for the editor so I don’t mind that their visibility doesn’t change until I load the scene, but I would like them to get the reference to know if they should be visible or not from it, maybe that would be a solution.
Perhaps this is overly complex for my use and it ends up being more worth it to just go to the original scene and make it visible or invisible there.
Thank you!

I’m thinking something like this :

@export var show_thumbnail : bool = true:
	set(value):
		show_thumbnail = value
		if Engine.is_editor_hint(): set_visibilty_in_nodes_with_variable_show_thumb(value)
func set_visibilty_in_nodes_with_variable_show_thumb(trigger:bool):
	for node in get_tree().get_nodes_in_group("visibility_toggle"):
		if "show_thumbnail" in node:
			if !node.is_node_ready():
				await ready
			node.visible = trigger

func setup():
	add_to_group("visibility_toggle")

This example has you back using groups, but the example code was a bit easier to write that way, and I was having a hard time putting my hands directly on a chunk of code that would let you iterate through a node and it’s children recursively. Fair warning, i am a bit of a newbie here… so I might just be leading you astray.
Anyway, what I meant about setting “show_thumbnail” outside the function: you have your setter that is setting show thumb value on the current node only, then you have a function that iterates through everything and turns it on or off to match. The function doesn’t bother setting the “show_thumbnail” variable in every single instance, because it isn’t really necessary and it’d cause a infinite loop, anyway. It means the next time you want to toggle the visibility the node you select might not have the boolean set to the same state as it’s actually visibility… but you could just click it on and off (or vice versa) to get it to the correct state.

Can you show the code using groups that make the editor crash? That should not happen and can be a engine bug (and should be reported)

That works fine but it still only changes the visibility of the nodes of the current scene, the ideal scenario would be that the nodes on other scenes also changed their visibility, as I said, I don’t need this to happen before I open the scene, it can just happen on ready() because this code will not run in the game and this is just a function for testing more quickly.
I also added true in the add_to_group so they persist.

I edited the code a little bit:

@export var show_thumbnail : bool = false:
	set(value):
		show_thumbnail = value
		if Engine.is_editor_hint(): set_visibilty_in_nodes_with_variable_show_thumb(value)

func setup():
	
	add_to_group("visibility_toggle", true)

func set_visibilty_in_nodes_with_variable_show_thumb(trigger:bool):
	
	if not is_node_ready():
		await ready
	
	for node in get_tree().get_nodes_in_group("visibility_toggle"):

		node.get_node("SceneThumbnail").visible = trigger

I deleted that part of the code and to be honest I can’t remember how I did it, I think I also used persisting groups and for loop.

It probably had something to do with this, maybe I used the for loop to change the variable with a set in each node and that made an infinite loop.

I’m thinking that maybe adding a resource to the scene could work, then you would have each node check for the visibility on the resource, and as the resource is shared on all of them that could work.

The resource idea is really good. I’m constantly fighting the shared resource feature, it’d be nice if it worked in you favor in this instance!

I have made a Resource that looks like this:

@tool
extends Resource
class_name ThumbnailVisibilityRes

signal thumbnail_visibility_changed

@export var thumbnail_visible:bool = false:
	set(trigger):
		
		thumbnail_visible = trigger
		thumbnail_visibility_changed.emit()
		

The other script looks like this:

@tool
extends Node2D

@onready var scene_thumbnail:Sprite2D = $SceneThumbnail
@export var thumbnail_res: ThumbnailVisibilityRes

func set_show_thumbnail():
		
		if not Engine.is_editor_hint(): return
		
		if not is_node_ready():
			await ready
			
		scene_thumbnail.visible = thumbnail_res.thumbnail_visible
		
		if scene_thumbnail.visible == false: return
			
		load_thumbnail()

func load_thumbnail():
	
	if (not ResourceLoader.exists(next_scene_path) and
	not ResourceLoader.exists(next_scene_path.get_base_dir() + "/thumbnail.png")):
		
		scene_thumbnail.texture = load("res://Rooms/error_thumbnail.jpg")
		print(name + " thumbnail couldn't load")
		return
		
	else:
		
		scene_thumbnail.texture = load(next_scene_path.get_base_dir() + "/thumbnail.png")
		print(name + " thumbnail loaded")

func _ready():
	
	if Engine.is_editor_hint():
		thumbnail_res.thumbnail_visibility_changed.connect(set_show_thumbnail)
		set_show_thumbnail()

When I change the variable of the resource and reload the scene it works, so it works on ready, but I cannot connect the signal, it just says “Invalid get index ‘thumbnail_visibility_changed’ (on base: ‘Resource (ThumbnailVisibilityRes)’).”

I searched online but cannot find anything.

I have also realized that the set of the Resource doesn’t work, might be because of what it says here, in the “Getting notified when resources change” Running code in the editor — Godot Engine (stable) documentation in English

But that is also a problem and I cannot get it to work.

Here is the solution:

MovementPoint Script:

@tool
extends Node2D

@onready var scene_thumbnail:Sprite2D = $SceneThumbnail
@export var thumbnail_res: ThumbnailVisibilityRes:
	set(resource):
			
		thumbnail_res = resource
		
		if not Engine.is_editor_hint(): return
		
		resource.changed.connect(set_show_thumbnail)

func set_show_thumbnail(): #EDITOR ONLY
		
		if not Engine.is_editor_hint(): return
		
		if not is_node_ready():
			await ready
			
		scene_thumbnail.visible = thumbnail_res.thumbnail_visible
		
		if scene_thumbnail.visible == false: return
			
		load_thumbnail()
		

func load_thumbnail(): #EDITOR ONLY
	
	if (not ResourceLoader.exists(next_scene_path) and
	not ResourceLoader.exists(next_scene_path.get_base_dir() + "/thumbnail.png")):
		
		scene_thumbnail.texture = load("res://Rooms/error_thumbnail.jpg")
		print(name + " thumbnail couldn't load")
		return
		
	else:
		
		scene_thumbnail.texture = load(next_scene_path.get_base_dir() + "/thumbnail.png")
		print(name + " thumbnail loaded")

func _ready():

	if Engine.is_editor_hint():
			
		set_show_thumbnail()

And the Resource:

@tool
extends Resource
class_name ThumbnailVisibilityRes

@export var thumbnail_visible:bool = false:
	set(trigger):
		
		thumbnail_visible = trigger
		changed.emit()
		

With this you can acces the resource exported variable on any instance and it will control the visibility of the children you choosed on all of them.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.