E Story 故事编辑器开发笔记 #6 实现添加节点对话框

创建添加节点对话框类

  1. 打开UI文件夹,创建C#文件,命名为NodeCreationBox
  2. 打开NodeCreationBox.cs,将内容修改如下:
C#
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

namespace E.Story
{
    // 添加节点对话框
    public class NodeCreationBox : ScriptableObject, ISearchWindowProvider
    {
        private StoryGraphView graphViewer;
        private Texture2D indentationIcon;

        // 初始化
        public void Init(StoryGraphView viewer)
        {
            graphViewer = viewer;

            // 设置缩进图标
            indentationIcon = new Texture2D(1, 1);
            indentationIcon.SetPixel(0, 0, Color.clear);
            indentationIcon.Apply();
        }

        // 创建搜索树
        public List CreateSearchTree(SearchWindowContext context)
        {
            List searchTreeEntries = new()
            {
                // 标题
                new SearchTreeGroupEntry(new GUIContent("添加节点")),

                new SearchTreeEntry(new GUIContent("对话", indentationIcon))
                {
                    level = 1,
                    userData = NodeType.Dialogue
                },
                new SearchTreeEntry(new GUIContent("分支", indentationIcon))
                {
                    level = 1,
                    userData = NodeType.Branch
                },
                new SearchTreeEntry(new GUIContent("开始", indentationIcon))
                {
                    level = 1,
                    userData = NodeType.Start
                },
                new SearchTreeEntry(new GUIContent("结束", indentationIcon))
                {
                    level = 1,
                    userData = NodeType.End
                },
            };

            return searchTreeEntries;
        }

        // 当点击对话框某个按钮时
        public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
        {
            // 检测节点类型执行对应操作
            NodeType type = (NodeType)SearchTreeEntry.userData;
            switch (type)
            {
                case NodeType.Dialogue:
                case NodeType.Branch:
                case NodeType.Start:
                case NodeType.End:
                    graphViewer.CreateNode(SearchTreeEntry.content.text, type, Vector2.zero);
                    return true;

                default:
                    return false;
            }
        }
    }
}

实例化添加节点对话框类

  1. 打开StoryGraphView.cs,添加字段nodeCreationBox
C#
private NodeCreationBox nodeCreationBox;
  1. 新增以下方法
C#
// 添加添加节点对话框
private void AddNodeCreationBox()
{
    nodeCreationBox = ScriptableObject.CreateInstance();
    nodeCreationBox.Init(this);
}

// 当打开添加节点对话框时
private void OnOpenNodeCreationBox()
{
    // 定义请求事件
    nodeCreationRequest = context =>
    {
        // 打开搜索框
        SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), nodeCreationBox);
    };
}
  1. 调用方法
C#
// 构造器
public StoryGraphView(StoryEditorWindow window)
{
    /* ... 此处代码已省略 ... */

    // 调用方法
    AddNodeCreationBox();
    OnOpenNodeCreationBox();
}

简化上下文菜单

  1. 打开StoryGraphView.cs,修改BuildContextualMenu方法
C#
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
    base.BuildContextualMenu(evt);

    evt.menu.AppendAction("添加节点", action =>
    {
        // 获取光标当前屏幕位置
        Vector2 screenMousePosition = action.eventInfo.mousePosition + storyEditorWindow.position.position + new Vector2(50, 35);
        // 触发请求事件
        nodeCreationRequest(new NodeCreationContext
        {
            screenMousePosition = screenMousePosition,
            index = -1
        });
    });
}

使节点创建在光标点击位置

  1. 打开StoryGraphView.cs,新增GetLocalMousePosition方法
C#
// 获取本地鼠标坐标
public Vector2 GetLocalMousePosition(Vector2 screenMousePosition)
{
    // 将光标的屏幕坐标转换为光标在当前窗口内的坐标
    Vector2 windowMousePosition = screenMousePosition - storyEditorWindow.position.position;
    // 将光标在当前窗口内的坐标转换为光标在节点视图内的坐标
    Vector2 localMousePosition = contentViewContainer.WorldToLocal(windowMousePosition);
    return localMousePosition;
}
  1. 打开NodeCreationBox.cs,修改OnSelectEntry方法
C#
// 当点击对话框某个按钮时
public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
{
    // 获取本地点击坐标
    Vector2 localMousePostion = graphViewer.GetLocalMousePosition(context.screenMousePosition);

    // 检测节点类型执行对应操作
    NodeType type = (NodeType)SearchTreeEntry.userData;
    switch (type)
    {
        case NodeType.Dialogue:
        case NodeType.Branch:
        case NodeType.Start:
        case NodeType.End:
            graphViewer.CreateNode(SearchTreeEntry.content.text, type, localMousePostion);
            return true;

        default:
            return false;
    }
}

修改默认添加的节点

  1. 打开StoryGraphView.cs,修改AddDefaultNodes方法
C#
// 添加默认节点
private void AddDefaultNodes()
{
    CreateNode("开始", NodeType.Start, new Vector2(200, 200));
    CreateNode("结束", NodeType.End, new Vector2(800, 200));
}

测试效果

最终窗口效果如下:

相关链接

留下评论