godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.05k stars 21.18k forks source link

Button Group breaks inheritance if the scene is opened in the editor (without changing anything) #86876

Open inhalt120g opened 10 months ago

inhalt120g commented 10 months ago

Tested versions

v4.2.1.stable.official [b09f793f5]

System information

Godot v4.2.1.stable - macOS 14.2.1 - GLES3 (Compatibility) - Apple M1 - Apple M1 (8 Threads)

Issue description

I assigned certain buttons to a button group. It works great until the moment I open the scene where the buttons are placed, after which a setting gets reset and inheritance gets broken.

Steps to reproduce

Open the attached project in Godot (don't click on any scenes!). Start it (click the launch button in the upper right corner) and watch the console. The printout will tell you which 3 buttons belong to a button group.

Close the project (press Esc) and back in the IDE, and open the "level 01" scene. Don't change anything in the scene! Launch the project again. Now the console log will show that no buttons belong to the group despite nothing actually changing from the first time the project was launched.

I tried everything I can think of, resaving the button group, making it unique, removing the "menu" from the base scene and readding it, remaking the whole setup from scratch, experimenting by making the button group local or not… It just loses the buttons from the group no matter what.

Minimal reproduction project (MRP)

engage button group changes settings.zip

inhalt120g commented 10 months ago

The way to make it work again is to reset the button group of the menu (in the Level 01" scene, click on the Menu and then in the inspector click on the circular arow next to the "bGroup" property on top). And this has to be done every time the scene is opened, which is very impractical.

zemiguel20 commented 10 months ago

I just arrived here because I was having a similar issue, trying to group instances of my custom Button scene (basically a button with animations). I tested your example and took note of the various cases.

I was taking notes as I did the tests, so it might be a little bit confusing to read, I apologize.

  1. "Menu" scene with one Control (script prints ButtonGroup list on ready) and 3 Buttons, all 4 of them referencing the "bGroup" ButtonGroup resource. Running "Menu" in isolation always works fine, that is, Control prints a list with 3 buttons and only one of the buttons can be selected at a time.

  2. Created a new scene "NewTest" with a Control node and an instance of "Menu". In "NewTest", the Menu instance appears to have a reference to a local instance of ButtonGroup (instead of "bGroup") and reset icon appears next to it. Ran "NewTest" and it worked fine. Pressing the reset button on the Menu instance makes the reference "bGroup" appear back. Switched, in the scenes bar, to the "Menu" scene tab, and then back again to "NewTest" tab. The Menu instance shows again the local ButtonGroup instance with the reset icon. Running "NewTest" still works fine.

  3. Created an inherited scene version of "Menu", "Menu_INH". The Control and the 3 buttons all reference the local instance with reset icon, instead of "bGroup". Running "Menu_INH" works fine. Similar to case 2, reseting the 4 references back to "bGroup" and switching tabs to "Menu" and back to "Menu_INH" makes the references in "Menu_INH" appear as local instances with the reset icon. Running "Menu_INH" still works fine.

  4. Now, I tried only resetting the reference in Control back to "bGroup". Running "Menu_INH", the Control prints an empty array, but only one button can stay selected, so the buttons still seem to be grouped. Switching tabs keeps the same result, even tho Control is back to having a local reference. Probably "bGroup" was replaced by a new instance, while the 3 buttons kept the one generated in case 3.

  5. Reset all 4 references as in case 3. Now similar to case 4, I reset the reference in the Control, but also Button1. Running "Menu_INH", the Control prints an array containing only Button1. Button1 is no longer grouped with the other two buttons, as it can stay selected at the same time as either of them. The other two buttons are still grouped together. Switching tabs keeps the same result, so it seems Control and Button1 share the new instance.

  6. Reset all 4 references as in case 3. Now I reset the reference in Control and Button1 separately. This is, reset Control and switch tabs, then reset Button1 and switch tabs. Running "Menu_INH", the printed array is empty, and Button1 isn't grouped with the other two buttons. Seems that as the resets were done separately, they have each a different instance.

  7. In the original "Menu" scene, turn all 4 references to null. Then in "Menu_INH" set the references to "bGroup". Now, if I switch to the "Menu" tab and back to "Menu_INH", the references are still "bGroup", and runs totally fine. In the "Menu" scene, I set the Control reference to "bGroup", switch back to "Menu_INH" and "bGroup" is still there, but this time running gives an empty array... I switch tabs again and now the Control has the local instance. If I reset the Control reference back to "bGroup", while the other buttons are still grouped also in "bGroup", running gives an empty array (?????).

  8. Finally, going back to case 1. Now I created a separate scene containing only a button, "New_Button", added it to Menu, and set it's reference also to "bGroup". Running "Menu" outputs only the same 3 buttons, and New_Button is not grouped with them.

Seems like for any scene containing references to a ButtonGroup resource, when they are instantiated by any parent scene, the parent replaces the references by a new instance? I don't know much about the core of the engine to have a clue about why this could be happening, but maybe this might help someone with experience.

inhalt120g commented 10 months ago

What made this particular file work as expected is that I made sure the button group is not set to "local to scene" and saving the button group after that.

So in the file from the first post, this means opening the Button Group (double click on it in the File System), making sure it's not set to local and saving it. The setting should look like this after the adjustment: スクリーンショット 2024-01-07 13 07 20

I'm 100 % sure I tried this yesterday too (a few times!, along with a few other things) but it didn't produce the desired result (maybe I forgot to save?). In any case here is the version of the same scene that works: engage button group changes settings.zip

zemiguel20 commented 10 months ago

Great! Thank you very much! Never noticed that property "Local to Scene". After reading its description, now the previous behavior makes sense.

The only thing I would like to understand is why this resource's default value is True, which might indicate that the planned use-cases for these resources were a bit different. Maybe I am structuring my menu in the wrong way, but to me, it seems normal to sometimes create a reusable button scene with some added effects and animations, since Themes are limited in this case.

Maybe it would be a good idea to add this as a note in the ButtonGroup docs? Something along the lines of "In case you need Nodes in different scenes to interact using the same ButtonGroup (e.g.: you are instancing your custom Button scene), make sure to set 'Local to Scene' to False, so each instance of that Button doesn't create a duplicate of this ButtonGroup".

Andrewfeng123 commented 10 months ago

I think (from messing around with the MRP) there is a bug with inherited scenes:

My guess for what is happening is:

  1. If "local to scene" is set to false true, then Y has its own copy of the button group and buttons (buttons are copied regardless of "local to scene"). But these buttons still refer to Y's button group.
  2. Pressing the circular arrow button works temporarily because it temporarily changes the button group of Y' to that of Y
zemiguel20 commented 10 months ago

I think (from messing around with the MRP) there is a bug with inherited scenes:

* say a scene `X` has an exported `bGroup: ButtonGroup` with "local to scene" set to false

* let a few buttons reference this group _in the editor_;

* let another scene `Y` instantiate `X` as a child scene;

* let scene `Y'` inherit from `Y`;

* run `Y`, you can see that its group does contain the buttons, but now run `Y'`, its group does not contain the buttons!

I could not reproduce the problem. I created a new project, running v4.2.1.stable.official [b09f793f5]. Created the scene X with some buttons and a script that just prints the button group.

extends Node

@export var group: ButtonGroup

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
    print(group.get_buttons())

scene_x

Created the scene Y containing X, and Y' inheriting Y. In both of them, X references bGroup.

scene_y_y'

Running both Y and Y' outputs an array with the 3 buttons. Just to make sure I am not rerunning the same scene, here are the Button object IDs, showing they are different instances: X outputs [Button:<Button#26742883527>, Button2:<Button#26793215182>, Button3:<Button#26843546833>], Y outputs [Button:<Button#26877101256>, Button2:<Button#26927432913>, Button3:<Button#26977764564>], and Y' outputs [Button:<Button#26994541768>, Button2:<Button#27044873427>, Button3:<Button#27095205078>]

Andrewfeng123 commented 10 months ago

Oops my bad, I meant to say with "local to scene" set to true. Anyhow, someone looking to reproduce can try with the attached project:

ngp.zip