当前位置: 首页 > 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

相关文章:

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

前言 在Unity3D游戏开发中&#xff0c;节点编辑器是一种强大的工具&#xff0c;它允许开发者以可视化的方式创建和编辑复杂的逻辑和流程。Unity提供了一个强大的UI工具包——GraphView&#xff0c;它使得创建自定义节点编辑器变得相对简单。本文将详细介绍如何使用GraphView实…...

【C++】开源:Armadillo数值计算库配置与使用

😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍Armadillo数值计算库配置与使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下次更新不迷路🥞 文章目录 :smirk:1. Armadillo介绍:blush:2. 环境配置:s…...

HackMyVM-Airbind靶机的测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、Getshell 3、提权 使用ipv6绕过iptables 四、结论 一、测试环境 1、系统环境 渗透机&#xff1a;kali2021.1(192.168.101.127) 靶 机&#xff1a;debian(192.168.101.11…...

C语言----函数

目录 1. 定义&#xff1a; 2.三要素 3.格式 4. 函数声明 5. 函数调用 6.函数传参 6.1. 值传递 6.2. 地址传递 6.3. 数组传递 string函数族 1.strcpy 2. strlen 3. strcat 4.strcmp 递归函数 1. 定义&#xff1a; 一个完成特定功能的代码模块 2.三要素 功能、…...

MySQL图形化界面工具--DataGrip

之前介绍了在命令行进行操作&#xff0c;但是不够直观&#xff0c;本次介绍图形化界面工具–DataGrip。 安装DataGrip 官网链接&#xff1a;官网下载链接 常规的软件安装流程。 参考链接&#xff1a;DataGrip安装 使用DataGrip 添加数据源&#xff1a; 第一次使用最下面会…...

PyTorch AMP 混合精度中grad_scaler.py的scale函数解析

PyTorch AMP 混合精度中的 scale 函数解析 混合精度训练&#xff08;AMP, Automatic Mixed Precision&#xff09;是深度学习中常用的技术&#xff0c;用于提升训练效率并减少显存占用。在 PyTorch 的 AMP 模块中&#xff0c;GradScaler 类负责动态调整和管理损失缩放因子&…...

【Ubuntu20.04】Apollo10.0 Docker容器部署+常见错误解决

官方参考文档【点击我】 Apollo 10.0 版本开始&#xff0c;支持本机和Docker容器两种部署方式。 如果您使用本机部署方式&#xff0c;建议使用x86_64架构的Ubuntu 22.04操作系统或者aarch64架构的Ubuntu 20.04操作系统。 如果您使用Docker容器部署方式&#xff0c;可以使用x…...

【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(二)

****非斜体正文为原文献内容&#xff08;也包含笔者的补充&#xff09;&#xff0c;灰色块中是对文章细节的进一步详细解释&#xff01; 3.1.2 基于注意力的解释&#xff08;Attention-Based Explanation&#xff09; 注意力机制可以揭示输入数据中各个部分之间的关系&#…...

朱姆沃尔特隐身战舰:从失败到威慑

前言 "朱姆沃尔特"号驱逐舰是美国海军雄心勃勃的项目&#xff0c;旨在重塑未来海战。它融合了隐身、自动化和强大火力&#xff0c;然而由于技术问题和预算超支&#xff0c;原计划建造32艘的目标被大幅缩减&#xff0c;最终只建造了三艘。该舰的设计特点包括“穿浪逆船…...

免费分享 | 基于极光优化算法PLO优化宽度学习BLS实现光伏数据预测算法研究附Matlab代码

研究内容 宽度学习系统&#xff08;BLS&#xff09;简介&#xff1a; BLS是一种新型的神经网络结构&#xff0c;由增强节点&#xff08;Enhancement Nodes, ENs&#xff09;和特征节点&#xff08;Feature Nodes, FNs&#xff09;组成&#xff0c;具有结构简单、训练速度快、泛…...

logback日志文件多环境配置路径

项目中遇到问题&#xff0c;springboot项目 本地jar包部署到现场后&#xff0c;经常遇到现场的日志存放的路径会更改&#xff0c;经过查阅&#xff0c;有两种方式&#xff0c;下面简单说明一下。 一、第一种 启动jar包时 添加参数 --logging.configF:\hgtest\config\logback.x…...

面试高频:一致性hash算法

