How to enable/disable a button with a signal from another scene

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Cimiur

Hi everyone,

I am a newbie and I have spent the last 8ish hours trying to figure out how to do this.
I also couldn’t find the answer browsing the web.

Basically, what I would like to do is enable/disable a button every time that the player enters or leaves an area. The thing is that the button and the area are in two different scenes.

What I have done is the following:

  • I created a global singleton script with the button node as variable

  • in the script of the button node I put:

Global.slotButton = self
  • and in the script of the area scene I connected the signal:
_on_Area2D_body_entered(_body):
Global.slotButton.disabled = false  (because I set it to start on disabled) 

 _on_Area2D_body_exited(_body):
Global.slotButton.disabled = true 

I have also tried to put a function in the button node like:

func test():
disabled =! disabled

and then call it on the signal callback. and a bunch of similar variations like set_disabled() etc., but nothing works, the button stays in the same status that it starts with.

The connection works because I tried with a print() in the test function in the button node and it prints every time that the body enters or exits.

I have also checked if my syntax was correct by connecting a function to a keyboard input to disable and enable the button and this one works.

There is definitely something that I am missing but my brain feels a bit like a mush atm :).

Help please?

:bust_in_silhouette: Reply From: AaronWizard

When you say that the button and the area are in two different scenes, where do they exist in your game’s main scene?

I presume the node structure of your game’s main scene looks like this:

  • Main scene
  • Scene with button
  • Scene with area

If this is the case, what you should do is attach a script to the scene with the area. Give this scene’s script a signal; I will call it “area_entered” as an example. Connect the area’s area_entered signal to a method in this scene’s script, where you emit the script’s “area_entered” signal.

# SceneWIthArea.tscn
extends Node

signal area_entered

func _on_Area2D_area_entered(_area: Area2D) -> void:
    emit_signal("area_entered")

Next, attach a script to the main scene. With the scene with the area, connect its “area_entered” signal to a method in the main scene. In this method you can access the scene with the button, where you’d disable the button.

# Main.tscn
extends Node

onready var scene_with_button = $SceneWithButton as Node

func _on_SceneWithArea_area_entered() -> void:
    var button := scene_with_button.get_node("Button") as Button
    button.disabled = not button.disabled

Does this accurately address your code and the problem you are facing?

Thanks for your reply.

So, the thing is that the structure is a bit more complicated and I have got many of the areas that I want to use for that.

The situation is more like:

Scene → instanced scene → several instanced scenes → several instanced area2d scenes for each of the previous scenes

Scene → instanced scene → instanced scene → instanced scene → several instanced button scenes

So I can’t really do that for all of them in the main game scene.

That is why I wanted to do find a way to connect the “reference” script of both button scenes and area scenes through a singleton

And I still can’t figure out why what I tried doesn’t work.

Thanks though :).

Cimiur | 2021-03-06 23:12