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

245 行
6.2 KiB

using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
using UnityEditor;
using System.Reflection;
using System;
using System.Linq;
using UnityEditorInternal;
using StatusFlags = UnityEngine.Experimental.UIElements.DropdownMenu.MenuAction.StatusFlags;
using NodeView = UnityEditor.Experimental.UIElements.GraphView.Node;
namespace GraphProcessor
{
[NodeCustomEditor(typeof(BaseNode))]
public class BaseNodeView : NodeView
{
public BaseNode nodeTarget;
public List< Port > inputPorts = new List< Port >();
public List< Port > outputPorts = new List< Port >();
public BaseGraphView owner { private set; get; }
protected Dictionary< string, Port > portsPerFieldName = new Dictionary< string, Port >();
protected VisualElement controlsContainer;
protected VisualElement debugContainer;
Label computeOrderLabel = new Label();
#region Initialization
public void Initialize(BaseGraphView owner, BaseNode node)
{
nodeTarget = node;
this.owner = owner;
owner.computeOrderUpdated += ComputeOrderUpdatedCallback;
AddStyleSheetPath("GraphProcessorStyles/BaseNodeView");
InitializePorts();
InitializeView();
InitializeDebug();
Enable();
this.RefreshPorts();
}
void InitializePorts()
{
foreach (var fieldInfo in nodeTarget.nodeFields)
{
// This will automatically create our visual ports
PortBehaviorFactory.CreatePortBehavior(
this,
fieldInfo.Value.info,
fieldInfo.Value.input ? Direction.Input : Direction.Output,
owner.connectorListener,
fieldInfo.Value.isMultiple,
fieldInfo.Value.name
);
}
}
void InitializeView()
{
controlsContainer = new VisualElement{ name = "controls" };
mainContainer.Add(controlsContainer);
debugContainer = new VisualElement{ name = "debug" };
mainContainer.Add(debugContainer);
title = (string.IsNullOrEmpty(nodeTarget.name)) ? nodeTarget.GetType().Name : nodeTarget.name;
SetPosition(nodeTarget.position);
}
void InitializeDebug()
{
ComputeOrderUpdatedCallback();
debugContainer.Add(computeOrderLabel);
}
#endregion
#region API
public Port GetPortFromFieldName(string fieldName)
{
Port ret;
portsPerFieldName.TryGetValue(fieldName, out ret);
return ret;
}
public PortView AddPort(FieldInfo fieldInfo, Direction direction, EdgeConnectorListener listener, bool isMultiple = false, string name = null)
{
// TODO: hardcoded value
PortView p = new PortView(Orientation.Horizontal, direction, fieldInfo, listener);
if (p.direction == Direction.Input)
{
inputPorts.Add(p);
inputContainer.Add(p);
}
else
{
outputPorts.Add(p);
outputContainer.Add(p);
}
p.Initialize(this, isMultiple, name);
portsPerFieldName[p.fieldName] = p;
return p;
}
public void RemovePort(PortView p)
{
if (p.direction == Direction.Input)
{
inputPorts.Remove(p);
inputContainer.Remove(p);
}
else
{
outputPorts.Remove(p);
outputContainer.Remove(p);
}
portsPerFieldName.Remove(p.fieldName);
}
public void OpenNodeViewScript()
{
var scriptPath = NodeProvider.GetNodeViewScript(GetType());
if (scriptPath != null)
InternalEditorUtility.OpenFileAtLineExternal(scriptPath, 0);
}
public void OpenNodeScript()
{
var scriptPath = NodeProvider.GetNodeScript(nodeTarget.GetType());
if (scriptPath != null)
InternalEditorUtility.OpenFileAtLineExternal(scriptPath, 0);
}
#endregion
#region Callbacks & Overrides
void ComputeOrderUpdatedCallback()
{
//Update debug compute order
computeOrderLabel.text = "Compute order: " + nodeTarget.computeOrder;
}
public virtual void Enable()
{
DrawDefaultInspector();
}
public virtual void DrawDefaultInspector()
{
var fields = nodeTarget.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (var field in fields)
{
//skip if the field is not serializable
if (!field.IsPublic && field.GetCustomAttribute(typeof(SerializeField)) == null)
continue ;
//skip if the field is an input/output and not marked as SerializedField
if (field.GetCustomAttribute(typeof(SerializeField)) == null && (field.GetCustomAttribute(typeof(InputAttribute)) != null || field.GetCustomAttribute(typeof(OutputAttribute)) != null))
continue ;
//skip if marked with NonSerialized or HideInInspector
if (field.GetCustomAttribute(typeof(System.NonSerializedAttribute)) != null || field.GetCustomAttribute(typeof(HideInInspector)) != null)
continue ;
var controlLabel = new Label(field.Name);
controlsContainer.Add(controlLabel);
var element = FieldFactory.CreateField(field, field.GetValue(nodeTarget), (newValue) => {
field.SetValue(nodeTarget, newValue);
owner.RegisterCompleteObjectUndo("Updated " + newValue);
});
if (element != null)
controlsContainer.Add(element);
}
}
public virtual void OnPortConnected(PortView port) {}
public virtual void OnPortDisconnected(PortView port) {}
public override void SetPosition(Rect newPos)
{
base.SetPosition(newPos);
nodeTarget.position = newPos;
}
public override bool expanded
{
get { return base.expanded; }
set
{
base.expanded = value;
nodeTarget.expanded = value;
}
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
evt.menu.AppendAction("Open Node Script", (e) => OpenNodeScript(), OpenNodeScriptStatus);
evt.menu.AppendAction("Open Node View Script", (e) => OpenNodeViewScript(), OpenNodeViewScriptStatus);
}
StatusFlags OpenNodeScriptStatus(DropdownMenu.MenuAction action)
{
if (NodeProvider.GetNodeScript(nodeTarget.GetType()) != null)
return StatusFlags.Normal;
return StatusFlags.Disabled;
}
StatusFlags OpenNodeViewScriptStatus(DropdownMenu.MenuAction action)
{
if (NodeProvider.GetNodeViewScript(GetType()) != null)
return StatusFlags.Normal;
return StatusFlags.Disabled;
}
#endregion
}
}