Looking to understand how to best assign scripts to game objects - C# and VS

Hello everyone.

Sorry, kind of a long post because I am trying to be detailed and outline what I am looking to learn.

I have been able to use Visual Scripting to make on screen UI and Physical buttons, that interact with Events and Triggers within Script Machines. Using a ‘PlayerObject’ with a ‘PlayerScript’, all the basics like jumping via keyboard input, or opening a UI menu and changing volume with mouse clicks, etc. No issues.

I start having conceptual and understanding problems, when multiple objects and multiple scripts are involved.

I am now trying to combine a C# script with my existing Visual Scripting environment. A prior post here showed me how to generate the nodes I need, and I can bring up the C# script Public Void Function nodes in Visual scripting. But I keep getting these errors like: “Object Reference not set to an instance of an object” when I try to implement them into the flow.

Previously, in my own experience with just Visual Scripting alone, it was just about adding the Script Machine component to the Player game object. In this specific example, I am trying to learn the right way to use C# script nodes, assigned properly to the right objects, to do things in the VS environment - as well as proper object/script assignment and ‘This’ usage.

The current C# code spawns an inventory menu, which has an ‘X’ button to close the window. The X button, in C# code, triggers the Set Object Active to false (hiding the menu), but also triggers an update to translate which inventory items you clicked on - to then show up in a separate UI element (imagine cards you pick for a card game from one UI, and them then being in your hand which is another UI. The main pool of cards is the main inventory window - closing it, updates your own hand of cards on screen in another UI).

As it is today - it works 100% fine with just the mouse. The C# script loads, interacts, functions just fine when I use the moues to open and then click the X to close. It looks like everything flows and updates. So as learning, I am trying to test it out and make the keyboard fire an action to open/close the inventory through Visual Scripting and my existing Script Machine.

As a test, using this to take keyboard input to toggle the menu visibility. ActivationObject is on the ‘Inventory’ game object under the canvas. inventoryVisible is a bool to help track the toggle status. If it is visible, and thus is closed, the Script Machine should fire the ‘UpdatePanel’ Public Void Function from the C# script, to update the other UI element.

Which game objects should have the PlayerScript assigned (which is where this screenshot currently lives)? I have added the PlayerScript to the Inventory Object, the ‘close button’ object, several other objects. I have had the Inventory Visible bool be a scene and an object variable.

What do I replace ‘this’ with here, in the red box? If it isn’t the inventory object, the player object, etc. I don’t know what to input. In my brain, there is a player that moves around, and a UI. The UI can have a trigger, that would move the player object X distance or add hit points, etc. Can everything life on one object?

I can’t figure out how to ask the right questions to get help with this.

Does any of this make sense, and can anyone help point me in the right direction?

Thanks all.

Edit:
This is the full function snippet:

public class SelectedPowerUpsDisplayer : MonoBehaviour
{
    public GameObject inventoryPanel;
    public ItemList itemList;
    [Header("Should be same Nr as displayed Child Slots!")]
    public int maxActivatedPowerUps = 4;
   
    List<Item> list;
    public void Start()
    {
        list = itemList.list;
        UpdatePanelSlotsForUsedItems();
    }

    /// <summary>
    /// updates the slots with the selected items from the user
    /// </summary>
    public void UpdatePanelSlotsForUsedItems()
    {
        var index = 0;
        foreach (Item item in list)
        {
            // do not take more items with you when there is no more space
            if (index >= maxActivatedPowerUps)
            {
                return;
            }
            if (!item.IsActivated())
            {
                continue;
            }

            var obj = inventoryPanel.transform.GetChild(index);
            obj.gameObject.SetActive(true);
            var slot= obj.GetComponent<InventorySlotController>();
            slot.item = item;
            slot.UpdateSelectedInfo();
            index++;
        }
        // update the rest of the free spots
        for(var i = index; i < maxActivatedPowerUps; i++)
        {
            var obj = inventoryPanel.transform.GetChild(i);
            obj.gameObject.SetActive(true);
            var slot= obj.GetComponent<InventorySlotController>();
            slot.item = null;
            slot.UpdateSelectedInfo();
        }
    }

}

It has ‘Item’ and ‘list’ and ‘item.list’, which I think are all contributing the errors I have - How am I supposed to get these to be “visible” to the Visual Script nodes/flow?

From what I understand the script unit “SelectedPowerUpsDisplayer” is nothing but a reference to the actual script’s component instance. The slot with the selection of “this” simply states that the script’s actual component is on the same Game Object as the script machine. This script unit lives in its own bubble isolated from the rest of the graph. The graph is simply calling it to perform and continuing the flow. This is only true unless the script has been written to reference the graph/script machine.

If the script works independently of the visual scripting graph then it should work without issue when reference inside the graph. Take a look at the component (this should be the “SelectedPowerUpsDisplayer” attached to a game object), and make sure the public variables are all referencing game objects in your scene.

What I believe is the solution:
Try creating a new Game Object. Name it something like “PowerUpManager”. Attach your script “SelectedPowerUpsDisplayer” as a component to it. Make sure to drag or populate the slots for the public field “inventoryPanel”. Then drag the the newly created gameobject to the graph where the “SelectedPowerUpsDisplayer” unit is and replace the slow currently referencing “this”.

Personally I have been custom re-writing my scripts as real custom nodes to have the script exist in the graph/script machine. But this does take some additional work a extra design thought.

Thanks for much Starpaq2. I’ve been trying to work on your suggestions and am still running into the same type of issues. I can’t fully understand what you are suggesting, so I tried a few different things like:

In this example, this is the C# component I added to the ‘Player’ game object, with the Inventory object and ItemList object added.
7569139--937045--upload_2021-10-13_7-26-51.png

