1
\$\begingroup\$

In my 2D platformer game, I'm trying to create a button that, when the player or a box is on top of it, opens a door of the same color. Here is the code for the button:

extends StaticBody2D

onready var is_object_on_button = false

func _on_Green_Button_Area_body_entered(body):
    is_object_on_button = true
    print("button is down")

func _on_Green_Button_Area_body_exited(body):
    is_object_on_button = false
    print("button is up")

Code for the door:

extends StaticBody2D

onready var is_object_on_button = Green_Button.is_object_on_button
onready var door_collision = $CollisionPolygon2D

func _process(delta):
    if is_object_on_button:
        door_collision.set_disabled(true)
        print("unlocked")
    else:
        door_collision.set_disabled(false)
        print("locked")

The button prints the right things at the right time, so I assume the button is working properly, but the door constantly stays (and prints) locked. How do I fix this?

Edit: After a bit of experimentation, I think that the problem is that is_object_on_button keeps returning to whatever value its assigned at the start: If I set it to true at the onready, it stays true. I do not know how to fix this, either.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ I don't know about gdscript, so this might not be relevant, but to me, onready var is_object_on_button = Green_Button.is_object_on_button sounds like you initialize a boolean when the node is ready. That's cool, but that's not a reference to the state of the object; you would probably need to do it like this onready var green_button = Green_Button and check the variable if green_button.is_object_on_button instead, assuming that the first call records a reference to the object, rather than a copy. \$\endgroup\$
    – Vaillancourt
    May 26, 2021 at 19:50
  • \$\begingroup\$ Unfortunately, this change hasn't helped, and it doesn't cause any change in behavior, as far as I can tell \$\endgroup\$
    – Anonymous
    May 26, 2021 at 21:04
  • \$\begingroup\$ Is Green_button the type of the object, or the name of an actual node? \$\endgroup\$
    – Vaillancourt
    May 26, 2021 at 23:27
  • 1
    \$\begingroup\$ In this, Green_Button is a singleton linking to the actual scene of the green button \$\endgroup\$
    – Anonymous
    May 27, 2021 at 0:24
  • 1
    \$\begingroup\$ Hmm if it's a singleton, why do you access to the Green_button variable through another variable? Why not just access the variable directly through the singleton? (if Green_Button.is_object_on_button:) \$\endgroup\$
    – Vaillancourt
    May 27, 2021 at 1:25

1 Answer 1

1
\$\begingroup\$

New Answer

The underlying reason of the problem is that the autoload (singleton) script is not the same on the scenario. When the player interacts with the instance on the scenario, the green door script interacts with the instance on autload (singleton).

There are a two solutions:

Option one: Don't use an autoload.

Now that green button has signals (as suggested in the original answer, kept for reference), you can connect them directly to the green door, or doors, in the scenario from the editor.

You would no longer need to connect those signals from code if you do it from the editor, of course.

Drawback: It can get complicated to connect all the signals for large scenarios.


Option two: Use a signal bus.

For those complicated large scenarios, there is a a common pattern in Godot: the signal bus.

To do it, you create a script and put in autoload (singleton), and that script will only defines signals. Nothing more. You would then emit those signals and connect them whenever you need them (knowing that being a singleton they are always available).

Let us say your singleton is called SignalBus (because, of course), and it has the signals "button_down" and "button_up" then in your green button code you can do this:

func _on_Green_Button_Area_body_entered(body):
    SignalBus.emit_signal("button_down")
    print("button is down")

func _on_Green_Button_Area_body_exited(body):
    SignalBus.emit_signal("button_up")
    print("button is up")

And in your green door code, you can connect to the SignalBus:

onready var door_collision = $CollisionPolygon2D

func _ready() -> void:
    SignalBus.connect("button_down", self, "_on_button_down")
    SignalBus.connect("button_up", self, "_on_button_up")

func _on_button_down():
    door_collision.set_disabled(true)
    print("unlocked")

func _on_button_up():
    door_collision.set_disabled(false)
    print("locked")

And that would be connecting all the green doors to all the green button via the signal bus.


Original Answer

This line:

onready var is_object_on_button = Green_Button.is_object_on_button

Is making a copy of the value when the Node enters the scene tree for the first time (just before _ready would run). That value never changes. The other script does not access it, nor modifies it.

Vaillancourt's advice in comments is correct, you should use Green_Button.is_object_on_button directly:

func _process(delta):
    if Green_Button.is_object_on_button:
        door_collision.set_disabled(true)
        print("unlocked")
    else:
        door_collision.set_disabled(false)
        print("locked")

You might also be interested in using signal. You can declare signals in your singleton, for example:

signal button_down
signal button_up

func _on_Green_Button_Area_body_entered(body):
    emit_signal("button_down")
    print("button is down")

func _on_Green_Button_Area_body_exited(body):
    emit_signal("button_up")
    print("button is up")

Then - given it is a singleton - you can connect to those signals anywhere from code:

onready var door_collision = $CollisionPolygon2D

func _ready() -> void:
    Green_Button.connect("button_down", self, "_on_button_down")
    Green_Button.connect("button_up", self, "_on_button_up")

func _on_button_down():
    door_collision.set_disabled(true)
    print("unlocked")

func _on_button_up():
    door_collision.set_disabled(false)
    print("locked")

See Custom signals and Connecting signals in code.

\$\endgroup\$
6
  • \$\begingroup\$ It seems like that hasn't worked either. I've gone ahead and made a public GitHub repo if anyone wants to take a crack at it: github.com/Hedluj/teleport_platformer_public \$\endgroup\$
    – Anonymous
    May 27, 2021 at 5:08
  • \$\begingroup\$ @Anonymous that is not a (complete) Godot project. I can't infer how you have your singletons setup from that alone. \$\endgroup\$
    – Theraot
    May 27, 2021 at 5:18
  • \$\begingroup\$ It should work now (I hope.) I'm relatively new to all of this stuff, sorry. \$\endgroup\$
    – Anonymous
    May 27, 2021 at 15:55
  • \$\begingroup\$ @Anonymous the green button on the scenario is not the same green button set in autoload. They are different instances. While the green door script connects to the one on autoload, you get the print messages from the one on the scenario. I'll suggest to use a signal bus, I'll expand the answer. \$\endgroup\$
    – Theraot
    May 27, 2021 at 16:02
  • \$\begingroup\$ @Anonymous answer updated. \$\endgroup\$
    – Theraot
    May 27, 2021 at 16:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .