Gentlymad-Studios / NewGraph

A general node graph solution centered on data management. This is based on the idea to visualize complex data structures as graph networks without having to modify already established data classes.
MIT License
246 stars 19 forks source link

Implement additional inputs #34

Open DraconInteractive opened 11 months ago

DraconInteractive commented 11 months ago

Hi! I'm trying to make a system similar as to what can be seen in ShaderGraph, where you create 'value' nodes that can feed into your main nodes to provide variables and context.

My current setup is as follows (see relevant scripts at the bottom):

I have created a 'CoreNode' class that derives from INode. In this, I have added methods for tracking outputs and executing actions. All of my nodes derive from this CoreNode.

The focus here is my ANode_SetAnimParameter class. It takes a string for the parameter name, and a string for the parameter value that is then parsed depending to an enum value (to parse as float, int or bool).

My goal was to change the parameter value string into its own node that feeds into the set anim parameter node.

To do this I did the following:

To all first appearances, this seems to work. The ports are created properly, I can create the string node correctly, and connect them all up. However, as soon as I press play in the editor, the connections between the VNode_String nodes and the ANode_SetAnimParameter nodes are lost. All other connections maintain their links.

Any ideas why this is happening? I think maybe due to my use of the VNode_String type to the input port, however I do want to be able to restrict the port type so I dont accidently provide an int to a string input.

Appreciate your time / thoughts! VNode_String.txt ANode_SetAnimParameter.txt CoreNode.txt ValueNode.txt

DraconInteractive commented 11 months ago

I was unable to solve the issue by changing the valueInput to type CoreNode.

However, I was able to get a solution working by making the block holding the input data connect to an output node. This isnt great in terms of flow (since the output connects to data used as an input), but it will work for now.

I would still love to know if it is possible to create your own additional input nodes :)

Doppelkeks commented 9 months ago

Hi,

NewGraph is designed to represent reference trees, similar to UML graphs, therefor it was desgined in a way that the input represents the node itself and that there is a clear flow in one direction. With these design decisions in mind it is currently not planned to have a default ability to create multiple input nodes, however if this is really needed you might be able to cook something up with custom NodeEditors :)

billykatz commented 9 months ago

Port Attribute

@DraconInteractive This may be a naive solution as I just started to play around with the code. But the PortAttribute has a PortDirection init param that defaults to PortDirection.Output

public PortAttribute(string name=null) : base(name, Capacity.Single, PortDirection.Output) { } 

I changed it to the following and was able to get ports on the left side.

public PortAttribute(PortDirection direction=PortDirection.Output, string name=null) : base(name, Capacity.Single, direction) { } 
Screenshot 2024-02-20 at 9 53 55 AM

Custom Editor

This may be the correct path but I got tripped up, maybe @Doppelkeks can help? How can I access the serialized property thru the customer node editor?

// startCoord should be input and endCoord should be output
public class MoveTileAnimationNode : INode
{
    [SerializeReference]
    public TileCoord startCoord; // I want this coord to be input for this node
    [Port, SerializeReference] // DisplayType.BothViews visualizes this field both in the inspector and the node itself. 
    public TileCoord endCoord;
}

How can I access the property from the customer node editor?

[CustomNodeEditor(typeof(MoveTileAnimationNode))]
public class MoveTileAnimationNodeEditor : NodeEditor
{
    private SerializedProperty property;
    public override void Initialize(NodeController nodeController)
    {
       // this is how I would access it in a EditorWindow
       property = nodeController.GetSerializedObject().FindProperty("startCoord"); 
       // ^ returns null
    }
}

Usecase

My use case is that I would like to create an action graph that allows animators to define animations with modular blocks. If you think this is a bad usage of NewGraph then let me know, Im still looking for a solution and would rather not write the whole thing myself. Thanks!

noio commented 7 months ago

Came here looking for the same thing.

But looking at the way NewGraph is set up, it's pretty clear that this is outside its use case. (and i'm happy because that keeps things a lot simpler)

Nodes reference other nodes directly through their [Port] fields. I.e. the type of a [Port] fields is always INode.

No separate data is being kept on Edges. To have multiple input ports, you'd have to keep track of — and serialize — Edges as their own data type which would then break the nice symmetry between the [Serializable] Node classes and their visual representation.

You would no longer be able to just plop a few [Node] and [Port] attributes on an existing class and make them show up in the Graph View. (Because you'd always have to deal with explicit Edges)

Edit: thinking about it, you would probably even need a separate Port datatype! 🤪

e.g.

Node {
  List<Port> Ports
}

Port {
  Edge Edge
}

Edge {
  Port From
  Port To
}