-
-
Notifications
You must be signed in to change notification settings - Fork 25
Better custom visual script node API? #33
Description
In the event that visual scripting doesn't get a massive, paradigm-shifting overhaul, I'd like to leave some feedback here about the current solution, as a programmer:
In $PROPRIETARY_ENGINE, I was able to follow a pattern of writing low-level systems in $LANGUAGE, and connecting to them with higher level, custom written nodes for a more plug-and-play method of implementing high level game logic, tying events to actions without awkward inspector-based solutions, etc. I won't go into the pros/cons of this approach here.
When I tried to replicate the same workflow in Godot, I found that the custom VS node API was pretty awkward. The heavy reliance on an array-based API for mapping names/types to ports is incredibly unwieldly and slowed down iteration a lot. Code like this looks acceptable at a glance, but once you blow it out to 3, 4 ports? For most of the nodes you'll end up making? And having to keep track of what input type and name lives at what index a month down the road, spread across several different functions? Not great.
## Snippet of official API # The types of outputs per index starting from 0. func _get_output_value_port_type(idx): return TYPE_VECTOR2
(For reference, the current custom visual script node API is documented here: https://docs.godotengine.org/en/3.5/tutorials/scripting/visual_script/custom_visualscript_nodes.html)
Code speaks better than words in this case, so an example of a better API, from my perspective:
# Example of a "Can Walk In Direction" node. # Accepts directional input, outputs a boolean as well as two output flows, # If GDSCript supports custom decorators... @input_value_port("Direction") var direction_input: Vector2 @output_value_port("Can Walk") var can_walk_output: bool @output_flow_port("Can Walk") var can_walk_flow: Flow @output_flow_port("Can't Walk") var cannot_walk_flow: Flow # If no custom decorators, or a decorator-based workflow is undesirable... func _ready(): direction_input = register_input_value("Direction", TYPE_VECTOR2) can_walk_output = register_output_value("Can Walk", TYPE_BOOLEAN) # etc ... func _step(start_mode, working_mem, other_params_no_one_uses): var can_walk = Map.can_walk_in_direction_no_pathfinding(direction_input.input) can_walk_output.output = can_walk if can_walk: # Any nodes connected to the "Can Walk" flow are activated. can_walk_flow.activate() else: cannot_walk_flow.activate()