创建复制数据类
打开Data文件夹,创建C#文件,命名为CopyDatas,并将内容修改如下:
C#
using System.Collections.Generic;
using System;
namespace E.Story
{
// 复制数据
[Serializable]
public class CopyDatas
{
public List<NodeData> nodeDatas = new();
public List<GroupData> groupDatas = new();
}
}实现方法并调用
打开StoryGraphView.cs,新增以下方法:
C#
// 当复制元素时
private void OnCopyElements()
{
serializeGraphElements = (elements) =>
{
CopyDatas copyDatas = new();
foreach (GraphElement element in elements)
{
// 检测是否节点
if (element is BaseNode node)
{
// 过滤掉开始节点
if (node.Type == NodeType.Start)
{
continue;
}
NodeData nodeData = node.GetNodeData();
copyDatas.nodeDatas.Add(nodeData);
}
// 检测是否分组
else if (element is BaseGroup group)
{
GroupData groupData = group.GetGroupData();
copyDatas.groupDatas.Add(groupData);
}
}
// 序列化成字符串
string temp = JsonUtility.ToJson(copyDatas, true);
//Debug.Log(temp);
return temp;
};
}
// 当粘贴元素时
private void OnPasteElements()
{
unserializeAndPaste = (operationName, data) =>
{
ClearSelection();
// 将字符串反序列化
CopyDatas copyDatas = JsonUtility.FromJson<CopyDatas>(data);
// 创建字典,使新元素与旧ID匹配
Dictionary<GroupData, BaseGroup> pasteGroups = new();
Dictionary<NodeData, BaseNode> pasteNodes = new();
// 遍历所有分组数据,创建分组
foreach (GroupData groupData in copyDatas.groupDatas)
{
// 更新节点标题
string newTitle = groupData.Title;
// 偏移节点位置
Vector2 newPosition = groupData.Position + new Vector2(50, 50);
// 创建节点
BaseGroup group = CreateGroup(newTitle, newPosition, false);
// 加入字典
pasteGroups.Add(groupData, group);
}
// 遍历所有节点数据,创建节点
foreach (NodeData nodeData in copyDatas.nodeDatas)
{
// 更新节点标题
string newTitle = nodeData.Title;
// 偏移节点位置
Vector2 newPosition = nodeData.Position + new Vector2(50, 50);
// 创建节点
BaseNode node = CreateNode(newTitle, nodeData.Type, newPosition, null, false);
// 加入字典
pasteNodes.Add(nodeData, node);
// 复制节点信息
node.Note = nodeData.Note;
node.ChoiceDatas = DataUtility.CloneChoiceDatas(nodeData.ChoiceDatas);
// 检测节点类型并获取特定变量值
if (node.Type == NodeType.Dialogue)
{
DialogueNode dNode = node as DialogueNode;
dNode.RoleName = nodeData.RoleName;
dNode.SentenceDatas = DataUtility.CloneSentenceDatas(nodeData.SentenceDatas);
}
// 绘制节点
node.Draw();
}
// 遍历所有节点
foreach (KeyValuePair<NodeData, BaseNode> pasteNode in pasteNodes)
{
NodeData nodeData = pasteNode.Key;
BaseNode node = pasteNode.Value;
// 更新分组信息
if (!string.IsNullOrEmpty(nodeData.GroupID))
{
foreach (GroupData id in pasteGroups.Keys)
{
if (nodeData.GroupID == id.GUID)
{
pasteGroups[id].AddElement(node);
node.Title = nodeData.Title;
break;
}
}
}
// 创建连线
foreach (Port outputPort in node.outputContainer.Children())
{
ChoiceData choiceData = (ChoiceData)outputPort.userData;
if (string.IsNullOrEmpty(choiceData.NextNodeID))
{
continue;
}
// 获取下个节点的数据
NodeData nextNodeData = pasteNodes.Keys.FirstOrDefault(x => x.GUID == choiceData.NextNodeID);
if (nextNodeData == null)
{
choiceData.NextNodeID = "";
continue;
}
// 获取下个节点的输入端口
BaseNode nextNode = pasteNodes[nextNodeData];
Port nextNodeInputPort = (Port)nextNode.inputContainer.Children().First();
// 记录GUID
choiceData.NextNodeID = nextNode.GUID;
// 创建连线
CreateEdge(outputPort, nextNodeInputPort);
}
node.RefreshPorts();
}
};
}调用方法
C#
public StoryGraphView(StoryEditorWindow window)
{
/* ... 此处代码已省略 ... */
OnCopyElements();
OnPasteElements();
}测试效果
最终窗口效果如下:

相关链接
- 完整代码:https://gitee.com/helloestar/e-story/wikis/DevelopNotes/14
- 视频版本:制作中……


