Gameplay Ingredients是一组用于 Unity 游戏的运行时和编辑器工具:一组脚本的集合,可在制作游戏和原型时简化简单的任务。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

216 行
4.8 KiB

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;
using Unity.Jobs;
using System.Linq;
namespace GraphProcessor
{
[Serializable]
public abstract class BaseNode
{
public virtual string name => GetType().Name;
//id
public string GUID;
public int computeOrder = -1;
public bool canProcess = true;
[NonSerialized]
public readonly NodeInputPortContainer inputPorts;
[NonSerialized]
public readonly NodeOutputPortContainer outputPorts;
//Node view datas
public Rect position;
public bool expanded;
public delegate void ProcessDelegate();
public event ProcessDelegate onProcessed;
[NonSerialized]
public Dictionary< string, NodeFieldInformation > nodeFields = new Dictionary< string, NodeFieldInformation >();
public class NodeFieldInformation
{
public string name;
public string fieldName;
public FieldInfo info;
public bool input;
public bool isMultiple;
public NodeFieldInformation(FieldInfo info, string name, bool input, bool isMultiple)
{
this.input = input;
this.isMultiple = isMultiple;
this.info = info;
this.name = name;
this.fieldName = info.Name;
}
}
public static BaseNode CreateFromType(Type nodeType, Vector2 position)
{
if (!nodeType.IsSubclassOf(typeof(BaseNode)))
return null;
var node = Activator.CreateInstance(nodeType) as BaseNode;
node.position = new Rect(position, new Vector2(100, 100));
node.OnNodeCreated();
return node;
}
#region Initialization
protected BaseNode()
{
InitializeInOutDatas();
Enable();
inputPorts = new NodeInputPortContainer(this);
outputPorts = new NodeOutputPortContainer(this);
foreach (var nodeFieldKP in nodeFields)
{
AddPort(nodeFieldKP.Value.input, nodeFieldKP.Value.fieldName);
}
}
~BaseNode()
{
Disable();
}
/// <summary>
/// Called only when the node is created, not when instantiated
/// </summary>
public virtual void OnNodeCreated()
{
GUID = Guid.NewGuid().ToString();
}
void InitializeInOutDatas()
{
var fields = GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in fields)
{
var inputAttribute = field.GetCustomAttribute< InputAttribute >();
var outputAttribute = field.GetCustomAttribute< OutputAttribute >();
bool isMultiple = false;
bool input = false;
string name = field.Name;
if (inputAttribute == null && outputAttribute == null)
continue ;
//check if field is a collection type
isMultiple = (inputAttribute != null) ? inputAttribute.allowMultiple : false;
input = inputAttribute != null;
if (!String.IsNullOrEmpty(inputAttribute?.name))
name = inputAttribute.name;
if (!String.IsNullOrEmpty(outputAttribute?.name))
name = outputAttribute.name;
nodeFields[field.Name] = new NodeFieldInformation(field, name, input, isMultiple);
}
}
#endregion
#region Events and Processing
public void OnEdgeConnected(SerializableEdge edge)
{
bool input = edge.inputNode == this;
NodePortContainer portCollection = (input) ? (NodePortContainer)inputPorts : outputPorts;
portCollection.Add(edge);
}
public void OnEdgeDisonnected(SerializableEdge edge)
{
if (edge == null)
return ;
bool input = edge.inputNode == this;
NodePortContainer portCollection = (input) ? (NodePortContainer)inputPorts : outputPorts;
portCollection.Remove(edge);
}
public void OnProcess()
{
inputPorts.PullDatas();
Process();
onProcessed?.Invoke();
outputPorts.PushDatas();
}
protected virtual void Enable() {}
protected virtual void Disable() {}
protected virtual void Process() {}
#endregion
#region API and utils
public void AddPort(bool input, string fieldName)
{
if (input)
inputPorts.Add(new NodePort(this, fieldName));
else
outputPorts.Add(new NodePort(this, fieldName));
}
public void RemovePort(bool input, NodePort port)
{
if (input)
inputPorts.Remove(port);
else
outputPorts.Remove(port);
}
public void RemovePort(bool input, string fieldName)
{
if (input)
inputPorts.RemoveAll(p => p.fieldName == fieldName);
else
outputPorts.RemoveAll(p => p.fieldName == fieldName);
}
public IEnumerable< BaseNode > GetInputNodes()
{
foreach (var port in inputPorts)
foreach (var edge in port.GetEdges())
yield return edge.outputNode;
}
public IEnumerable< BaseNode > GetOutputNodes()
{
foreach (var port in outputPorts)
foreach (var edge in port.GetEdges())
yield return edge.inputNode;
}
public NodePort GetPort(string fieldName)
{
return inputPorts.Concat(outputPorts).FirstOrDefault(p => p.fieldName == fieldName);
}
#endregion
}
}