Why when adding Handles.ArrowHandleCap to a line it's not drawing the ArrowHandleCap?

Viewed 1452

I'm using Editor Window maybe that's the problem ?

The idea is when connecting two nodes is also to make an arrow at the end position that will show the connecting flow direction.

In the screenshot when I'm connecting two nodes for example Window 0 to Window 1 So there should be an arrow at the end of the line near Window 1 showing indicating that Window 0 is connected to Window 1 so the flow is from Window 0 to Window 1.

But it's not drawing any ArrowHandleCap.

I don't mind to draw another simple white arrow at the end position but it's not working at all for now. Not drawing an arrow at all.

Nodes

This is my Editor Window code :

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using UnityEditor.Graphs;
using UnityEngine.UI;

public class NodeEditor : EditorWindow
{
    List<Rect> windows = new List<Rect>();
    List<int> windowsToAttach = new List<int>();
    List<int> attachedWindows = new List<int>();

    int tab = 0;
    float size = 10f;

    [MenuItem("Window/Node editor")]
    static void ShowEditor()
    {
        const int width = 600;
        const int height = 600;

        var x = (Screen.currentResolution.width - width) / 2;
        var y = (Screen.currentResolution.height - height) / 2;

        GetWindow<NodeEditor>().position = new Rect(x, y, width, height);
    }


    void OnGUI()
    {
        Rect graphPosition = new Rect(0f, 0f, position.width, position.height);
        GraphBackground.DrawGraphBackground(graphPosition, graphPosition);

        int selected = 0;
        string[] options = new string[]
        {
     "Option1", "Option2", "Option3",
        };
        selected = EditorGUILayout.Popup("Label", selected, options);

        if (windowsToAttach.Count == 2)
        {
            attachedWindows.Add(windowsToAttach[0]);
            attachedWindows.Add(windowsToAttach[1]);
            windowsToAttach = new List<int>();
        }

        if (attachedWindows.Count >= 2)
        {
            for (int i = 0; i < attachedWindows.Count; i += 2)
            {
                DrawNodeCurve(windows[attachedWindows[i]], windows[attachedWindows[i + 1]]);
            }
        }

        BeginWindows();

        if (GUILayout.Button("Create Node"))
        {
            windows.Add(new Rect(10, 10, 200, 40));
        }

        for (int i = 0; i < windows.Count; i++)
        {
            windows[i] = GUI.Window(i, windows[i], DrawNodeWindow, "Window " + i);
        }

        EndWindows();
    }


    void DrawNodeWindow(int id)
    {
        if (GUILayout.Button("Attach"))
        {
            windowsToAttach.Add(id);
        }

        GUI.DragWindow();
    }


    void DrawNodeCurve(Rect start, Rect end)
    {
        Vector3 startPos = new Vector3(start.x + start.width, start.y + start.height / 2, 0);
        Vector3 endPos = new Vector3(end.x, end.y + end.height / 2, 0);
        Vector3 startTan = startPos + Vector3.right * 50;
        Vector3 endTan = endPos + Vector3.left * 50;
        Color shadowCol = new Color(255, 255, 255);

        for (int i = 0; i < 3; i++)
        {// Draw a shadow
            //Handles.DrawBezier(startPos, endPos, startTan, endTan, shadowCol, null, (i + 1) * 5);
        }

        Handles.DrawBezier(startPos, endPos, startTan, endTan, Color.white, null, 5);
        Handles.color = Handles.xAxisColor;
        Handles.ArrowHandleCap(0, endPos, Quaternion.LookRotation(Vector3.right), size, EventType.Repaint);
    }
}
1 Answers

The problem is that the arrow is always behind the e.g. Window 0 since you call DrawNodeWindow always after DrawNodeCurve.

It happens because the arrow is always drawen starting from the endPos to the right direction with length = size so you always overlay it with the window later ... you have to change

// move your endpos to the left by size 
var endPos = new Vector3(end.x - size, end.y + end.height / 2 , 0);

in order to have it start size pixels left before the actual end.x position.

enter image description here

enter image description here

However, as you can see it is still really small since it usually is used to display the arrow in 3D space - not using Pixel coordinates .. you might have to tweak arround or use something completely different.


How about e.g. simply using a GUI.DrawTexture instead with a given Arrow sprite?

// assign this as default reference via the Inspector for that script
[SerializeField] private Texture2D aTexture;

// ...

// since the drawTexture needs a rect which is not centered on the height anymore
// you have to use endPos.y - size / 2 for the Y start position of the texture
GUI.DrawTexture(new Rect(endPos.x, endPos.y - size / 2, size, size), aTexture, ScaleMode.StretchToFill);

like mentioned in the comment for all serialized fields in Unity you can already reference default assets for the script itself (in contrary to doing it for each instance like for MonoBehaviours) so with the NodeEditor script selected simply reference a downloaded arrow texture

enter image description here

If using a white arrow as texture you could then still change its color using

var color = GUI.color;
GUI.color = Handles.xAxisColor;
GUI.DrawTexture(new Rect(endPos.x, endPos.y - size / 2, size, size), aTexture, ScaleMode.StretchToFill);
GUI.color = color;

Result

enter image description here


P.S.: Arrow icon usedfor the example: https://iconsplace.com/red-icons/arrow-icon-14 you can already change the color directly on that page before downloading the icon ;)

Related