I have a Fighter instance, which has a float Range property. It indicates the range of fighter’s weapon, and also the target detecting range.
Then there are two child nodes that takes this parameter: Weapon : Node who creates bullets and assign Rangeto the bullet; and TargetDetector : Area2D that search for targets. I want it to be modified so I can see the circle range of TargetDetector Area2D.
What’s the proper way to make Weapon.Range, Fighter.Range and TargetDetector.Range
all equal? I have to assign them manually, which is odd to me…
I tried the approach using getter & setter, sets child properties in setter. The problem gets to the initialization order: if the property is assigned before exported child nodes, they will be unable to get assigned and a null reference exception would be thrown. If I ignore the exception, then values would not get synced.
When I assign values in the editor it won’t get synced instantly to child nodes, until I run the game or create a new instance of it. for [Tool] _Ready runs only once as well, still not syncing them.
Simply for recording a Range variable it is enough, but I want other code to make a bunch of properties always (I want it always…) the same in multiple binded nodes, regardless of time they get synced.
So the first line, since TargetDetector is not assigned, it will throw exception.
Since it throw exception, TargetDetector will finally get a value of null.
I’m confused, did you mean I need to assign TargetDetector in constructor? But it’s an Export variable recorded in the .tscn file, how do I know the exact object in constructor?
Oh you may have misunderstood, the code instance.TargetDetector = ... is the engine code that I suppose from where I encountered null-reference exceptions.
The code seems to be excuted when I double-click Fighter’s .tscn file and it open up in editor, then the exception comes in the output. It’s not defined by me.
So the only valid re-assign position is _OnReady(), where the engine code finish execution and come to my own code.
To synchornize multiple properties so that when I modify the root/source property, others gets to the right value immediately.
In this post, Fighter.Range is the source. TargetDetector.Range and Weapon.Range, as they both are child node of Fighter, should be always equal to Fighter.Range. By the word always I mean it must be effective in the godot editor, when I change Fighter’s Range property in inspector, I shall see the TargetDetector : Area2D change its collsion shape size in the 2D view.
If node is not ready then the children won’t exist in the tree so their properties can’t be set. The way to do is via Fighter.Range setter. You can call IsNodeReady() in the setter and exit early if it returns false. Otherwise assign the value to dependent nodes. For this to work in the editor the script must be a tool script. If the children properties have setters, their scripts must be tools as well in order for everything to run properly in the editor.
You can force the setter execution in _Ready() if needed by doing Fighter.Range = Fighter.Range
It sounds like you need to instantiate the TargetDetector and add it to the scene tree early, like in a constructor, and that TargetDetector.Range should be a reference that gets set to Fighter.Range, or just some reference to the Fighter to pull variables from it.
imo this sounds like a broader architectural problem, but Ive never used cs in godot tho so idk.
If its suitable, you could just make a @tool node+gdscript that updates other node’s properties on _process() to keep your fighter from being a tool but getting the updates you want. that’s a quick and dirty way to do it assuming the value doesn’t change at runtime and you exclude the tool from builds.