这两天看到技术群里&#xff0c;有小伙伴在讨论一致性hash算法的问题&#xff0c;正愁没啥写的题目就来了&#xff0c;那就简单介绍下它的原理。下边我们以分布式缓存中经典场景举例&#xff0c;面试中也是经常提及的一些话题&#xff0c;看看什么是一致性hash算法以及它有那些…...

docker部署项目

docker部署项目 &#xff08;加载tar包&#xff1a;docker image load -i mysql.tar&#xff09; 一、jdk环境配置 1.jdk下载地址 --Java Archive | Oracle 中国 --选择好版本进入 --下载Linux x64 Compressed Archive的链接 2.解压 --创建文件夹&#xff1a;mkdir /ro…...

每天40分玩转Django:Django Celery

Django Celery 一、知识要点概览表 模块知识点掌握程度要求Celery基础配置、任务定义、任务执行深入理解异步任务任务状态、结果存储、错误处理熟练应用周期任务定时任务、Crontab、任务调度熟练应用监控管理Flower、任务监控、性能优化理解应用 二、基础配置实现 1. 安装和…...

df.groupby(pd.Grouper(level=1)).sum()

df.groupby(pd.Grouper(level1)).sum() 在 Python 中的作用是根据 DataFrame 的某一索引级别进行分组&#xff0c;并计算每个分组的总和。具体来说&#xff1a; df.groupby(...)&#xff1a;这是 pandas 的分组操作&#xff0c;按照指定的规则将 DataFrame 分组。 pd.Grouper(…...

运动控制探针功能详细介绍(CODESYS+SV63N伺服)

汇川AM400PLC和禾川X3E伺服EtherCAT通信 汇川AM400PLC和禾川X3E伺服EtherCAT通信_汇川ethercat通信-CSDN博客文章浏览阅读1.2k次。本文详细介绍了如何使用汇川AM400PLC通过EtherCAT总线与禾川X3E伺服进行通信。包括XML硬件描述文件的下载与安装,EtherCAT总线的启用,从站添加…...

C语言基础18(GDB调试)

文章目录 GDBGDB概述什么是GDB**GDB**的主要功能 GDB的启动GDB常见的启动方式 GDB的退出GDB的常用命令GDB查看源代码指令———list(1)**GDB** 查看设置**------info****GDB** 查看内存**GDB** 设置断点**---break (b)****GDB** 设置观察点**---watch****GDB** 程序调试 GDB完整…...

《向量数据库指南》——应对ElasticSearch挑战,拥抱Mlivus Cloud的新时代

在当今数据驱动的商业环境中,向量数据库的应用正变得愈加重要。随着人工智能和机器学习的快速发展,尤其是在自然语言处理、图像识别及推荐系统等领域,向量数据库以其强大的存储和检索能力,迎来了广泛的应用机会。然而,在实际应用中,企业在选择和实施向量数据库方案时,常…...

c++的stl库中stack的解析和模拟实现

目录 1.stack的介绍和使用 1.1stack的介绍 1.2stack的使用 2.stack的模拟实现 1.stack的介绍和使用 1.1stack的介绍 1. stack 是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 2. stac…...

C语言——字符函数和内存函数

目录 前言 字符函数 1strlen 模拟实现 2strcpy 模拟实现 3strcat 模拟实现 4strcmp 模拟实现 5strncpy 模拟实现 6strncat 模拟实现 7strncmp 模拟实现 8strstr 模拟实现 9strtok 10strerror 11大小写字符转换函数 内存函数 1memcpy 模拟实现 2…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...

MeshGPT 笔记

[2311.15475] MeshGPT: Generating Triangle Meshes with Decoder-Only Transformers https://library.scholarcy.com/try 真正意义上的AI生成三维模型MESHGPT来袭&#xff01;_哔哩哔哩_bilibili GitHub - lucidrains/meshgpt-pytorch: Implementation of MeshGPT, SOTA Me…...

嵌入式面试常问问题

以下内容面向嵌入式/系统方向的初学者与面试备考者,全面梳理了以下几大板块,并在每个板块末尾列出常见的面试问答思路,帮助你既能夯实基础,又能应对面试挑战。 一、TCP/IP 协议 1.1 TCP/IP 五层模型概述 链路层(Link Layer) 包括网卡驱动、以太网、Wi‑Fi、PPP 等。负责…...