本帖最后由 龙哥的秘密花园 于 2023-11-19 16:58 编辑
本帖最后由 龙哥的秘密花园 于 2023-11-19 16:48 编辑
在“Assets”下创建文件夹“龙哥的秘密花园/图视图”,并创建两个脚本文件起名为“分拆视图”“龙哥的秘密花园视图”
在“图视图”文件夹下鼠标右键“Create/UI toolkit/Style Sheet”创建样式起名为“龙哥的秘密花园样式”
再次创建“Create/UI toolkit/UI Document”创建UXML起名为“龙哥的秘密花园UXML”
在“图视图”文件夹下创建“Editor”并将刚创建的文件放到该文件夹下
在该文件下创建C#脚本起名为“路径”,选中右键“龙哥的秘密花园UXML”点击“Copy Path”粘贴到UXML路径字符串下
再次选中右键“龙哥的秘密花园样式”点击“Copy Path”粘贴到“样式路径”字符串下
打开“分拆视图”脚本 -> 保存
打开“龙哥的秘密花园视图” 保存
在“Editor”文件夹下 双击“龙哥的秘密花园UXML”弹出“UI Bulider”刚刚创建的两个脚本“分拆视图”
“龙哥的秘密花园视图”在“Project”下,根据命名空间下类名可以看到
简单的构建一下编辑器视图 在拖拽“分拆视图”时“Console”下会报错,这是因为“分拆视图”需要两个子控件,当添加后就不会报错了
创建C#脚本起名“编辑器窗口”保存
在标头中打开“龙哥的秘密花园/编辑器”弹出如下窗口
打开脚本“龙哥的秘密花园视图”在构造函数中添加一些控制器->保存回到Unity查看“编辑器窗口”
因为背景下无法准确观察到缩放这里将添加网格布局,双击“龙哥的秘密花园样式”保存
在“龙哥的秘密花园视图”也添加下面代码 保存回到Unity
如图
这里遇到到第一问题:矩形选择器(RectangleSelector
)的位置似乎和鼠标位置差了一个“分拆视图”下的左边控件距离,这里可以看出来矩形选择器(RectangleSelector
)是以父的坐标空间下位置。
解决方法:双击 ”龙哥的秘密花园视图“在“Hierarchy”找到“龙哥的秘密花园视图”,拖拽一个“VisualElement”。将“龙哥的秘密花园视图”添加到“VisualElement”。
保存重新打开“编辑器窗口”
现在该在“龙哥的秘密花园视图”下添加节点了
打开脚本“龙哥的秘密花园视图”
打开“编辑器窗口”在视图中鼠标右键 “创建节点”
当尝试连线时,无法连线, 这是因为没有重新连线规则,打开“龙哥的秘密花园视图”添加如下代码
namespace 龙哥的秘密花园.独特
{
public class 龙哥的秘密花园视图 : GraphView
{
public new class UxmlFactory : UxmlFactory<龙哥的秘密花园视图, UxmlTraits>{}
public 龙哥的秘密花园视图(){
Insert(0,new GridBackground());
//增加内容缩放,拖动,拖拽,框选控制器
this.AddManipulator(new ContentZoomer());
this.AddManipulator(new ContentDragger());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new RectangleSelector());
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(路径.样式路径));
this.graphViewChanged+=视图改变时;
}
/// <summary>
/// 用于处理移除 节点连接节点的逻辑
/// </summary>
/// <param name="graphViewChange"></param>
/// <returns></returns>
private GraphViewChange 视图改变时(GraphViewChange graphViewChange)
{
if (graphViewChange.elementsToRemove != null) {
graphViewChange.elementsToRemove.ForEach(elem => {
});
}
if (graphViewChange.edgesToCreate != null) {
graphViewChange.edgesToCreate.ForEach(edge => {
});
}
return graphViewChange;
}
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
{
//第1种写法
// List<Port> ports1=new();
// foreach (var item in ports){//遍历所有的端口
// //当前端口的方向不能和startPort的方向一致--->Input!=Input Output!=Output
// //当前端口的节点不能和startPort的节点一样
// if(item.direction!=startPort.direction&&item.node!=startPort.node)
// {
// ports1.Add(item);
// }
// }
//第二种写法:引用System.Linq
//ports.Where(endport=>endport.direction!=startPort.direction&&endport.node!=startPort.node).ToList();
return ports.Where(endport=>endport.direction!=startPort.direction&&endport.node!=startPort.node).ToList();
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
//base.BuildContextualMenu(evt);
evt.menu.AppendAction("创建节点",创建节点);
}
private Port 实例化端口(Node node,Orientation orientation,Direction direction,Port.Capacity capacity)
{
return node.InstantiatePort(orientation,direction,capacity,typeof(bool));
}
private void 创建节点(DropdownMenuAction action)
{
Node node=new Node();
node.title="节点";
var 输入= 实例化端口(node,Orientation.Vertical,Direction.Input,Port.Capacity.Single);
//
输入.portName="输入";
var 输出= 实例化端口(node,Orientation.Vertical,Direction.Output,Port.Capacity.Multi);
//
输出.portName="输出";
输出.portName="输出";
输入.portColor=new Color
(64/255,224/255f,208/255f,1);
输出.portColor=new Color
(64/255,224/255f,208/255f,1);
node.inputContainer.Add(输入);
node.outputContainer.Add(输出);
AddElement(node);
}
}
}
在“编辑器窗口”中就可以连接了,但是创建的节点视图位置并不是在鼠标位置下的,接下来继续实现节点视图的位置
public class 龙哥的秘密花园视图 : GraphView
{
public new class UxmlFactory : UxmlFactory<龙哥的秘密花园视图, UxmlTraits>{}public 龙哥的秘密花园视图(){
Insert(0,new GridBackground());
//增加内容缩放,拖动,拖拽,框选控制器
this.AddManipulator(new ContentZoomer());
this.AddManipulator(new ContentDragger());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new RectangleSelector());
styleSheets.Add(AssetDatabase.LoadAssetAtPath(路径.样式路径));
this.graphViewChanged+=视图改变时;}
///
/// 用于处理移除 节点连接节点的逻辑
///
///
///
private GraphViewChange 视图改变时(GraphViewChange graphViewChange)
{
if (graphViewChange.elementsToRemove != null) {
graphViewChange.elementsToRemove.ForEach(elem => {});}
if (graphViewChange.edgesToCreate != null) {
graphViewChange.edgesToCreate.ForEach(edge => {
});
}
return graphViewChange;}public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
{
//第1种写法
// List<Port> ports1=new();
// foreach (var item in ports){//遍历所有的端口
// //当前端口的方向不能和startPort的方向一致--->Input!=Input Output!=Output
// //当前端口的节点不能和startPort的节点一样
// if(item.direction!=startPort.direction&&item.node!=startPort.node)
// {
// ports1.Add(item);
// }
// }
//第二种写法:引用System.Linq
//ports.Where(endport=>endport.direction!=startPort.direction&&endport.node!=startPort.node).ToList();
return ports.Where(endport=>endport.direction!=startPort.direction&&endport.node!=startPort.node).ToList();
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
base.BuildContextualMenu(evt);
evt.menu.AppendAction("创建节点",创建节点);
}
private Port 实例化端口(Node node,Orientation orientation,Direction direction,Port.Capacity capacity)
{
return node.InstantiatePort(orientation,direction,capacity,typeof(bool));
}
private Vector2 mousepos=Vector2.zero;
private void 创建节点(DropdownMenuAction action)
{
Node node=new Node();
node.title="节点";
var 输入= 实例化端口(node,Orientation.Vertical,Direction.Input,Port.Capacity.Single);
//
输入.portName="输入";
var 输出= 实例化端口(node,Orientation.Vertical,Direction.Output,Port.Capacity.Multi);
//
输出.portName="输出";
输出.portName="输出";
输入.portColor=new Color
(64/255,224/255f,208/255f,1);
输出.portColor=new Color
(64/255,224/255f,208/255f,1);
node.inputContainer.Add(输入);
node.outputContainer.Add(输出);
node.SetPosition(new Rect(mousepos,new Vector2(150,200)));
AddElement(node);
}
/// <summary>
/// 在龙哥的秘密花园视图执行的所有事件都会调用这个方法
/// </summary>
/// <param name="evt"></param>
protected override void ExecuteDefaultAction(EventBase evt)
{
base.ExecuteDefaultAction(evt);
if(evt is MouseDownEvent 点击事件)
{
mousepos=点击事件.localMousePosition;//鼠标在当前目标坐标系中的位置。
}
}
}
}
嘿嘿还有一个问题没有解决,这个视频可以看到当我缩小视图时位置似乎又不对了
解决方法:需要重新计算当前坐标空间。
回到Unity,不管怎么缩放或者移动,都能准确的在鼠标点击的位置生成。
namespace 龙哥的秘密花园.独特
{
public class 龙哥的秘密花园视图 : GraphView
{
public new class UxmlFactory : UxmlFactory<龙哥的秘密花园视图, UxmlTraits>{}
public 龙哥的秘密花园视图(){
SetupZoom(ContentZoomer.DefaultMinScale,ContentZoomer.DefaultMaxScale);
Insert(0,new GridBackground());
//增加内容缩放,拖动,拖拽,框选控制器
this.AddManipulator(new ContentZoomer());
this.AddManipulator(new ContentDragger());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new RectangleSelector());
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(路径.样式路径));
this.graphViewChanged+=视图改变时;
}
/// <summary>
/// 用于处理移除 节点连接节点的逻辑
/// </summary>
/// <param name="graphViewChange"></param>
/// <returns></returns>
private GraphViewChange 视图改变时(GraphViewChange graphViewChange)
{
if (graphViewChange.elementsToRemove != null) {
graphViewChange.elementsToRemove.ForEach(elem => {
});
}
if (graphViewChange.edgesToCreate != null) {
graphViewChange.edgesToCreate.ForEach(edge => {
});
}
return graphViewChange;
}
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
{
//第1种写法
// List<Port> ports1=new();
// foreach (var item in ports){//遍历所有的端口
// //当前端口的方向不能和startPort的方向一致--->Input!=Input Output!=Output
// //当前端口的节点不能和startPort的节点一样
// if(item.direction!=startPort.direction&&item.node!=startPort.node)
// {
// ports1.Add(item);
// }
// }
//第二种写法:引用System.Linq
//ports.Where(endport=>endport.direction!=startPort.direction&&endport.node!=startPort.node).ToList();
return ports.Where(endport=>endport.direction!=startPort.direction&&endport.node!=startPort.node).ToList();
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
base.BuildContextualMenu(evt);
evt.menu.AppendAction("创建节点",(a)=>创建节点(a));
}
private Port 实例化端口(Node node,Orientation orientation,Direction direction,Port.Capacity capacity)
{
return node.InstantiatePort(orientation,direction,capacity,typeof(bool));
}
private Vector2 mousepos=Vector2.zero;
private void 创建节点(DropdownMenuAction action)
{
Node node=new Node();
node.title="节点";
var 输入= 实例化端口(node,Orientation.Vertical,Direction.Input,Port.Capacity.Single);
//
输入.portName="输入";
var 输出= 实例化端口(node,Orientation.Vertical,Direction.Output,Port.Capacity.Multi);
//
输出.portName="输出";
输出.portName="输出";
输入.portColor=new Color
(64/255,224/255f,208/255f,1);
输出.portColor=new Color
(64/255,224/255f,208/255f,1);
node.inputContainer.Add(输入);
node.outputContainer.Add(输出);
//mousepos= this.ChangeCoordinatesTo(contentViewContainer,mousepos);//或者使用这个拓展方法
mousepos= contentViewContainer.WorldToLocal(this.LocalToWorld(mousepos));//先将鼠标位置转换到“龙哥的秘密花园视图”的世界空间
//然后将鼠标在“龙哥的秘密花园视图”的世界空间转换到“contentViewContainer”的本地坐标空间
node.SetPosition(new Rect(mousepos,new Vector2(150,200)));
AddElement(node);
}
/// <summary>
/// 在龙哥的秘密花园视图执行的所有事件都会调用这个方法
/// </summary>
/// <param name="evt"></param>
protected override void ExecuteDefaultAction(EventBase evt)
{
base.ExecuteDefaultAction(evt);
if(evt is MouseDownEvent 点击事件)
{
mousepos=点击事件.localMousePosition;//鼠标在当前目标坐标系中的位置。
}
}
}
}