-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exported (non-static) Arrays are not duplicated when instancing. #16478
Comments
This is the expected behavior according to the doc. Though I don't know the reason for that. |
Ahh, forgot about that bit of the doc. Still think it's backwards and could be improved, so I'll leave this open for discussion. |
Yeah, there may be a good reason for it, but I agree it's definitely surprising. I wonder if it would be possible to find more use for the |
I would agree that this behavior is something that should be reserved for static variables. Although the current behavior is documented, it runs contrary to what's expected by most people, and how it would function in any other OO language I can think of. |
I have to agree with this. I understand, in a general sense, why this occurs (Arrays are a standard datatype, not a Resource, and are handled differently by the engine), but it's incredibly unintuitive and makes exported arrays have very limited utility. The particular example where I ran into this issue is a breakout clone; Bricks have a "layers" array which stores the textures for each level of brick as it gets hit (red -> yellow -> green -> purple -> blue -> destroyed). I have two sets of brick sprites (regular and glossy), and intended to have two versions of the brick scene, one with the regular version and one with the glossy version, so as that I could swap the scenes if I decided I preferred one or the other. It would seem like a tidy solution to this issue would be to create a Resource wrapper for Arrays, allowing you to save a |
Additionally, and ancillary to this, when instancing a node in the editor with an exported array on it, the array is not duplicated, leading changes to the array on one (child) node to be applied across all instances and even the original scene. This is an unacceptable behavior, for very obvious reasons. |
I can't see what exactly is your point because it's just an expected behavior in OOP. You can try to reproduce it using Python. You can "avoid" this behavior initializing the array in the init/ready method. In the extends Node
export(Array) var test
func _ready():
if test == null: # if the array is "empty" in the inspector it will be kept as null
test = []
test.append("test %s" % self)
print(test) However, I think it's an inconsistency in gdscript implementation because both |
I just tested @williamd1k0's method and it does indeed work. Explicitly constructing the array in the I have the following
|
Likely will be still unsolved after #17382, but that PR might be a step towards fixing it. |
In 2.x the expected behaviour addressed here, was the actual behaviour. Unfortunately I opened a duplicate of this, but take a look #17507 |
You are correct that this is an expected behavior in Python, but that's because variables declared with that syntax reside in the class, not the instance, and are initialized at declaration time. What you describe is the realm of static member variables in almost all OO languages (C++, C#, D, etc.), which brings me to my next point; In GDScript, static member variables are explicitly disallowed:
In GDScript, the correct behavior is that all variables are instance-local and should be initialized upon initialization of the script (i.e. just before the
If it does what I think it does, it should fix half the problem. The ideal solution (AFAIK) is to make instances have a copy-on-write property in the editor, and otherwise duplicate the value at runtime. This will allow changes to the parent scene's copy to properly propagate, while allowing every instance their own copy. |
This! I can't see why specifically array should work differently from everything else. All other exported variables and node specific properties (Size, Position and so on) are instance-local! And again, this behaviour has changed since 2.x, what is the logic behind this change? |
Well, the array variable is an instance-local reference to a shared array, so it's still technically instance-local |
Still valid in 3.2.3 and the current |
This design decision is just confusing. Why is every variable local except of arrays? Does not make any sense. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This is fixed in 4.0, but still valid in 3.x. |
If this was fixed in 4.0, it seems there was a regression at some point: extends Node
@export var array: Array[String]
func _ready():
array.append(get_name())
await get_tree().process_frame
print("array in %s: " % get_name(), array)
Full project: ArrayRegression.zip If intentional, godotengine/godot-docs#5640 should be extended to 4.X docs as well. Edit: the issue also happens in 4.2 dev 5 |
Can confirm in 4.1.3. even while being documented earlier this behavior is a huge gotcha that feels out of place compared to how a user would expect a variable to behave. Also I'd suggest updating the docs with a warning about this until it's fixed because as of now there is no mention of it which only adds to the confusion |
For comparison (on 3.5.3), this behavior for exported default array values is not the same as function default array arguments, which are a pretty similar idea. I agree with most in this thread that export defaults should behave the same way as regular var defaults and add function argument defaults to the list. I bring this up because of the comparison to Python back when this issue was first discussed. In Python (at least the version I remember), using a mutable value like func test_array_default(foo := []):
foo.append(randi())
print(foo)
func _ready():
for i in 10:
test_array_default()
for i in 10:
test_array_default([i]) ...it works intuitively. Example output showing that the default arg array is new every time, just like explicitly passing a new array:
It only accumulates values if you pass the same array every time (not shown here) instead of a new one -- and the default is new each time. |
Still valid in 4.3 RC3 |
Godot version: Godot 3.0
OS/device including version: Solus Linux / X11
Issue description: When exporting an array variable in GDScript, the array is not duplicated upon instancing of the node. This behavior conflicts with all other properties, and is contrary to the OOP model Godot uses. The array is not static (or class-wide), but belongs to the instance, and so every instance's copy should be unique. Currently, unless manually duplicated, modifications to the array affect all instances of the class.
This issue may be present with Dictionaries as well, I have not tested them.
Steps to reproduce: Write this script:
Save a node with the script a as scene, instance two copies at runtime, and add them to the tree.
Expected result:
Result:
Minimal reproduction project: See above.
The text was updated successfully, but these errors were encountered: