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!
@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.
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’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.
@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)’).”