Search Unity

Simple node editor

Discussion in 'Immediate Mode GUI (IMGUI)' started by unimechanic, Jul 5, 2013.

  1. Aramilion

    Aramilion

    Joined:
    Apr 15, 2016
    Posts:
    23
    input.gif Hey! I'm struggling with a major problem for quite a while, but it was rather annoying than game breaking, so i just left it couse why spend time on it now, when i can do it later :)

    So here it is, when i have a node with an obiect field/ text etc. And i want to edit this field, I need to click on Node in order to make it focused and selected, and after that i can click on my fields. (Text field works this way, and i was ok with it) but obiect field is quite different. You have "Select" button there, and it is clickable eevn before you have this node focused. This opens a widow with object i want to select and save in this field.
    When the node was selected before i clicked the "Select" button (name was bold), everything works fine, but when i click "Select" button before this node was focused by me, window opens too, but the object i selected is not saved and nothing change! This is so annoying and i don't rly understand the input system here :)

    The gif should explain it better,
    1) I click on node to make it focused,
    2) I choose the image and it appears in node
    3) I click somewhere else to make node unfocused
    4) I click on Select Button, and choose image. (Nothing happens)
    5) I click again on Select Button (node was already focused), and can select normally.

    Hope you have an idea about what can i do to help it. :)
     
  2. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Jep, it is unfortunately a known problem, not only with object fields but in fact with all kinds of popup fields, too. It is because of the special nature of these controls: They block the input or atleast delay it (due to their priority) so the event will be received by the node one frame later. This causes the control ID of the nodes to change after the control made use of it and thus they won't match anymore.

    What most likely happens, in order:
    1. click: Control receives the event, stores control ID and opens popup for that ID
    2. after click: Node receives the event and the clicked node is pushed to the front (so it is focused). That changes the control ID of it's controls
    3. Popup window of the control is finished (user has selected something) and the control tries to apply this to the stored control ID. Because it is changed nothing will happen.

    What should happen:
    1. click: Node receives the event and the clicked node is pushed to the front (so it is focused). That changes the control ID of it's controls
    1. click: Control receives event, stores control ID and opens popup for that ID
    3. Popup window of the control is finished (user has selected something) and the control tries to apply this to the stored control ID. It is the current ID of the control and everything works fine

    In case you have a different node selected before clicking on the control of the other node it might be even worse and the window changes the control of the previous node instead of the node you're aiming for!
    All this is only an assumption, but I assure you it has been a problem for a while now. A solution would be to not change the render order of the nodes on selection change (Look into NodeEditor.cs/DrawSubCanvas).

    It really depends on the control, most controls are low priority but some like the Picker Fields (Object, Color, ...) and the popup fields (Dropdown, EnumField, ...) will cause this issue:/

    I hope you were able to follow me there, it is a bit confusing:/
     
  3. Aramilion

    Aramilion

    Joined:
    Apr 15, 2016
    Posts:
    23
    Thanks for REALLY fast response! I think i get it now, why it happens. Will see if i can fix it by the thing you have mentionned. :) Will say if it fixed my issue. I just hope i won't break anything with it and it is fixable!
     
  4. Aramilion

    Aramilion

    Joined:
    Apr 15, 2016
    Posts:
    23
    Unfortunetly it hasn't helped. Render order has to be changed because when you are dragging nodes, the one you're dragging have to be on top of others, otherwise the overlapping node will be selected and moved.
    The problem is HandleSelecting, when i comment it, i can do what i wanted, BUT i cannot move any nodes :) right, so i wollowed because it was kind of right direction.

    I've put all HandleSelecting logic after HandleFocusing, except unfocusControlsForState = state;
    And it worked like a charm! Till i ralised something. sometimes, or more like preety often, when you are moving nodes TO FAST, your mouse isn't over the node anymore before next loop where you would translate it there -> stopped dragging.
    ehh.. seems more annoying than double bunny click :)

    I have to fix it sooner or later, but for now it's all i came up with. If there is something i've broke with this solution and you're aware of it, please tell me ;p
     
  5. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Sorry our WLan Router broke because of a lightning strike, but we're up again with a replacement:)
    I tried to fix it some way some time ago but I think I came across similar problems - but since then alot in this direction has changed. Maybe I'll be able to take a look at it again but no promises:(
     
    Last edited: Jul 22, 2016
  6. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hello everyone,
    ChicK00o on GitHub has made a great example of a Dialogue system - along with a system to seperate canvases in types to only show type-specific nodes to allow for a more cleaner workflow. If you want a dialogue system, this might be a great start for you:)

    Btw, I won't be able to respond as fast as usual because I drowned my phone so I don't receive instant notifications anymore:(
     
  7. Aramilion

    Aramilion

    Joined:
    Apr 15, 2016
    Posts:
    23
    Hey! It's me again!
    I have a problem with Scriptable Obiect, Node. I have a custom public enum field, it is needed to specify transit animation between pages of content my nodes represent. I can specify the animation and when i click PLAY, everything is working as i wanted. The problem starts when i want to test it on built application. Because than enum is set to default value!!!
    I thought it was problem with enums at first, but when i changed it to Int, it's the same. :(
    It's first time i'm using non-reference variables i want to store. every other one persists... Google is silent for me about this, so i thought i'll ask here :)
    I have a list of specific type of Nodes in my monobehaviour script and i use it to go through other, connected to it nodes. I add nodes there in edit mode, while connectiong them together. I need it to have the references to other staff like components or GameObiects (which are ok and working good), and this AnimationType. I need to do it to make my buttons work and transit to other pages with content. (has to be done dynamicly)

    Here is my code executed always first.
    Code (CSharp):
    1.  
    2.     public void Play()
    3.     {
    4.         List<Node> buttonOnClickListeners = new List<Node>();
    5.         foreach (NodePage nodePage in ManagerHierarchy.Instance.pages)
    6.         {
    7.             if (nodePage.nodeTransitTo != null)
    8.             {
    9.                 buttonOnClickListeners.Add(nodePage);
    10.             }
    11.  
    12.             foreach (Node n in nodePage.nodes)
    13.             {
    14.                 if (n.nodeTransitTo != null)
    15.                 {
    16.                     buttonOnClickListeners.Add(n);
    17.                 }
    18.             }
    19.         }
    20.  
    21.         for (int i = 0; i < buttonOnClickListeners.Count; i++)
    22.         {
    23.             Node node = buttonOnClickListeners[i];
    24.             if (node == null || node.Item == null) continue;
    25.  
    26.             Button button = node.Item.GetComponent<Button>();
    27.             if (button == null)
    28.             {
    29.                 button = node.Item.AddComponent<Button>();
    30.             }
    31.             button.onClick.AddListener(() => ManagerHierarchy.Instance.SetActivePage(node.nodeTransitTo.Item, node.AnimationType));
    32.             Debug.Log("Added Listener(node, item, animation) = (" + node.name + ", " + node.Item.name + ", " + node.AnimationType + ", " + node.nodeTransitTo.name + ")");
    33.         }
    34.     }

    The log i get is right everzwhere but in AnimationType field. And once again i'll point out that everything is working in play mode, and in build with an exception of Animaiton type beeing default.


    EDIT: On another computer it's working... weird. have to look at it again
    EDIT2: It magicly started working. No further help needed in this topic :) But there is still problem with position described below:

    //##########################################

    And there is one more thing :)
    I want to make a combobox in one of my nodes, but using the Unity built in popup, it appears on weird position when the zoom is different than 1. So i have to make my custom editor window to make it appear always under my node. Simple, right :) I hate it already... Mabye because i don't fully understand what is going on there. I know you are using NodeEditor.ScreenToCanvasSpace(Vector2); to translate positions from screen to node canvas. So i made my function NodeEditor.CanvasToScreenSpace(Vector2) Brilliant idea! The name wasn't enough to make it work, so i implemented it as simple inverse function and it worked as far as position translation is conserned. But even with that i cannot make it work.
    I even decided that it can be showed just under my mouse position, but it doesn't work either! And it's weird.
    things i tried already:
    GUIUtility.GUIToScreenPoint(Event.current.mousePosition)
    GUIUtility.GUIToScreenPoint(GUILayoutUtility.GetLastRect().position);
    it all seems to be scaled by gui scale.

    Long post o_O
     
    Last edited: Jul 27, 2016
  8. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    @Aramilion Can I see your node code and can you also tell me how the nodes are stored? So far I'm clueless but let me take a look maybe I can find the cause:/
    EDIT: Alright, saw your edit:)

    Regarding your second problem, it's a bit tricky because there is scaling, group hacking and whatever complex stuff involved. Standard Unity GUI doesn't correctly account for scaling unfortunately (the whole scaling implementation is slacking). That's why I've started the OverlayGUI replacement for popups, etc.

    In order to get the real mouse position, always use GUIScaleUtility.GUIToScreenSpace(); which will give you the correct screen position. For GUI positions, it's indeed way more complex. I don't have a solid solution for you yet, I'll get back if I have. Until then, mouse position must suffice:/
     
    Last edited: Jul 27, 2016
  9. Aramilion

    Aramilion

    Joined:
    Apr 15, 2016
    Posts:
    23
    As i edited my earlier post, it seems fixed now. i'm not sure what have coused the problem.

    And with the position I will use it as soon as I will get to work tomorrow! Will tell here if it worked, but it soulds like it should :)
     
  10. Aramilion

    Aramilion

    Joined:
    Apr 15, 2016
    Posts:
    23
    I tried it, and it worked a bit. but with different scale than 1 is still the problem.
    I've used:
    NodeEditorFramework.Utilities.GUIScaleUtility.GUIToScreenSpace(Event.current.mousePosition) + editorWindow.position.position
    in NodeGUI() of one of my custom nodes.
    it always shows in position, where it would be correct if zoom was'1'. so it has offset which is grater, the greater is distance between node and centre of editorWindow.
    I want to make simple Popup window. Maybe i will try to do it like you have done contex menu? Hm. need to give it a try.

    EDIT: yeh, it's the same, i think it's coused by me wanting to call it from NodeGUI() which is overlaped by GUILayout;
     
    Last edited: Jul 28, 2016
  11. Overmind5000

    Overmind5000

    Joined:
    Dec 26, 2013
    Posts:
    4
    Hello folks. I just want to say Very spiffy work on this editor, though while using the Develop branch, I've run into a problem.

    Severity Code Description Project File Line Suppression State
    Error CS1061 'GenericMenu' does not contain a definition for 'Show' and no extension method 'Show' accepting a first argument of type 'GenericMenu' could be found (are you missing a using directive or an assembly reference?) ************\Assets\Plugins\Node_Editor\Framework\NodeEditorInputSystem.cs 266 Active

    Just for experimentation, I replaced the problem function 'Show' with one that was available labeled 'ShowAsContext'. I'm not sure if that was a function of be not understanding the code, or if something was off in the repository. I got it to work with my fix, but I was unable to find a way to specify a canvas type.

    That said, I hope a fix may emerge sometime soon.

    EDIT: I'm using Unity 5.4.0f3.
     
    Last edited: Aug 9, 2016
  12. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hi, thanks for the kind words:)
    The error is caused by the class GenericMenu in NoodeEditorFramework that aims to improve and fix some things of the UnityEditor.GenericMenu. One 'improvement' was to add a Show method to show the menu at arbitrary positions.
    What seems to happen is that somehow the code references the UnityEditor version instead of the replacement one... Did you change anything, like added the UnityEditor directive?
    Tbh I did not yet test it in 5.4 but apparently they broke a different tool/utility of mine with a simple precaution so I'm not too suprised seeing it broken in some way:/
     
  13. Overmind5000

    Overmind5000

    Joined:
    Dec 26, 2013
    Posts:
    4
    I have not included UnityEditor as a dependency. In fact, when inspecting the GenericMenu class made for the node editor, and there was no Show() function present, but there was one present in the class PopupMenu instead.

    By the way, The error persisted through 2 other files - RuntimeNodeEditor.cs, NodeEditorInputSystem.cs

    EDIT: I noticed your latest commit. It fixed the issue. Thank you.
     
    Last edited: Aug 9, 2016
  14. chrislugram

    chrislugram

    Joined:
    Jun 16, 2014
    Posts:
    3
    Hi everyone,

    First of all, thanks for this project, it is really useful. I am trying to connect several outputs in only one input, but I don't know how. Is it that possible? or I should to create one inputs for each outputs dinamically? (or something else that I have not thought)

    example.png

    Thanks!
     
  15. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hi! First, know that this has been requested alot and I'll keep it in my mind:)
    This Node Editor was built with calculation in mind, and even though we're planning to expand this with other cases of usage on GitHub right now, the current calculation system just would not work with having multiple inputs to one output. So, that would be the first thing to do.
    But, I see you're using it as a dialogue - so you might be able to modify it to your needs until this gets more flexible. There are others on this thread that already did this though, so it might be worth a try. Additionally, there is a new branch added to the repo recently by ChicK00o which is a great working dialogue example which works by dragging and dropping it into a project with the latest node editor develop version:)
     
  16. chrislugram

    chrislugram

    Joined:
    Jun 16, 2014
    Posts:
    3
    Thanks a lot! I'm going to search in ChicK00o solutions!
     
  17. M_Dizzle

    M_Dizzle

    Joined:
    Dec 10, 2013
    Posts:
    20
  18. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hi! Thanks for this reminder, should have kept it up to date:D
    Had a kind of hard time searching it but eventually I found it and it was quickly updated. I made yet another example branch for it including the texture canvas that I was using as an example when I first posted it:)
     
    M_Dizzle likes this.
  19. _alia_

    _alia_

    Joined:
    Nov 4, 2008
    Posts:
    29
    Just wanted to say thanks for an excellent framework! Super easy to use! Makes debugging noise functions a doddle!

    heat_noise.PNG
     
    Seneral likes this.
  20. M_Dizzle

    M_Dizzle

    Joined:
    Dec 10, 2013
    Posts:
    20

    Amazing! Thanks so much. This example really helps me to understand the structure of how to work with the framework too. Thanks for all your hard work!
     
    Seneral likes this.
  21. M_Dizzle

    M_Dizzle

    Joined:
    Dec 10, 2013
    Posts:
    20
    Hi @Seneral! me again.

    I've been looking into Node Editor to generate synth audio - by having an audio output node, that's connected to a synth generation node. The Node Canvas is loaded in a Monobehavior called SynthPlayer.cs that uses onAudioFilterRead (https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnAudioFilterRead.html) to populate the data[] from the Audio Output node I've created.

    The problem is that it's necessary to recalculate the canvas each time onAudioFilterRead is called to generate the next part of the soundwave, but calling NodeEditor.RecalculateAll(canvas) throws this error:

    ArgumentException: LoadAssetAtPath can only be called from the main thread.
    Constructors and field initializers will be executed from the loading thread when loading a scene.
    Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
    NodeEditorFramework.NodeEditor.CheckEditorPath () (at Assets/plugins/Node_Editor/Framework/NodeEditor.cs:94)
    NodeEditorFramework.NodeEditor.ReInit (Boolean GUIFunction) (at Assets/plugins/Node_Editor/Framework/NodeEditor.cs:51)
    NodeEditorFramework.NodeEditor.checkInit (Boolean GUIFunction) (at Assets/plugins/Node_Editor/Framework/NodeEditor.cs:43)
    NodeEditorFramework.NodeEditor.StartCalculation () (at Assets/plugins/Node_Editor/Framework/NodeEditor.cs:332)
    NodeEditorFramework.NodeEditor.RecalculateAll (NodeEditorFramework.NodeCanvas nodeCanvas) (at Assets/plugins/Node_Editor/Framework/NodeEditor.cs:313)
    SynthPlayer.OnAudioFilterRead (System.Single[] data, Int32 channels) (at Assets/NodeReactor/SynthComposer/SynthPlayer.cs:58)
    I've found a workaround that involves manually calling the Output node's .Calculate() function from onAudioFilterRead, which then has to call it's input's .Calculate() function - but this obviously not ideal as I'd need to add this to every single node class that I want to include in my synth player and would get messy in cases where one output knob is going to multiple knobs (the wrong phase of sound would be produced as it'd be run twice).

    Is there a way to Recalculate the canvas outside of the main thread without directly editing the framework?

    I noticed that there's flags & functions for keeping track of whether the node and descendants are calculated, but these are internals/protected.

    I'd like to avoid touching your framework code if possible, so would I have to write my own recursive calc function and keep track of the calculated nodes in a List<> or something?
     
  22. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hi! This error is triggered because the callback you're using is called on a different thread. That broke another tool of mine aswell in 5.4:/ Pretty annoying tbh...
    But from looking at the stack trace it's caused by the first initialization of the framework which is needed to check and initialize it's modules. It is also checking it's path, which is causing the error here. As this initialization has only to be done once, you should be able to move it to an initialization function which is called on the main thread. Do that by adding NodeEditor.checkInit () in either Start or Awake:)
    If that is the only problem with recalculating on a different thread, than this should be all you need to do. Let's hope, else alot more changes would be needed...
     
    M_Dizzle likes this.
  23. M_Dizzle

    M_Dizzle

    Joined:
    Dec 10, 2013
    Posts:
    20
    Hey @Seneral thanks for the quick reply!

    I fixed the problem myself! I ended up doing what I said and making my own recursive algorithm, it'd be good to get your feedback!

    I basically copied your RTCanvasCalculator and added my own bits to make a base class to extend;

    Code (CSharp):
    1. //canvasPlayer.cs
    2. using UnityEngine;
    3. using System;  // Needed for Math
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using System.Linq;
    7.  
    8. using NodeEditorFramework;
    9.  
    10. public class CanvasPlayer : MonoBehaviour
    11. {
    12.  
    13.     public string canvasPath;
    14.     private List<Node> calculatedNodes; //the nodes that have been calculated already in Calculate all
    15.     /// <summary>
    16.     /// Gets the working canvas that is internally used, it is not the saved one the path points to
    17.     /// </summary>
    18.     public NodeCanvas canvas { get; private set; }
    19.  
    20.     protected virtual void Start()
    21.     {
    22.         LoadCanvas(canvasPath);
    23.     }
    24.  
    25.     protected virtual void Update()
    26.     {
    27.  
    28.     }
    29.  
    30.     /// <summary>
    31.     /// Assures the canvas is loaded
    32.     /// </summary>
    33.     public void AssureCanvas()
    34.     {
    35.         if (canvas == null)
    36.         { // Try to load canvas
    37.             LoadCanvas(canvasPath);
    38.             if (canvas == null)
    39.                 throw new UnityException("No canvas specified to calculate on " + name + "!");
    40.         }
    41.     }
    42.  
    43.     /// <summary>
    44.     /// Loads the canvas at path as a copy
    45.     /// </summary>
    46.     public void LoadCanvas(string path)
    47.     {
    48.         canvasPath = path;
    49.         if (!string.IsNullOrEmpty(canvasPath))
    50.         {
    51.             canvas = NodeEditorSaveManager.LoadNodeCanvas(canvasPath, true);
    52.             CalculateCanvas();
    53.         }
    54.         else
    55.             canvas = null;
    56.     }
    57.  
    58.     /// <summary>
    59.     /// Calculates the currently loaded canvas and debugs the various outputs
    60.     /// </summary>
    61.     public void CalculateCanvas()
    62.     {
    63.         //AssureCanvas();
    64.         NodeEditor.RecalculateAll(canvas);
    65.         //DebugOutputResults();
    66.     }
    67.  
    68.     /// <summary>
    69.     /// Debugs the values of all possible output nodes
    70.     /// Could be done more precisely but it atleast shows how to get them
    71.     /// </summary>
    72.     private void DebugOutputResults()
    73.     {
    74.         AssureCanvas();
    75.         List<Node> outputNodes = getOutputNodes();
    76.         foreach (Node outputNode in outputNodes)
    77.         {
    78.             string outID = "(OUT) " + outputNode.name + ": ";
    79.             if (outputNode.Outputs.Count == 0)
    80.             { // If the node has no outputs, display it's inputs, because that's what the output node works with
    81.                 foreach (NodeInput input in outputNode.Inputs)
    82.                     outID += input.typeID + " " + (input.IsValueNull ? "NULL" : input.GetValue().ToString()) + "; ";
    83.             }
    84.             else
    85.             { // Else display the final output of the output node
    86.                 foreach (NodeOutput output in outputNode.Outputs)
    87.                     outID += output.typeID + " " + (output.IsValueNull ? "NULL" : output.GetValue().ToString()) + "; ";
    88.             }
    89.             Debug.Log(outID);
    90.         }
    91.     }
    92.  
    93.     /// <summary>
    94.     /// Gets all nodes that either have no inputs or no input connections assigned
    95.     /// </summary>
    96.     public List<Node> getInputNodes()
    97.     {
    98.         AssureCanvas();
    99.         return canvas.nodes.Where((Node node) => (node.Inputs.Count == 0 && node.Outputs.Count != 0) || node.Inputs.TrueForAll((NodeInput input) => input.connection == null)).ToList();
    100.     }
    101.  
    102.     /// <summary>
    103.     /// Gets all nodes that either have no output or no output connections leading to a followup node
    104.     /// </summary>
    105.     public List<Node> getOutputNodes()
    106.     {
    107.         AssureCanvas();
    108.         return canvas.nodes.Where((Node node) => (node.Outputs.Count == 0 && node.Inputs.Count != 0) || node.Outputs.TrueForAll((NodeOutput output) => output.connections.Count == 0)).ToList();
    109.     }
    110.  
    111.     public List<T> getOutputNodes<T>()
    112.     {
    113.         AssureCanvas();
    114.         return canvas.nodes.OfType<T>().ToList<T>();
    115.     }
    116.  
    117.     public void CalculateAll()
    118.     {
    119.         calculatedNodes = new List<Node>();
    120.         List<Node> outputs = getOutputNodes();
    121.  
    122.         foreach (Node node in outputs)
    123.         {
    124.             CalculateNode(node);
    125.         }
    126.     }
    127.     public void CalculateNode(Node checkNode)
    128.     {
    129.         //get this nodes inputs
    130.         List<NodeInput> inputs = checkNode.Inputs;
    131.         foreach(NodeInput inputNode in inputs)
    132.         {
    133.             Node node = inputNode.GetNodeAcrossConnection();
    134.             CalculateNode(node);
    135.         }
    136.         if (!calculatedNodes.Contains(checkNode))
    137.         {
    138.             checkNode.Calculate();
    139.             calculatedNodes.Add(checkNode);
    140.         }
    141.            
    142.  
    143.     }
    144. }
    145.  
    I added List<Node> calculatedNodes and then a recursive function to iterate back through them;

    Code (CSharp):
    1.  
    2.     public void CalculateAll()
    3.     {
    4.         calculatedNodes = new List<Node>();
    5.         List<Node> outputs = getOutputNodes();
    6.  
    7.         foreach (Node node in outputs)
    8.         {
    9.             CalculateNode(node);
    10.         }
    11.     }
    12.     public void CalculateNode(Node checkNode)
    13.     {
    14.         //get this nodes inputs
    15.         List<NodeInput> inputs = checkNode.Inputs;
    16.         foreach(NodeInput inputNode in inputs)
    17.         {
    18.             Node node = inputNode.GetNodeAcrossConnection();
    19.             CalculateNode(node);
    20.         }
    21.         if (!calculatedNodes.Contains(checkNode))
    22.         {
    23.             checkNode.Calculate();
    24.             calculatedNodes.Add(checkNode);
    25.         }
    26.            
    27.  
    28.     }
    I've only tested it over one connection so far, but it seems to be working

    I also added a GetOutputs<T>() so I could easily grab a particular output type to my class as well as copying your Editor script to support getting the path in the inspector.

    Is this fine, or should I try as you suggested with the checkInit() method?

    Cheers!
     
  24. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Well RTCanvasCalculator is meant to be used as an example and thus that'd be the best way to get started. Still, I'd try to simply add a checkInit in the start method, I'd really like to know;)
     
  25. muhammad_ahmad1999

    muhammad_ahmad1999

    Joined:
    Aug 4, 2016
    Posts:
    7
    Hello.

    The node editor that you have created, can we use it in runtime. I mean will the node editor work in the final compiled exe?

    Thank you in advance!
     
  26. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    I don't know what you exactly mean, whether you want it to calculate at runtime or whether you want your players to be able to use the node editor...Either way, you can fully use the API at runtime, so you can calculate or do whatevery you want with the canvases, and to some extend also use the Node Editor GUI. There are some limitations that are normal at runtime, f.E. you can't save canvases as assets so all your changes would be lost. For an example of it you can drag the RuntimeNodeEditor Component on an object:)
     
  27. muhammad_ahmad1999

    muhammad_ahmad1999

    Joined:
    Aug 4, 2016
    Posts:
    7
    hello

    Thanks for your quick reply!!!

    I just did do that but I see nothing -> I dragged the RuntimeNodeEditor to an object and I ran it and I see a black screen (Unity sky).

    Thanks for your quick response!
     
  28. muhammad_ahmad1999

    muhammad_ahmad1999

    Joined:
    Aug 4, 2016
    Posts:
    7
    Also, is there a way we could get a list of all the nodes that are connected to each other.

    Like for example, if there is a start node and then that is linked to an add node. is there a way we could get a list of nodes that gives a list containing the start node then the add node?

    Thanks!
     
  29. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Sorry I forgot to add you need to specify a canvas. Try playing with the few settings. nevertheless I'll check and assure it works later.
    Also check the RTCanvasCalculator, it has no GUI but some functions like these that are helpful. I did post them last page in this post:)
    Sorry for the short answers!
     
  30. Rimevel

    Rimevel

    Joined:
    Dec 8, 2015
    Posts:
    10
    Hello Seneral.
    I am working on implementing a simple visual scripting system using your code as a base. Been going well so far but I have a weird problem I have been trying to figure out. When I start the game all connections between nodes are lost for some reason :( But it works fine in the editor. Even when saving and loading. For some reason connections are temporarily stripped from the canvas asset during runtime?
     
  31. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,421
    Hi @Seneral
    Just came across this and I think it's great, but the documentation doesn't explain how to create custom nodes...

    I am looking to strip out the default nodes and create a few simple ones for my use:

    • Title Node (no connections)
      • title (string)
    • Description Node (no connections)
      • description (string/textbox)
    • Option Node (can connect to the child options node below)
      • display title (string)
      • executeCommand (boolean)
      • command (string)
    • Child Option Node (can connect to other child option nodes)
      • display title (string)
      • executeCommand (boolean)
      • command (string)
    Is this kind of setup simple (and how would I do it)?

    node.png

    Currently when I try to create my own node (even when duplicating an existing one), I get this when trying to create it in the graph editor:

    Code (CSharp):
    1. InvalidOperationException: Operation is not valid due to the current state of the object
    2. System.Linq.Enumerable.Single[Node] (IEnumerable`1 source, System.Func`2 predicate, Fallback fallback)
    3. System.Linq.Enumerable.Single[Node] (IEnumerable`1 source, System.Func`2 predicate)
    4. NodeEditorFramework.NodeTypes.getDefaultNode (System.String nodeID) (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Framework/NodeTypes.cs:58)
    5. NodeEditorFramework.Node.Create (System.String nodeID, Vector2 position) (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Framework/Node.cs:78)
    6. NodeEditorFramework.NodeEditor.ContextCallback (System.Object obj) (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Framework/NodeEditor.cs:624)
    7. NodeEditorFramework.Utilities.PopupMenu+MenuItem.Execute () (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Utilities/OverlayGUI.cs:320)
    8. NodeEditorFramework.Utilities.PopupMenu.DrawItem (NodeEditorFramework.Utilities.MenuItem item, Rect groupRect) (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Utilities/OverlayGUI.cs:227)
    9. NodeEditorFramework.Utilities.PopupMenu.DrawGroup (Rect pos, System.Collections.Generic.List`1 menuItems) (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Utilities/OverlayGUI.cs:187)
    10. NodeEditorFramework.Utilities.PopupMenu.Draw () (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Utilities/OverlayGUI.cs:161)
    11. NodeEditorFramework.Utilities.OverlayGUI.StartOverlayGUI () (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Utilities/OverlayGUI.cs:24)
    12. NodeEditorFramework.NodeEditor.DrawCanvas (NodeEditorFramework.NodeCanvas nodeCanvas, NodeEditorFramework.NodeEditorState editorState) (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Node_Editor/Framework/NodeEditor.cs:130)
    13. NodeEditorFramework.NodeEditorWindow.OnGUI () (at Assets/Scripts/Console Interaction/Terminal_Node_Editor/Editor/Node_Editor/NodeEditorWindow.cs:127)
    14. System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)
     
    Last edited: Aug 20, 2016
  32. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    That's certainly, weird... which version are you using? Can you verify they are actually removed temporarily, or are they just not drawn (which is way more likely)? Like, debug the connections on a buttonclick in one node...
     
  33. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Yes, the documentation is very outdated, atleast that one for the master branch... There has been a MUCh better documentation in progress since march but haven't been able to update and upload it yet. But, now that I have weekend, I might be able to do it, even if it will take quite some time:)

    Did you try in 5.3.x or in 5.4?
    Also, assuming when copying you did change identification stuff like class name, path specified in the attribute and ID itself, right? And where did you place that copy? It should run everywhere BUT the Plugins/Editor folder if I remember correctly...
     
  34. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,421
    We are using Unity Pro 5.4.0f3.

    I changed the class name and ID (not sure what you mean by attribute(if you mean the node's menu path, then yes)) and the file is in a folder called "Default" which is in the same folder as the Example and FloatCalc folders.

    I copied the ExampleNode from the Examples folder to this place and then edited it, which should have worked but now I am unable to add both my custom node, or your example one, and am given that error twice each time I try.
     
  35. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Well then it's probably related to 5.4.0... I unfortunately still did not find enough time to update it accordingly, will take a look at it now even though I should sleep by now :D

    EDIT: So I tested in 5.4.0f3, too, and everything seems fine. Are you using the latest version from the develop branch? And can you send your node code even if the changes should be all done, maybe there is something you missed... else I don't yet know what could have caused this:/
     
  36. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    @Labyrith-Studios Regarding your actual layout and design that you're aiming for, it seems perfectly fine and is easy to implement, atleast from the Node Editor side;)
    You would only have those four nodes... or three, depending if you'd really need a seperate Child Node... or even one, because title and description could be solved better otherwise I suppose:) And of course one custom ConnectionType for the connections.
    Other than that I can't really say anything without knowing your plans, but seems simple enough...
     
  37. M_Dizzle

    M_Dizzle

    Joined:
    Dec 10, 2013
    Posts:
    20
    Hi @Seneral I tried adding the checkInit function to my start method and it still didn't work - same error as before
    Hi @Seneral I tried using the CheckInit method you suggested, but it didn't work - fortunately mine did, although I added a check whether the node across the connection was null or not before calculating.

    Code (CSharp):
    1. public void CalculateNode(Node checkNode)
    2.     {
    3.        
    4.         //get this nodes inputs
    5.  
    6.         List<NodeInput> inputs = checkNode.Inputs;
    7.         foreach (NodeInput inputNode in inputs)
    8.         {
    9.             Node node = inputNode.GetNodeAcrossConnection();
    10.             if(node!=null) //the added check for null
    11.                 CalculateNode(node);
    12.         }
    13.         if (!calculatedNodes.Contains(checkNode))
    14.         {
    15.             checkNode.Calculate();
    16.             calculatedNodes.Add(checkNode);
    17.         }
    18.     }
    On another note, how do I go about using a custom GUIStyle on certain elements? The best I've come up with is finding a monobehavior in the scene with a public property of a GUISkin, but I seem to have to do this every frame.
     
  38. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Ouch, missed something:) The theory was that later in the callback function it would not need to reinit again - but I forgot that it does need to reinit i it hasn't been initiated in the OnGUI function before because it needs to be in the onGUI function to set the GUI parts up.
    Anyway, if you want to try one more time, you need to call it in the first OnGUI call.

    Well you can always cache the GUIStyle, right? What I'd do and what is already done like this with other special styles is to load them on Initialization in NodeEditorGUI and putting them into static properties which can be accessed by the nodes:)
     
  39. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,421
    Do you know what the error is that I keep getting though?
    I have tried several things but making my own seems to invalidate my new one and that which it is copied from :(
     
  40. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    As I said before, no, I don't receive any errors when performing the actions you mentioned... Can you send your node code which throws the error when trying to create?
     
  41. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,421
    Fixed it...
    I had a typo which wasn't squiggled :(

    I do however have a bit of a problem with 1 of my nodes.

    I have an option node which has a float called level.
    I also have another node called child option which is meant to display the level value of the connected parent option node, but doesn't.

    Option Node
    Code (CSharp):
    1. using UnityEngine;
    2. using NodeEditorFramework;
    3. using NodeEditorFramework.Utilities;
    4.  
    5. [Node (false, "Standard/Terminal/Option Node")]
    6. public class OptionNode : Node
    7. {
    8.     public const string ID = "optionNode";
    9.     public override string GetID { get { return ID; } }
    10.  
    11.     public string value = "Example";
    12.     public float level;
    13.     public string command;
    14.  
    15.     public override Node Create (Vector2 pos)
    16.     {
    17.         OptionNode node = CreateInstance<OptionNode> ();
    18.      
    19.         node.rect = new Rect (pos.x, pos.y, 300, 100);
    20.         node.name = "Option Node";
    21.  
    22.         NodeOutput.Create(node, "level", "Float");
    23.  
    24.         return node;
    25.     }
    26.  
    27.     protected internal override void NodeGUI ()
    28.     {
    29.         GUILayout.Label ("Please add an option below:");
    30.  
    31.         value = RTEditorGUI.TextField(new GUIContent("Title", "The title displayed as the option."), value);
    32.         level = RTEditorGUI.FloatField(new GUIContent("Level", "The level index for the option."), level);
    33.         OutputKnob(0);
    34.         command = RTEditorGUI.TextField(new GUIContent("Command", "Runs if this is an end option."), command);
    35.  
    36.         if (GUI.changed)
    37.             NodeEditor.RecalculateFrom(this);
    38.     }
    39.  
    40.     public override bool Calculate ()
    41.     {
    42.         Outputs[0].SetValue (level);
    43.         return true;
    44.     }
    45. }
    46.  
    Child Option Node
    Code (CSharp):
    1. using UnityEngine;
    2. using NodeEditorFramework;
    3. using NodeEditorFramework.Utilities;
    4.  
    5. [Node (false, "Standard/Terminal/Child Option Node")]
    6. public class ChildOptionNode : Node
    7. {
    8.     public const string ID = "childOptionNode";
    9.     public override string GetID { get { return ID; } }
    10.  
    11.     [HideInInspector]
    12.     public bool assigned = false;
    13.     public float parentValue = 0;
    14.  
    15.     public string value = "Example";
    16.     public float level;
    17.     public string command;
    18.  
    19.     public override Node Create (Vector2 pos)
    20.     {
    21.         ChildOptionNode node = CreateInstance<ChildOptionNode> ();
    22.      
    23.         node.rect = new Rect (pos.x, pos.y, 300, 116);
    24.         node.name = "Child Option Node";
    25.  
    26.         NodeInput.Create(node, "parentValue", "Float");
    27.         NodeOutput.Create(node, "level", "Float");
    28.  
    29.         return node;
    30.     }
    31.  
    32.     protected internal override void NodeGUI ()
    33.     {
    34.         Inputs[0].DisplayLayout(new GUIContent("Parent Level: " + (assigned ? parentValue.ToString() : ""), "The input value to display"));
    35.         GUILayout.Label ("Please add an option below:");
    36.  
    37.         value = RTEditorGUI.TextField(new GUIContent("Title", "The title displayed as the option."), value);
    38.         level = RTEditorGUI.FloatField(new GUIContent("Level", "The level index for the option."), level);
    39.         OutputKnob(0);
    40.         command = RTEditorGUI.TextField(new GUIContent("Command", "Runs if this is an end option."), command);
    41.  
    42.         if (GUI.changed)
    43.             NodeEditor.RecalculateFrom(this);
    44.     }
    45.  
    46.     public override bool Calculate ()
    47.     {
    48.         if (!allInputsReady())
    49.         {
    50.             parentValue = 0;
    51.             assigned = false;
    52.             return false;
    53.         }
    54.  
    55.         parentValue = Inputs[0].connection.GetValue<float>();
    56.         assigned = true;
    57.  
    58.         Outputs[0].SetValue<float>(level);
    59.         return true;
    60.     }
    61. }
    62.  
    I can't work out what is wrong, any ideas?

    I am also trying to work out how to change the node line and input/output box colours as they are quite hard to look at through my monitor (not the best monitor) but can't find it anywhere.
     
  42. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Huh, it does work for me... Copied the nodes in and after adding a method overload in RTEditorGUI for TextField which you seem to have added, everything works fine, I can change the parent level float and it is automatically updated and displayed in the connected child option node (Note: in the label, but not in the text input box if that's what you mean)...
    WorkingOptionNodes.jpg

    For changing the color of the connection, just edit the default float connection type or add a new one if you want. It can be found in Framework/ConnectionTypes.cs, at the very bottom:)
     
  43. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,421
    I didn't make any changes to RTEditorGUI, it was already there!
     
  44. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    I just downloaded the latest version of the develop branch and still the nodes access a RTEditorGUI.TextField overload with only two parameters (GUIStyle missing for default). So now it's sure we're talking of different versions here... Do you use the master branch or develop? Although it seems weird, develop is actually the more stable right now because I didn't have the time yet to merge them and create a new release. Can you confirm you're using develop?
     
  45. vicenterusso

    vicenterusso

    Joined:
    Jan 8, 2013
    Posts:
    130
    Does your node system works at runtime?
     
  46. Rimevel

    Rimevel

    Joined:
    Dec 8, 2015
    Posts:
    10
    Using your dev branch version.
    After som more testing it seems like the connections are intact inside of the .asset files.
    It is only when trying to access the data through a public reference inside a component during runtime that all outputs & inputs return null.

    Is it wrong to just do this and link a .asset file that contains a node canvas through the inspector?:

    Code (CSharp):
    1. public NodeCanvas canvas;
    Not sure if I need to do something else to be able to read all the data inside :/
     
  47. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Ah I thought you meant the connections would dissappear in the RuntimeNodeCanvas! Now I understand:)

    With the latest version it should not be a problem, now that the need for uncompressing is removed:) If in doubt, resave the file before use from inside the Editor window!
    Tell me if that works.
     
  48. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,421
    Ah, I didn't even check for different branches...Oops!

    I am using the main one, should I be using the Develop one instead?
     
  49. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Yes! I'm sorry for that inconvenience, I haven't yet found the time to merge them. I mentioned it in the readme but barely anyone reads the full readme before testing (me included) ;)
    But yes, master hasn't been updated in months unfortunately, develop is currently best (and usually more stable, even though I can't always promise stability on develop...)
     
  50. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hey guys, I need feedback on the newest update on the repo, I really hope to finally have eliminated most bugs... if so, then I finally am able to merge and get the master up and running - and then I can put the new documentation online which has been held back because it only applies to the develop branch so far (yes, a mess).
    So, any feedback is highly appreciated!