目录
设置输出端口所需数据结构
创建选项数据类
- 打开Data文件夹,创建C#文件,命名为
ChoiceData
- 打开ChoiceData.cs,将内容修改如下:
C#
using System;
using UnityEngine;
namespace E.Story
{
// 选项数据
[Serializable]
public class ChoiceData
{
[SerializeField] private string text;
[SerializeField] private string nextNodeID;
// 选项文本
public string Text { get => text; set => text = value; }
// 节点GUID
public string NextNodeID { get => nextNodeID; set => nextNodeID = value; }
// 构造器
public ChoiceData(string text)
{
this.text = text;
}
}
}
修改基类节点
- 打开BaseNode.cs,新增以下属性:
C#
// 选项数据列表
public List ChoiceDatas { get; set; }
- 修改以下方法:
C#
// 初始化节点
public virtual void Init(StoryGraphView graphView, string title, Vector2 position)
{
/* ... 此处代码已省略 ... */
ChoiceDatas = new() { new("下个节点") };
}
// 绘制输出容器
public virtual void DrawOutputContainer()
{
// 遍历选项视图列表,创建对应端口
for (int i = 0; i < ChoiceDatas.Count; i++)
{
ChoiceData choiceData = ChoiceDatas[i];
output = this.CreatePort(choiceData.Text);
output.userData = choiceData;
outputContainer.Add(output);
}
}
创建中间派生类
创建单进单出节点类
- 打卡UI Node文件夹,创建C#文件,命名为
SingleInSingleOutNode
- 打开SingleInSingleOutNode.cs,将内容修改如下:
C#
using UnityEditor.Experimental.GraphView;
using UnityEngine;
namespace E.Story
{
// 单进单出节点
public class SingleInSingleOutNode : BaseNode
{
public override void Init(StoryGraphView graphView, string title, Vector2 position)
{
base.Init(graphView, title, position);
// 重设属性默认值
Type = NodeType.SingleInSingleOut;
}
}
}
创建单进多出节点类
- 继续创建C#文件,命名为
SingleInMultiOutNode
- 打开SingleInMultiOutNode.cs,将内容修改如下:
C#
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace E.Story
{
// 单进多出节点
public class SingleInMultiOutNode : BaseNode
{
public override void Init(StoryGraphView graphView, string title, Vector2 position)
{
base.Init(graphView, title, position);
// 重设属性默认值
Type = NodeType.SingleInMultiOut;
// 清除并添加默认选项
ChoiceDatas.Clear();
ChoiceDatas.Add(new("选项文本"));
}
protected override void DrawOutputContainer()
{
// 遍历选项视图列表,创建对应端口
for (int i = 0; i < ChoiceDatas.Count; i++)
{
ChoiceData choiceData = ChoiceDatas[i];
output = CreateOutputPort(choiceData);
outputContainer.Add(output);
}
}
protected override void DrawExtensionContainer()
{
// 创建添加选项按钮
Button btnAdd = ElementUtility.CreateButton("添加选项", () =>
{
ChoiceData choiceData = new("选项文本");
ChoiceDatas.Add(choiceData);
output = CreateOutputPort(choiceData);
outputContainer.Add(output);
});
// 放置UI元素
extensionContainer.Add(btnAdd);
RefreshExpandedState();
}
// 创建选项端口
private Port CreateOutputPort(object userData)
{
// 获取选项数据
ChoiceData choiceData = (ChoiceData)userData;
// 创建输出接口
Port outputPort = this.CreatePort();
// 创建删除按钮
Button btnDelete = ElementUtility.CreateButton("X", () =>
{
if(ChoiceDatas.Count == 1)
{
Debug.LogWarning("需至少保留一条选项");
return;
}
ChoiceDatas.Remove(choiceData);
graphView.RemoveElement(outputPort);
});
// 创建选项文本框
TextField tfdChoice = ElementUtility.CreateTextField(choiceData.Text, null, callback =>
{
choiceData.Text = callback.newValue;
});
// 放置UI元素
outputPort.Add(btnDelete);
outputPort.Add(tfdChoice);
return outputPort;
}
}
}
创建单进零出节点类
- 继续创建C#文件,命名为
SingleInZeroOutNode
- 打开SingleInZeroOutNode.cs,将内容修改如下:
C#
using UnityEngine;
namespace E.Story
{
// 单进零出节点
public class SingleInZeroOutNode : BaseNode
{
public override void Init(StoryGraphView graphView, string title, Vector2 position)
{
base.Init(graphView, title, position);
// 重设属性默认值
Type = NodeType.SingleInZeroOut;
// 清除默认选项
ChoiceDatas.Clear();
}
public override void Draw()
{
DrawMainContainer();
DrawTitleContainer();
DrawTitleButtonContainer();
DrawTopContainer();
DrawInputContainer();
DrawExtensionContainer();
}
}
}
创建零进单出节点类
- 继续创建C#文件,命名为
ZeroInSingleOutNode
- 打开ZeroInSingleOutNode.cs,将内容修改如下:
C#
using UnityEngine;
namespace E.Story
{
// 零进单出节点
public class ZeroInSingleOutNode : BaseNode
{
public override void Init(StoryGraphView graphView, string title, Vector2 position)
{
base.Init(graphView, title, position);
// 重设属性默认值
Type = NodeType.ZeroInSingleOut;
}
public override void Draw()
{
DrawMainContainer();
DrawTitleContainer();
DrawTitleButtonContainer();
DrawTopContainer();
DrawOutputContainer();
DrawExtensionContainer();
}
}
}
扩展上下文菜单
打开StoryGraphView.cs,修改以下方法:
C#
// 创建节点
public BaseNode CreateNode(string title, NodeType type, Vector2 position)
{
// 获取类型
Type nodeType = Type.GetType($"E.Story.{type}Node");
// 创建对应节点
BaseNode node = Activator.CreateInstance(nodeType) as BaseNode;
node.Init(this, title, position);
node.Draw();
AddElement(node);
return node;
}
// 添加默认节点
private void AddDefaultNodes()
{
CreateNode("节点", NodeType.Base, new Vector2(200, 200));
}
// 构建上下文菜单
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
base.BuildContextualMenu(evt);
// 点击按钮实现添加新节点
evt.menu.AppendAction("添加节点", action =>
{
CreateNode("节点", NodeType.Base, Vector2.zero);
});
evt.menu.AppendAction("添加单进单出节点", action =>
{
CreateNode("单进单出节点", NodeType.SingleInSingleOut, Vector2.zero);
});
evt.menu.AppendAction("添加单进多出节点", action =>
{
CreateNode("单进多出节点", NodeType.SingleInMultiOut, Vector2.zero);
});
evt.menu.AppendAction("添加单进零出节点", action =>
{
CreateNode("单进零出节点", NodeType.SingleInZeroOut, Vector2.zero);
});
evt.menu.AppendAction("添加零进单出节点", action =>
{
CreateNode("零进单出节点", NodeType.ZeroInSingleOut, Vector2.zero);
});
}
测试效果
打开插件窗口,最终效果如下:
