UI toolkit构建节点编辑器(视图界面)
本帖最后由 龙哥的秘密花园 于 2023-11-19 16:58 编辑> 本帖最后由 龙哥的秘密花园 于 2023-11-19 16:48 编辑
在“Assets”下创建文件夹“龙哥的秘密花园/图视图”,并创建两个脚本文件起名为“分拆视图”“龙哥的秘密花园视图”
!(data/attachment/forum/202311/19/130830kmhodxxix79z7vmm.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119115626.png")
在“图视图”文件夹下鼠标右键“Create/UI toolkit/Style Sheet”创建样式起名为“龙哥的秘密花园样式”
再次创建“Create/UI toolkit/UI Document”创建UXML起名为“龙哥的秘密花园UXML”
在“图视图”文件夹下创建“Editor”并将刚创建的文件放到该文件夹下
!(data/attachment/forum/202311/19/131053cro8bn35g5gtop4w.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119121940.png")
在该文件下创建C#脚本起名为“路径”,选中右键“龙哥的秘密花园UXML”点击“Copy Path”粘贴到UXML路径字符串下
再次选中右键“龙哥的秘密花园样式”点击“Copy Path”粘贴到“样式路径”字符串下
!(data/attachment/forum/202311/19/131616gdnwhqh9hz55aohu.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119122734.png")
打开“分拆视图”脚本 -> 保存!(data/attachment/forum/202311/19/132007q7zu7okfx2wxiqbk.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119123406.png")
打开“龙哥的秘密花园视图” 保存!(data/attachment/forum/202311/19/132211myou7g0vv57n0o77.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119124023.png")
!(data/attachment/forum/202311/19/132107i2kg5zcfgjzfwswf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119123716.png")
在“Editor”文件夹下 双击“龙哥的秘密花园UXML”弹出“UI Bulider”刚刚创建的两个脚本“分拆视图”
“龙哥的秘密花园视图”在“Project”下,根据命名空间下类名可以看到
!(data/attachment/forum/202311/19/132242e4zo13ovt18mp8ss.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119124023.png")
简单的构建一下编辑器视图在拖拽“分拆视图”时“Console”下会报错,这是因为“分拆视图”需要两个子控件,当添加后就不会报错了
!(data/attachment/forum/202311/19/132553k9p9ul2z9lrsd7lp.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119124716.png")
创建C#脚本起名“编辑器窗口”保存
!(data/attachment/forum/202311/19/132644svrrw22hhve2psoe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119125526.png")
在标头中打开“龙哥的秘密花园/编辑器”弹出如下窗口
!(data/attachment/forum/202311/19/132952k9hqbqyhlzhj9jhh.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119125638.png")
!(data/attachment/forum/202311/19/132955xeep8pesi8xvxpvu.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119125814.png")
打开脚本“龙哥的秘密花园视图”在构造函数中添加一些控制器->保存回到Unity查看“编辑器窗口”
!(data/attachment/forum/202311/19/133134wgkppwpknynkett7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119130226.png")
因为背景下无法准确观察到缩放这里将添加网格布局,双击“龙哥的秘密花园样式”保存
!(data/attachment/forum/202311/19/133543hiiyz9dd5g9vc3r0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119133524.png")
在“龙哥的秘密花园视图”也添加下面代码 保存回到Unity
!(data/attachment/forum/202311/19/133753zzudwcr8m84xwcg7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119133739.png")
如图!(data/attachment/forum/202311/19/134123b5ucbbfb5ji5xl4z.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119134118.png")
这里遇到到第一问题:矩形选择器(`RectangleSelector`)的位置似乎和鼠标位置差了一个“分拆视图”下的左边控件距离,这里可以看出来矩形选择器(`RectangleSelector`)是以父的坐标空间下位置。
!(data/attachment/forum/?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ录屏20231119134521.mp4")
解决方法:双击 ”龙哥的秘密花园视图“在“Hierarchy”找到“龙哥的秘密花园视图”,拖拽一个“VisualElement”。将“龙哥的秘密花园视图”添加到“VisualElement”。
!(data/attachment/forum/202311/19/135449t857o768zwqo3zoo.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119135440.png")
保存重新打开“编辑器窗口”
!(data/attachment/forum/?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ录屏20231119135620.mp4")
现在该在“龙哥的秘密花园视图”下添加节点了
打开脚本“龙哥的秘密花园视图”
!(data/attachment/forum/202311/19/141159jeef9usgbg98ffkv.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119141142.png")
打开“编辑器窗口”在视图中鼠标右键 “创建节点”
!(data/attachment/forum/202311/19/141331eeqzmomyott8ev73.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")
当尝试连线时,无法连线, 这是因为没有重新连线规则,打开“龙哥的秘密花园视图”添加如下代码
```
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;//鼠标在当前目标坐标系中的位置。
}
}
}
}
嘿嘿还有一个问题没有解决,这个视频可以看到当我缩小视图时位置似乎又不对了
!(data/attachment/forum/?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ录屏20231119162322.mp4")
解决方法:需要重新计算当前坐标空间。
!(data/attachment/forum/202311/19/163235iuzp631ddzxy556x.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ截图20231119163224.png")
回到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;//鼠标在当前目标坐标系中的位置。
}
}
}
}
```
!(data/attachment/forum/?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "QQ录屏20231119165433.mp4")
赚积分 牛逼 赚积分
页:
[1]