Search Unity

Simple node editor

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

  1. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Aha. Thanks, I'll write on the list - as item #9724818635935173 that needs to be done. :D
     
  2. WanderlandGaming

    WanderlandGaming

    Joined:
    Oct 5, 2016
    Posts:
    3
    Just discovered this thread while looking for a solution to manage a small army of nodes in a story, with a fair amount of details to handle for each node. I am still fairly new with Unity, so there is lots of learning taken just by trying and understand the framework and examples.
    There will be a link between a standard screen type of input - I have a 'draft UI' for this that I am finalising - and the node editor which hopefully will gently sync with the underlying data model, as two different views on the same set of data.
    Wherever my few Unity hours per week end up ... Thanks for the great framework, and sharing :)
     
  3. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    So things are moving forward for me, I'm finally able to save the nodes, knobs and connections in my database. Yay. :)

    Now I face a small issue: When dragging to make a connection, I can make several connections FROM the same knob, but not to it. Fair enough, no biggie...but, how to I save all the connections?

    Right now, I'm using knob.GetNodeAcrossConnection(); to access the connected node. Not nodeS. ;) I assume (haven't cheched) that it gives me the first/oldest connection I made from that knob.

    Would it be hard to get all them? If so, would it be easier to disable multi connections and put a GUI warning "Are you sure you want to change this connection?"?
     
  4. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Thanks:) Yep, probably need to write a converter as Jamsa does for you custom underlying data model...
     
  5. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Great:) Well, you can access all the connecting knobs through connection or connections (depending on the knob type, currently you can't create multiple connections to an input) and then call knob.body to get the node:)
     
  6. WanderlandGaming

    WanderlandGaming

    Joined:
    Oct 5, 2016
    Posts:
    3
    Indeed, there seems to be some similarities ... Looking at it from a 'user friendliness' perspective, I believe the nodes will be enriched with some decorators (think about a visual way to segregate the type of data hidden in the node ... type of actions and decision tree as for their statuses) and a trigger for a detailed input of what is in the node details. I currenty imagine the nodes as a type of summary / helicopter view that helps accessing the inner details.
    Being a vintage type of developer, I guess it will take a bit of time, and some hairs to be lost in the process as the ideas of how the framework can be used keep popping in :p
     
  7. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Sorry, didn't see your reply before now...

    Hmm... right now I'm getting the node at the other end of a connection this way:
    Code (CSharp):
    1. Node Connectednode = knob.GetNodeAcrossConnection();
    What's knob type? You mean in/out?

    I can't really see, how I could get all of the nodes, if there's more. Could you explain it a bit more? Or even give an example? :)
     
  8. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hey, sure:)
    Code (csharp):
    1. Node prev = knob.connection.body; // For Inputs
    2. List<Node> next = knobOut.connections.Select<Node> ((Knob k) => k.body).ToList(); // For Outputs
    Sorry, only pseudo code... am on my mobile currently.
    Hope that works for you:)
    Seneral
     
  9. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Awesome, thanks. :) :)
     
  10. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Lol, I spoke (wrote? :D) too soon. :p

    My code looks like this:
    Code (CSharp):
    1. foreach (NodeKnob knob in node.nodeKnobs)
    2.                 {
    3.                    
    4.                     List<Node> next = knobOut.connections.Select<Node>((NodeKnob k) => k.body).ToList(); // For Outputs
    5. ...
    1) there's no Knob k, so I changed it to NodeKnob k - seems to work

    2) knobOut should just be a knob? No? Guess that's what you meant by knob type. :D
    How do I get the right knob type, in the code shown above? Connections going out should be good enough for me. :)
     
  11. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Yes, forgot it's called NodeKnob not Knob. As I said, just on mobile;)
    Well if you want all connections in a canvas it's best to focus on one type - in or out...

    So when iterating the node.nodeKnobs list, you can check for the type like this:
    Code (csharp):
    1. if (knob is OutputKnob)
    2.     NodeKnob outKnob = (OutputKnob)knob;
    And then perform either of these actions to get the connected nodes.

    When you loaded the canvas properly with the functions from NodeEditorSaveManager then the lists node.Inputs and node.Outputs are already populated according to the type so you could just iterate over these lists.

    Hope that helps:)
    Seneral
     
    Last edited: May 4, 2017
  12. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Yes, a fine excuse. :p ;)

    Aha, looks easy. Me like! :D

    Thanks!! :) :)

    "When you loaded the canvas properly with the functions..." Um, did *I* do that, or did you?? :D I haven't even started doing the load functions yet! :D
     
  13. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hey - sorry just checked, please remove the typeof() in the if condition:) Edited...

    Regarding the load functions... Where do you access the canvas from? From the editor window, so the window handles the loading? Or do you simply reference the canvas asset?
    If it's a simple reference, Inputs and Outputs are not populated - this is done by the load functions in NodeEditorSaveManager... Either way, the first method always works fine - but from functions in the Node itself, you can always use Outputs[] or Inputs[] directly, as a shortcut;)
     
  14. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Awesome. Even easier! :D Can we remove moar!? :D
     
    Seneral likes this.
  15. outpost75

    outpost75

    Joined:
    Jan 7, 2014
    Posts:
    4
    I can't build my project anymore, if I put the sources from the develop branch into my Assets/Plugins directory. This also happens with a blank and new Unity project. I'm using the Standalone build. What is my mistake?

    The editor (Window / Node Editor) is running without problems.

    Assets/Plugins/Node_Editor/Framework/SaveSystem/NodeEditorSaveManager.cs(273,5): error CS0103: The name `UnityEditor' does not exist in the current context
    Assets/Plugins/Node_Editor/Framework/SaveSystem/NodeEditorSaveManager.cs(277,4): error CS0103: The name `AddSubAssets' does not exist in the current context
    Assets/Plugins/Node_Editor/Framework/SaveSystem/NodeEditorSaveManager.cs(282,5): error CS0103: The name `AddSubAssets' does not exist in the current context
    Assets/Plugins/Node_Editor/Framework/SaveSystem/NodeEditorSaveManager.cs(284,6): error CS0103: The name `AddSubAsset' does not exist in the current context
    Error building Player because scripts had compiler errors

    Edit:
    The docs say "Installing is as simple as dragging and dropping the Editor and Node_Editor folders into your project at Assets/Plugins." But if I look at the Unity docs, the Plugins folder should contain .dll files.
    I moved the Editor and Node_Editor into "Assets/Editor/Node Editor" and changed the path in NodeEditor.cs. Seems to work fine.

    I also didn't see why there are two folders, Editor and Node_Editor, so I merged the Editor into Node_Editor. Doesn't seem to cause problems.

    Problem seems to be solved. Thanks for reading ;)

    Edit:
    Not resolved. I can't access the canvas, because it's in Editor. Since other people don't seem to have any problems, I'm obviously doing something wrong. But I don't understand what's missing.
    Could someone please upload an empty project, that can compile to an .exe and a MonoBehaviour script that can access the canvas so it can process the nodes?
     
    Last edited: May 6, 2017
  16. Wtyson

    Wtyson

    Joined:
    Aug 15, 2014
    Posts:
    58
    i get same error as above to when i drag and drop the master into a clean project.
     
  17. outpost75

    outpost75

    Joined:
    Jan 7, 2014
    Posts:
    4
    I put a "#if UNITY_EDITOR" around those lines and around my "NodeGUI()"s. It builds my exe, I can work with the editor.
     
  18. Wtyson

    Wtyson

    Joined:
    Aug 15, 2014
    Posts:
    58
    i cant get it to work at all in unity 5.6 all it does is throw errors a null reference . ill post actual error later when im not working
     
  19. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hey @outpost75 and @Wtyson :)
    Just checked, building with master works fine for me in 5.5.0.
    The develop branch indeed has errors - this is not uncommon though, as it's changing over development I can't always check if it builds fine - and when I added a dependency to the UnityEditor, especially in the save system, I sometimes forget to wrap it in an #if UNITY_EDITOR check. As @outpost75 points out, that should be the fix:)
    @Wtyson, I will have to check 5.6 once i can get my hands on it - I currently only have limited mobile connection, no Wifi, so I'm hesitant on what to download. Will fix as soon as I can.

    @outpost75 Regarding your errors after changing the folder structure:
    Never seen Plugins is only for DLLs - where is that from?
    Sure, you can put it somewhere else, but only limited. You may have to check with the special folders docs and especially the script compilation order to get an idea why it's placed how it is.
    Basically, the scripts in the editor folder, like the editor window, REQUIRE the UnityEditor namespace and only work in the editor. These are not included in the build.
    I placed the framework in the Plugin folder because that causes them to be compiled before all other scripts. This is on one hand benefitial in that it has support for UnityScript nodes and generally makes sure EVERY script can access it. On the other hand this means the NodeEditor in turn can NOT access any of your scripts outside the Plugin folder. So, you either put your custom nodes outside of the plugins folder so they can access your other code (like processing or database), or you can put the complete framework outside the Plugins folder, if you desire.

    TL;DR: Do NOT try to put all framework scripts in the Editor folder, this will exclude them from the build and normal scripts cannot access the framework anymore - throwing errors. In turn never put the scripts in the Editor folder outside of it, because that will include them in the build and directly throw the '`UnityEditor' does not exist in the current context' errors.

    Hope that helps:)
    Seneral
     
  20. outpost75

    outpost75

    Joined:
    Jan 7, 2014
    Posts:
    4
    @Seneral Thank you for confirming the #if.

    From the special folders docs, that you linked:
    I moved the Node_Editor from Plugins to its own folder. I don't see any errors or problems. So it should be fine, I think? Time will tell :)
     
  21. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Well, if you keep the Editor and Node_Editor folders themselves inplace and adjust the path, yes. Please note the said limitations this has, f.E. you can't use UnityScript nodes.
    Don't think it causes other complications though:)
     
  22. Wtyson

    Wtyson

    Joined:
    Aug 15, 2014
    Posts:
    58
    ok i lied this works fine in 5.6 was a issue on my end
     
  23. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Cool, no problem:) Glad it works.
     
  24. Wtyson

    Wtyson

    Joined:
    Aug 15, 2014
    Posts:
    58
    @Seneral its a nice editor i like it but issue is its more of a final product now that its gotten this far and makes it harder to customize or break apart due to it being split into so many scripts with all the extra custom methods. easier to make one from scratch at this point :p but all in all its a nice editor and a decent reference for people who don't know how to make one. i tested out a earlier release of it to and it was more code friendly in the earlier stages . but keep up the good work ;)
     
  25. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Interesting that you say this. I get your point, I agree it's alot of code to dig in right now than when the project started.
    This is due to the fact that, after user request, each module of the framework got an overhaul to be more generic (except of the connection/knob system - but most user requests I get now are targetted toward that, so it is next). This usually consists of the module getting it's own scripts, and the code to expand due to, for example, assembly fetching routines.
    So with each module being improved, the framework has slowly got bigger, but also closer to being a complete solution rather than a starting point.
    From my experience most users appreciate that - it's just so more convenient to work with out if the box.
    Maybe, and that is a big maybe, I can create a stripped down version whenever I merge to master so it is easy to grasp and build an own framework around. Problem with that is: To create a small franework I would have to strip so many features that actually make this framework useable...
    Or you can maybe, as you proposed yourself, use an older, less feature rich version.
    Anyway, thanks for your input - even though I can't and don't want to change it, I se your point.
    Maybe expanding the docs is the only solution to that in the long run...
     
  26. Wtyson

    Wtyson

    Joined:
    Aug 15, 2014
    Posts:
    58
    Yeah i spent some time with it cause i was trying to see if i could save time on creating the node editor back bone but after trying to integrate it into my already built custom editor it would stop working all together. wouldn't even give me a error which was strange. no big deal though. i just needed it for the save load canvas part. but im thinking i might change my system to auto write C# scripts instead. Not sure on this yet. still in the planning phase on this trying to make it intuitive and non coder friendly as well.
     
  27. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    Is there a repo for this now? Link please.
     
  28. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Got it in my signature lol - and a quick google would have brought it up, too;)
     
    Jamsa78 likes this.
  29. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Finally have some time to actually look at this...but now its a bit confusing. :-/

    My code:
    Code (CSharp):
    1.  
    2. foreach (NodeKnob knob in node.nodeKnobs)
    3.                 {
    4. List<Node> next = knobOut.connections.Select<Node>((NodeKnob k) => k.body).ToList(); // For Outputs
    5.                     if (knob is OutputKnob)
    6.                         NodeKnob outKnob = (OutputKnob)knob;
    knobOut is an unknown object, and I can't figure out what it should be?
    OutputKnob is also unknown, what's that supposed to be?
     
  30. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Lol, the check for the type OutputKnob and the following cast to OutputKnob outKnob is only there so the selection of the following nodes can actually happen (connections is only available on OutputKnobs).
    I accidentally confused some type names - as I said I was on my phone - so heres the full code to get the following nodes of one node:
    Code (csharp):
    1. List<Node> nConnectedNodes = new List<Node> ();
    2. foreach (NodeKnob knob in node.nodeKnobs)
    3. {
    4.     if (knob is NodeOutput)
    5.     { // This knob is an output knob referencing other nodes
    6.         NodeOutput outKnob = (NodeOutput)knob; // cast to type NodeOutput to access the member connections
    7.         List<Node> kConnectedNodes = outKnob.connections.Select((NodeInput kIn) => kIn.body).ToList(); // Get all nodes this output references
    8.         nConnectedNodes.AddRange (kConnectedNodes); // Add the connections of this knob to the node list
    9.     }
    10. }
    or in short:
    Code (csharp):
    1. List<Node> nConnectedNodes = new List<Node> ();
    2. foreach (NodeOutput outKnob in node.nodeKnobs.OfType<NodeOutput> ())
    3.         nConnectedNodes.AddRange (outKnob.connections.Select((NodeInput kIn) => kIn.body));
    Hope that makes sense to you now:)
    Seneral
     
  31. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Hehe, well I'm noobish, so I guess that makes it perfect. :D

    I'll check out the code tomorrow. :)
     
  32. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Awesome, No errors in the code!! :D Yay.

    You rock dude. :cool::D
     
  33. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    And now where I got save to work. Loading is next..but then I remember I also need to save the position of the nodes! :D

    Sooo....am I guessing correctly, when I'm looking at node.rect.position.x and node.rect.position.y?? :)
     
  34. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Well, rect consists of x and y position (which you linked) and width/height.
    But ontop of that you also need to save each node's individual members, like a variable in your node.
    I don't suppose you're familiar with System.Reflection?
    Can't guide you through every step but that's about what you should expect:)
     
  35. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    So I need all, even if width/height is default?

    You mean EVERYTHING, or just the ones that are specific for my nodes? :)

    Well, reflection, as the IBM version anno 1985. Yes. :cool:
    As the Unity version, nope! :confused: :D
     
  36. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Yes, currently many of the nodes variables - including knobs and size - is only initialized once in the create method but planned to be moved to properties so that they don't need to be saved explicitly.

    No, only the variables specific to your nodes;)

    Well, C# reflection isn't too bad, so if you got experience with the concept than it should be no big problem...
    You'd have to get all variables from the node children class (not including node base class) and manually save them, aswell as repopulate the node on loading.
    Or you can use a generalized serializer, but then you could just as well put the whole canvas object through such a serializer...
     
  37. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Hmm.. wouldn't it be easier to use the create method when loading? Sure the ids will not match, but...

    Lol, I may be noobish, but not THAT noobish. ;) My vars are already being saved. ;)

    Yeah...experience, that's the word...if only I could remember much about it. :D

    Yeah, I figured as much... ;p
     
  38. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    He, all variables would be reset. No way around serializing them, I'm afraid...
    But if they are alrady being saved, great! :)
    You can also manually pass each nodes variables inan override method instead of doing it generally...
     
  39. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Hmmm...that doesn't really give me a clear image of what to do... :p

    I guess I'll "just" have try it out and see what mess I'll make. :D
     
  40. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hey, sorry I can't guide you through it right now.
    But I'll see, once I have more time, I'll try implementing a custom format myself:)
     
  41. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Hehe, don't worry, it's weekend! :) :) :cool::p:D:eek::oops::rolleyes:o_O:confused::mad::(;):):D

    That would be awesome. :)
     
  42. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Not for me lol - not much of a weekend left...
    You probably all noticed I haven't been doing much development stuff on this project since quite a long time.
    Well, here's why:
    I have tons more stuff to do than just three months ago... I literally only have one day in the week + weekend that I have free time. Additionally to this project, I'm currently writing an essay, creating a trailer and an update for TC2 Node Painter, and helping friends renovating...
    Hope you all understand:) Will try to be back on this project once I do have more time!
     
    Jamsa78 likes this.
  43. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Hehe, they got a name for that: Workaholic! :D

    As long as we're getting it for free, I can't see that we can demand anything from you. :)
     
  44. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hehe, that's true I guess:) Still, would love to have more time to put into this project...
     
    Jamsa78 likes this.
  45. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Hehe, and so would we! :D Wanna come and work with us?? :D
     
  46. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Ok, now I can load the individual nodes, put them in a list and add that list to a newly created nodecanvas.
    But what then?
    using cache.nodeCanvas = MyNewCanvas; clearly doesn't work - the sidegui dissapears and a wierd green thingy is placed in the center of the canvas! :D
     
  47. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Use the SetCanvas function - it automatically checks if the canvas is valid, manages the editor state (which could be the reason the UI freaked out for you), updates the cache and so on.
    I see that it would have been easier to capsulate that variable and add proper getter/setter which automatically handle this:D
     
  48. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    Ah, of cause the famous SetCanvas function! Why didn't I think that!? :D Oh, well. I'm just lame, or something. :p

    Ah, yes. But that would have been too easy! Right? :D
     
  49. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96

    Hmm..using cache.SetCanvas doesn't change anything, still crashes. :(

    Do I have to do something else? Or perhaps in a different order? Perhaps something about the EditorState??
     
  50. Jamsa78

    Jamsa78

    Joined:
    Mar 29, 2017
    Posts:
    96
    This is my code, without the boring stuff:
    Code (CSharp):
    1.                     NodeCanvas nodeCanvas = ScriptableObject.CreateInstance<NodeCanvas>();
    2.                     List<Node> NodeList = new List<Node>();
    3. .
    4. .(for loop'n'stuff)
    5. .
    6.                     ProvideNode provideNode = ScriptableObject.CreateInstance<ProvideNode>();
    7.                     NodeData = GetSingelNodeFromDB(path, Nodes[nodeCnt,1]);
    8.                     provideNode.Create(new Vector2(int.Parse(NodeData[5]), int.Parse(NodeData[6])));
    9.                     provideNode.name = NodeData[2];
    10.                     provideNode.varName = NodeData[3];
    11.                     provideNode.varValue = NodeData[4];
    12.  
    13.                     NodeList.Add(provideNode);
    14. .
    15. .(other types of nodes being added)
    16. .
    17. .(end of for loop)
    18.                     nodeCanvas.nodes = NodeList;
    19.  
    20.                     nodeCanvas.Validate();