How to do something when a Node in a certain Group is instanced?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By hexaquo

Situation:
I have 2 different visual styles in the game I’m working on, and the terrain is loaded / updated dynamically. These styles are often switched by changing a shader parameter. This shader parameter should always be up-to-date with the global style, so parts of the terrain need to react to changes, but also set the current style when first instanced.

Solution 1:
In each Node with such a shader, set the flag accordingly at the beginning and react to each style change. This results in a lot of duplicate code and is easy to forget when adding or adapting a Node with that shader.

Solution 2:
Inherit from a script which handles style switching in the shader. As far as I can tell, this is not an option because this will be done by different types of Nodes (Meshes, Particles, …)

Solution 3:
Add Nodes which switch style by changing a shader parameter to a group and update all Nodes in that group when the style changes. This works well and I find it quite clean, since individual Nodes with that shader don’t have know about styles at all. However, this only works when the style changes - if the style has changed and a Node is instanced after the style change, it doesn’t have the according style.

In Solution 1 and 2, I could resolve this by setting the initial style in the _ready function. However, I can’t find a way to do that with groups except for constantly iterating over all of them, which would be hugely inefficient.

Essentially, it’d be ideal if I could add code which is called for all Nodes in a group when they’re instanced.

Can anyone think of a way to do this (or a completely different, even better solution)?

:bust_in_silhouette: Reply From: johnygames

I am not sure I understand completely, but as far as I can tell, you could write code in the _ready() function of all nodes which checks what group any given object belongs to. Then, if an object belongs to a particular group, proceed to change its shader parameter. You can check whether an object belongs to a group using the is_in_group() method and you can retrieve all the groups an object belongs to using the get_groups() method. Every time an object is generated, call the get_groups() method on its _ready() function and if it is part of a certain group, have its parameter changed.

You could even create a dictionary of group names as keys and shader parameters as values in order to better manage your changes.

It is advisable to combine this with a set of global variables defined in a singleton. Your main loop updates the parameters in question and when an object is created, it reads from those global variables. Then it checks what group(s) said object is part of and it decides what parameters to change.

However, you may have to write this check in every node, unless you can have your objects inherit from another class or script. Insofar as I know, a script that inherits from Node will do the trick, because all it does is it checks what groups an object belongs to. That way you will not have to set a flag on every node individually.

Does this help at all?

Thanks for the response! That’s similar to what I meant in my “Solution 1”. You’re right, that would work - however, I’d really want to avoid having to write more or less the same code into many different _ready functions. (I have quite a lot of different Nodes which would need to set shader parameters). I don’t think inheritance is an option, since these Nodes are different VisualInstances - I’d need multiple inheritance to inherit from the shader-parameter-setting Node and the specific VisualInstance (MeshInstance, Particles, …).

hexaquo | 2020-03-20 12:34