Search code examples
unity-game-engineui-toolkit

Assign UIElements button.clickable, using Visual Scripting Graph


I am trying to use Unity3D's UIToolkit with Visual Scripting Graph...

Typically, I can Query for the proper element, and then add the necessary function to the callback... However, as I am new to Visual Scripting, I am not sure how to get to this point. I've got the 'clickable' object of the button isolated, but I'm not sure how to assign the follow-up execution in the graph.

Usually in the code, I would do something like

clickable.clicked += ExampleFunction();

What I am messing up in the graph, is how to access the '.clicked' part. I can get the proper button element, and I can isolate its clickable property, but I can't figure out how to assign some kind of functionality to react to the button getting clicked.

I could use a custom node to make this work, but I am looking for a way to do this with built-in nodes, if possible.


Solution

  • Alright... I had to write a custom node, but I figured this out. Here is the graph for the solution.

    Graph example

    You have to grab the UIDocument from whichever GameObject it is attached to... You then need to get the Root Visual Element, do NOT clone or instantiate it. You then need to Query for the desired button, using the name you gave it in the UI Builder. It is easier if you use the U Query Extensions nodes... After that, I just made a custom node to subscribe the functionality. I am not familiar of any nodes that do this.

    Here is the 'Subscribe Start Result' node code:

    using Unity.VisualScripting;
    using UnityEngine;
    using UnityEngine.UIElements;
    
    public class SubscribeStartResult : Unit
    {
        [DoNotSerialize]
        [PortLabelHidden]
        public ControlInput inputTrigger;
    
        [DoNotSerialize]
        [PortLabelHidden]
        public ValueInput element;
    
        protected override void Definition()
        {
            element = ValueInput<Button>("element");
        
            inputTrigger = ControlInput("inputTrigger", (flow) => 
            {
                flow.GetValue<Button>(element).clicked += () => 
                { 
                    Debug.Log("Button clicked"); 
                };
                return null;
            });
        }
    }
    

    With this setup, clicking the 'Start Button' in play-mode will log "Button clicked" in the Console.

    The 'return null;' line is an artifact of the lambda. It is required to continue the control flow in the event this node has a follow-up... Otherwise, this combination of nodes and code allow you to assign callbacks for the UI Builder elements, using the Visual Scripting Graph.