E Story 故事编辑器开发笔记 #14 实现复制粘贴

创建复制数据类

打开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();
}

测试效果

最终窗口效果如下:

相关链接

留下评论