Hello, I tried this method after the “var new_element = $BG.duplicate(true)” line. Although “new_element.print_tree_pretty()” shows what it’s supposed to show, the error still exists, and it’s specifically in the line with “var new_element = $BG.duplicate(true)”.
That implies _Button_3 is not a valid instance somehow. Is the thing you’re duplicating maybe not fully created yet? As in, some of its children are not yet created?
Maybe before calling duplicate, recursively walk over the thing you’re duplicating and call is_valid_instance() on all the children? It would only be a debug/testing thing, but if any of those calls came back false it would be diagnostic.
In general, I’ve been thinking a lot about how to fix the error, but I don’t understand anything. Can someone figure out the code and help me?
All script code:
extends Control
var army_elements := []
var close_requested := false
var on_for = false
func _process(delta: float) -> void:
if Global.army.size() == 1:
$BG/One.visible = true
$BG/Many.visible = false
$BG/Name.text = str(Global.army[0].editor_description)
if Global.army.size() > 1 and !on_for:
on_for = true
$BG/Name.text = "Армии"
$BG/One.visible = false
$BG/Many.visible = true
for i in Global.army.size():
var container = $BG/Many/ScrollContainer/VBoxContainer
for child in container.get_children():
if child.name != "ArmName" and child.name != "Varm":
child.queue_free()
var new_element = $BG/Many/ScrollContainer/VBoxContainer/ArmName.duplicate()
$BG/Many/ScrollContainer/VBoxContainer.add_child(new_element)
new_element.text = Global.army[i].editor_description
new_element.visible = true
var count = 0
for child in container.get_children():
if new_element.text == Global.army[i].editor_description:
count += 1
if count >= 2 and child.name != "ArmName" and child.name != "Varm":
child.queue_free()
on_for = false
army_elements = army_elements.filter(func(element):
return element != null and !str(element).begins_with("<Freed Object>")
)
if close_requested:
close_requested = false
handle_close_operation()
else:
update_army_display()
func handle_close_operation() -> void:
for i in range(army_elements.size() - 1, -1, -1):
var element = army_elements[i]
var child = element.get_child(0) if element else null
for unit in $ARMS.get_children():
if unit is CharacterBody3D and child and str(unit) == child.editor_description:
if Global.army.has(unit):
Global.army.erase(unit)
unit.reparent(self)
element.queue_free()
army_elements.remove_at(i)
break
func update_army_display() -> void:
for unit in Global.army:
if !is_unit_displayed(unit):
add_unit_display(unit)
func is_unit_displayed(unit: CharacterBody3D) -> bool:
for element in army_elements:
if element and element.get_child(0).editor_description == str(unit):
return true
return false
func add_unit_display(unit: CharacterBody3D) -> void:
var new_element = $BG.duplicate(true)
new_element.print_tree_pretty()
if Global.army.size() >= 2:
new_element.get_node("Many/ScrollContainer/VBoxContainer/_Label_3").name = "Label@3"
new_element.get_node("Many/ScrollContainer/VBoxContainer/_Label_4").name = "Label@4"
add_child(new_element)
#get_child(2).get_child(0).get_child(0).get_child(2).get_child(0)
new_element.get_child(0).editor_description = str(unit)
new_element.top_level = true
new_element.visible = true
army_elements.append(new_element)
unit.reparent($ARMS)
new_element.print_tree_pretty()
func _on_clouse_pressed() -> void:
close_requested = true
func _on_ubr_pressed() -> void:
print(123)
Why are you calling duplicate(true)? duplicate() takes an integer flags argument to tell which parts to clone, and by default is 15 (that is, binary 1111, all flags set). I’m not sure what true turns into when cast this way, but if it isn’t basically all bits set then you’re turning off some of the duplication.
duplicate (true) I specify it to be copied better (that’s what it says on the Internet), and on_for prevents new loops from being created forever, in _procces
editor_description я использую как хранилище для имени (не ноды, а просто имени)
Copied… better? I’m not sure I understand. duplicate() takes an integer argument, with the default argument being 15. Each bit in that (there are four, all set in 15) controls what is and isn’t duplicated:
DuplicateFlags DUPLICATE_SIGNALS = 1
Duplicate the node's signal connections.
DuplicateFlags DUPLICATE_GROUPS = 2
Duplicate the node's groups.
DuplicateFlags DUPLICATE_SCRIPTS = 4
Duplicate the node's script (also overriding the duplicated children's scripts, if combined with DUPLICATE_USE_INSTANTIATION).
DuplicateFlags DUPLICATE_USE_INSTANTIATION = 8
Duplicate using PackedScene.instantiate(). If the node comes from a scene saved on disk, reuses PackedScene.instantiate() as the base for the duplicated node and its children.
That’s from the Node docs. I don’t see why you wouldn’t want all of those set, and calling with true may not do that.
With on_for, your code looks like this:
var on_for = false
func _process(delta: float) -> void:
[...]
if Global.army_size() > 1 and !on_for:
on_for = true
[stuff]
on_for = false
I don’t see how that’s going to do anything useful. Outside of that if block, on_for appears to always be false. It’s a local var, so it’s not going to affect other nodes.
Apologies if google translate made a hash of your comment about editor_description:
“I use it as a storage for the name (not the node, just the name)”
I’d advise against this; I’m not sure if a field like that would be stripped out in release builds…
I didn’t quite understand what you meant by (on_for), but without it, the code doesn’t work correctly.
And in the code, neither dublicate or duplicate(true) change anything. The documentation turns out to be very hard to read since it either doesn’t fully translate or translates incorrectly.
DeepSeek helps me with these questions (ducumentation).
Example for Editor_description:
editor_description = "Army of liberty"
or editor_description = "My Army"
What I mean about on_for is, I don’t see what it could possibly be doing. It will always be false when it gets tested, so the !on_for test will always evaluate to true.
duplicate takes a bitflag as argument, that’s what hexgrid was trying to tell you, by setting it to true, you’re stripping it from some of the default duplication flags.
Assuming true == 1, that means it would just duplicate the Node’s signals.
See Node — Godot Engine (stable) documentation in English
Hope this makes it clearer,
Cheers !