I also created the new game object (HandManager) and added the C# SelectedPowerUpDisplayer component to it, adding it to the ‘this’ flow.
7569139--937054--upload_2021-10-13_7-53-25.png

All of my variations result in
7569139--937057--upload_2021-10-13_7-55-35.png

In the C# script itself (SelectedPowerUpDisplayer), it uses the ItemList and Item and Inventory, etc, which I can see in the component. In my misguided head, I thought I could create a node that was a visual representation of a block of C# code. Then use flow connections to ‘trigger’ that specific section of C# code.

Then it occurred to me - how do I get it to trigger all of the OTHER elements associated with that single function or block of code? It never really occurred to me that UpdatedPanelSlot was itself called by this Public Void Start. So I tried that too, to have Start call UpdatedPanelSlot. Same issue though :frowning:

List list;
public void Start()
{
list = itemList.list;
UpdatePanelSlotsForUsedItems();
}

7569139--937156--upload_2021-10-13_9-59-54.png

How is the main Selected Power Ups Displayer node in my first picture, how do they get all the ‘other stuff’ they need?

Spawning the main inventory UI does not invoke any other actions aside from Set Active, unlike the close, which then updates the second UI and sets the first UI to not active.

Maybe this example can help, try it like the the gif I attached:

7574017--938143--vs_referencing.gif

You have a script node named ‘Web Link Button’, and then drag the Web Link Button Script component into the ‘this’ field in that visual node. When I attempt to do this (drag and drop into the ‘this’ section), the Fuzzy Finder menu appears and has the >> expand menu and offers me options. I cannot just drop the component into the node.

Like this
7577257--938848--upload_2021-10-16_9-27-40.png

When I expand the >> it then just inserts the monobehavior node, like this
7577257--938851--upload_2021-10-16_9-28-18.png

I’m pretty sure this is down to my lack of understanding about how the scripting works.

The amerature coder in me doesn’t understand how using the ‘SelectedPowerUpsDisplayer’ as a node in visual scripting - how would its flow cature the ‘list = itemList.list’ and ‘List list’ assignments. Those seem to be related to ‘Start’, which calls the desired ‘UpdatePanelSlotsForUSedItems’ function.

7577257--938854--upload_2021-10-16_9-29-25.png

I really want to fire “all of SelectedPowerUpsDisplayer” when the user triggers the event. But I think I am just firing parts of it like the Public Void UpdatedPanelSlotsForUsedItems or Start(), when I should really be doing something else instead.

Any ideas why your last drag and drop suggestion would be functioning differently for me in this case? Or why it is acting in this way?

I’ll update you if I think of any other possible solutions.

Personally a script that size I would rewrite as a graph of it’s own in unity Visual Script.

In my development since using VS I have started converting all my scripts to VS graphs. I save an incredible amount of time for debugging and reduced typos. It might seem crazy but scripting in Unity for 10 years and I’m all for Unity VS. And for the type of development I do … if there is a performance reduction, its completely negligible in the apps and products I create.

The stubborn part of me had to solve this mystery. I think I may have it.

Please take a look at your graph type as follows:
Click on your gameobject that holds the Script Machine Component.

I believe your problem is coming from the source type. In order for the references to work in the scene, you must convert the source to “Embed”.

**After you do this… my previous advice should work out.

Don’t worry because you can still keep an unaltered copy of your graph as an asset in your project directory.
Sometimes it can be hard to get your head around graphs vs. embeds.

Hopefully this works.
EDIT: CLICK ON THE CONVERT BUTTON DO NOT MANUALLY SWITCH THE DROPDOWN.
7583299--940024--upload_2021-10-18_16-19-47.png

According to the official discord as of today, they’re evaluating removing embed graphs entirely. Nothing confirmed yet, but I wouldn’t rely on them too much. If they’re removed, there likely will be some kind of conversion process though. But you already can manually convert too.

A workaround would be to use Scene or GameObject scope variables in a graph asset, which can reference components on other GameObjects in the scene same as embed graphs albeit with extra steps.

1 Like

Not to derail this thread too much, but thank your for the heads up.

I actually prefer the juggling of embed vs. graph asset. The workflow seems quick when dealing with with a unique one time scene based functions.

The only reason I find your (unconfirmed) info concerning is because the blackboard seems really terrible for managing a large quantity of variables/references. I would hope we’d get a modified blackboard for the aesthetics and user experience.

Yea, but if multiple people work on different embed graphs in the same scene, you’re in a bad situation. And if something happens with that graph, say you accidentally delete the GO that holds it, you have to roll back the whole scene asset to recover. Or a prefab asset. Lots of room for human error there with potentially dire consequences when you have to lose a bunch of level design or something akin to that just to recover a graph, and then have to get that level design back in.

Indeed, the current blackboard is pretty terrible - variables take too much space, it’s can’t be organized in groups or with headers, can’t be searched and all of it is weakly typed and weakly referenced. They do have plans for completely replacing UI/UX layer of the package though, it’ll be in line with shader graph, vfx graph, etc. eventually. All Unity graph based tools will use the same UI tech.

And they also have plans for variable improvements, making them GUID based, so at the very least they’ll be strongly referenced and hopefully also strongly typed.

And the reason why they’re considering deprecation of embed graphs is because there are significant technical issues with converting them to the new high performance runtime with lots of edge cases. Potentially insurmountable amount of edge cases.

1 Like

Hello folks.

I sincerely appreciate both of your time on this.

I’ve still not resolved this, but I also wanted to mention that I’m basically moving on from this approach. I am spending far too much time trying to adapt my thinking to someone else’s code, which was originally intended to just be a short cut anyway.

I’d rather do it the long way and learn properly, instead of trying to figure out how to use something that I may not even need or want long term. Your additional advice on the future of BB / etc, is also helpful.

Thanks again!

1 Like