当前位置: 首页 > news >正文

Unity3D 基于GraphView实现的节点编辑器框架详解

前言

在Unity3D游戏开发中,节点编辑器是一种强大的工具,它允许开发者以可视化的方式创建和编辑复杂的逻辑和流程。Unity提供了一个强大的UI工具包——GraphView,它使得创建自定义节点编辑器变得相对简单。本文将详细介绍如何使用GraphView实现一个节点编辑器框架,并提供技术详解和代码实现。

对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!

一、GraphView简介

GraphView是Unity提供的一个用于创建节点编辑器的UI组件。它允许开发者以图形化的方式展示和编辑节点及其连接。GraphView提供了丰富的API,使得开发者可以轻松地自定义节点、边、面板和工具栏等。

二、节点编辑器框架设计

在创建一个节点编辑器框架时,我们需要考虑以下几个关键部分:

  1. 节点(Node):节点是编辑器中的基本元素,它代表了一个可以执行特定操作的单元。每个节点都应该有一个唯一的标识符、一个标题、一个或多个输入/输出端口,以及用于显示和操作节点的UI元素。
  2. 边(Edge):边用于连接节点,表示节点之间的数据流或逻辑依赖关系。在GraphView中,边通常由两个端口(一个输入端口和一个输出端口)组成。
  3. 面板(Panel):面板是节点的容器,它提供了用于添加、删除和移动节点的界面。面板还可以包含工具栏、小地图等辅助工具。
  4. 工具栏(Toolbar):工具栏提供了用于创建新节点、保存和加载编辑器状态、撤销和重做操作等功能的按钮和菜单。
  5. 数据存储:为了持久化编辑器状态,我们需要将节点的数据和连接关系存储在一个可序列化的数据结构中。在Unity中,ScriptableObject是一个常用的选择。

三、技术详解

  1. 创建节点和边
  • 节点可以通过继承GraphView的Node类来创建。在节点类中,我们需要重写BuildContextualMenu方法来添加右键菜单项,如添加输入/输出端口、删除节点等。
  • 边可以通过GraphView的Edge类来创建。在创建边时,我们需要指定边的输入和输出端口,并处理边的绘制和连接逻辑。

  1. 管理节点和边的数据
  • 我们可以使用ScriptableObject来存储节点的数据和连接关系。每个节点可以有一个对应的ScriptableObject来存储其特定的数据。
  • 连接关系可以通过存储边的输入和输出端口的标识符来表示。

  1. 实现撤销和重做功能
  • 撤销和重做功能可以通过维护一个操作历史记录来实现。每次对编辑器进行更改时,都可以将更改作为一个操作添加到历史记录中。
  • 撤销操作可以回滚到历史记录中的上一个状态,重做操作可以恢复到下一个状态。

  1. 实现保存和加载功能
  • 保存功能可以将编辑器的当前状态序列化为一个文件或字符串,并保存到磁盘上。
  • 加载功能可以从磁盘上读取文件或字符串,并将其反序列化为编辑器的状态。

四、代码实现

以下是一个简单的节点编辑器框架的代码实现示例:

using UnityEngine;
using UnityEditor;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
// 定义一个用于存储节点数据的ScriptableObject
[CreateAssetMenu(fileName = "NewNodeGraph", menuName = "NodeGraph/NodeGraph")]
public class NodeGraph : ScriptableObject
{
// 存储节点和边的数据
public List<NodeBaseData> nodes = new List<NodeBaseData>();
public List<NodeLinkData> edges = new List<NodeLinkData>();
}
// 定义一个用于存储节点基础数据的类
[Serializable]
public abstract class NodeBaseData
{
public string GUID;
public string NodeName = "NodeBase";
public Rect Position = Rect.zero;
// 其他节点数据
}
// 定义一个用于存储边数据的类
[Serializable]
public class NodeLinkData
{
public string BaseNodeGUID;
public string OutputPortName;
public string TargetNodeGUID;
public string TargetPortName;
}
// 定义一个节点类,继承自GraphView的Node类
public class MyNode : Node
{
// 节点数据
public NodeBaseData nodeData;
// 构造函数
public MyNode()
{
// 设置节点标题和样式
title = "My Node";
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Packages/com.unity.uielements/Editor/Resources/Styles/GraphView.uss"));
// 添加输入/输出端口
var inputPort = new Port(Orientation.Horizontal, Direction.Input, Port.Capacity.Single, typeof(float));
inputPort.portName = "Input";
inputContainer.Add(inputPort);
var outputPort = new Port(Orientation.Horizontal, Direction.Output, Port.Capacity.Single, typeof(float));
outputPort.portName = "Output";
outputContainer.Add(outputPort);
// 添加右键菜单
this.RegisterCallback<MouseDownEvent>(OnMouseDown);
}
// 处理右键菜单事件
private void OnMouseDown(MouseDownEvent evt)
{
if (evt.button == MouseButton.RightMouse)
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Delete Node"), false, () => { DeleteNode(); });
menu.ShowAsContext();
evt.StopPropagation();
}
}
// 删除节点
private void DeleteNode()
{
// 从GraphView中移除节点
graphView.RemoveElement(this);
// 从NodeGraph中移除节点数据(需要自行实现)
}
}
// 定义一个节点视图类,继承自GraphView
public class MyGraphView : GraphView
{
// 构造函数
public MyGraphView(EditorWindow window, StyleSheet styleSheet)
{
this.styleSheets.Add(styleSheet);
this.AddManipulator(new ContextualMenuManipulator(OnContextualMenu));
this.AddManipulator(new SelectionDragManipulator());
this.AddManipulator(new RectangleSelector());
this.AddManipulator(new ZoomManipulator());
this.AddManipulator(new PanManipulator());
// 初始化节点和边(需要自行实现)
}
// 处理右键菜单事件
private void OnContextualMenu(ContextualMenuPopulateEvent evt)
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Create Node"), false, () => { CreateNode(); });
menu.ShowAsContext();
}
// 创建节点
private void CreateNode()
{
var newNode = new MyNode();
newNode.SetPosition(new Rect(mousePosition, Vector2.one * 100));
this.Add(newNode);
// 添加节点数据到NodeGraph中(需要自行实现)
}
}
// 定义一个编辑器窗口类,用于显示节点编辑器
public class NodeEditorWindow : EditorWindow
{
private MyGraphView graphView;
private NodeGraph nodeGraph;
// 构造函数
[MenuItem("Window/Node Editor")]
public static void ShowWindow()
{
var window = GetWindow<NodeEditorWindow>("Node Editor");
window.minSize = new Vector2(800, 600);
}
// 初始化编辑器窗口
private void OnEnable()
{
// 加载或创建NodeGraph
nodeGraph = AssetDatabase.LoadAssetAtPath<NodeGraph>("Assets/NodeGraphs/MyNodeGraph.asset");
if (nodeGraph == null)
{
nodeGraph = ScriptableObject.CreateInstance<NodeGraph>();
AssetDatabase.CreateAsset(nodeGraph, "Assets/NodeGraphs/MyNodeGraph.asset");
AssetDatabase.SaveAssets();
}
// 初始化GraphView
var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Packages/com.unity.uielements/Editor/Resources/Styles/GraphView.uss");
graphView = new MyGraphView(this, styleSheet);
graphView.StretchToParentSize();
rootVisualElement.Add(graphView);
// 初始化节点和边(根据nodeGraph加载数据)
// 需要自行实现
}
// 保存编辑器状态
private void OnDisable()
{
// 保存nodeGraph到磁盘(需要自行实现)
}
}

五、总结

本文介绍了如何使用Unity3D的GraphView组件创建一个简单的节点编辑器框架。我们详细讨论了节点编辑器框架的设计、技术实现和代码示例。通过自定义节点、边、面板和工具栏等组件,开发者可以轻松地创建出功能强大的节点编辑器,以满足游戏开发中的复杂需求。希望本文能为Unity3D开发者提供有价值的参考和指导。

更多教学视频

Unity3D​www.bycwedu.com/promotion_channels/2146264125

http://www.lryc.cn/news/515073.html

相关文章:

  • 【C++】开源:Armadillo数值计算库配置与使用
  • HackMyVM-Airbind靶机的测试报告
  • C语言----函数
  • MySQL图形化界面工具--DataGrip
  • PyTorch AMP 混合精度中grad_scaler.py的scale函数解析
  • 【Ubuntu20.04】Apollo10.0 Docker容器部署+常见错误解决
  • 【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(二)
  • 朱姆沃尔特隐身战舰:从失败到威慑
  • 免费分享 | 基于极光优化算法PLO优化宽度学习BLS实现光伏数据预测算法研究附Matlab代码
  • logback日志文件多环境配置路径
  • 面试高频:一致性hash算法
  • docker部署项目
  • 每天40分玩转Django:Django Celery
  • df.groupby(pd.Grouper(level=1)).sum()
  • 运动控制探针功能详细介绍(CODESYS+SV63N伺服)
  • C语言基础18(GDB调试)
  • 《向量数据库指南》——应对ElasticSearch挑战,拥抱Mlivus Cloud的新时代
  • c++的stl库中stack的解析和模拟实现
  • C语言——字符函数和内存函数
  • 查询docker overlay2文件夹下的 c7ffc13c49xxx是哪一个容器使用的
  • Golang的容器编排实践
  • 【51项目】51单片机自制小霸王游戏机
  • ArkTs之NAPI学习
  • 【数据库初阶】MySQL中表的约束(上)
  • 173. 矩阵距离 acwing -多路BFS
  • Linux下部署Redis集群 - 一主二从三哨兵模式
  • 实战设计模式之建造者模式
  • 活动预告 | Microsoft Azure 在线技术公开课:使用 Azure OpenAI 服务构建生成式应用
  • ubuntu安装firefox
  • 计算机网络原理(谢希仁第八版)第4章课后习题答案