How do I make an empty GameObject with just my CustomClass and no renderers in it to be always pickable in the Editor, without using the ugly 3 axes position handle but having something nicer like a small dot to click on?

Hi,

I’m building a path system and don’t like to always show the handles of each node (a list of Transforms).

Each node is actually also a gameobject with a PathNode info component on it, because in the future I may want to add some logic or code to each component, that’s why I’m using a gameObject.

I already have the OnDrawGizmos defined, so I can see how each path node is linked, and the SimplePath classes handles the… showing of the path node handles when the path is selected.

image of a path

And when selected, I have this ugly handles - I’d like to just have the node shown and drag it with the move tool

more image

Anyway, I’d love to give the pathnodes a more stylish look and would like to be selectable when clicking on their Zoom dependant representation.

The quick and dirty way would be to attach a sprite renderer and hide it at runtime but… isn’t there another option? Maybe using handles or some kind of code/class/method/helperclass/utility I don’t know?

Thank you! :slight_smile:

Well, the best option here would be to implement a custom inspector for your “path system” component ( the one that holds the list of Transforms). In there you can use OnSceneGUI to render Handles into the SceneView for each transform you have in your list.

You can use Handles.FreeMoveHandle or implement your own handle. FreeMoveHandle allows you to specify any “cap” function (CubeCap, CircleCap, ConeCap, ArrowCap, CylinderCap, DotCap, RectangleCap, SphereCap) as visual representation.

The FreeMoveHandle is actually used inside the PositionHandle. It will show when you hold down “shift”. In that case the 3 planar handles are hidden and a white rectangle will show. That’s the FreeMoveHandle. It allows movement parallel to the current camera view. Since you use the 2d orthographic view it’s always the x-y-plane.

edit

Here’s a quick (untested) example of what i mentioned in the comments below. This is the basic framework:

[InitializeOnLoad]
public class PathHandlesEditorExtension
{
    static PathHandles()
    {
        SceneView.onSceneGUIDelegate += OnSceneGUICallback;
    }
    static void OnSceneGUICallback(SceneView currentView)
    {
        // Your custom SceneView stuff goes here
    }
}

The InitializeOnLoad attribute will make Unity “initialize” the class when the editor is loaded. Initialize doesn’t mean that an instance is created, but only the static constructor will be called. There we subscribe to the scene view delegate. After that our “OnSceneGUICallback” method will be called whenever a SceneView receives an event.

To manage the nodes in the Scene you might want to use this:

// Inside your PathNode class:
public class PathNode : MonoBehaviour
{
    #if UNITY_EDITOR
    public PathNode()
    {
        PathHandlesEditorExtension.AddNode(this);
    }
    #endif
}

This will add the constructor only when compiled in the editor. Of course the PathHandlesEditorExtension class would need to that AddNode method:

// inside PathHandlesEditorExtension

private static List<PathNode> nodes = new List<PathNode>();
public static void AddNode(PathNode aNode)
{
    lock(nodes)
    {
        nodes.Add(aNode);
    }
}

static void OnSceneGUICallback(SceneView currentView)
{
    lock(nodes)
    {
        // iterate backwards to remove null objects on the fly
        for(int i = nodes.Count-1; i >=0; i--)
        {
            var node = nodes*;*

if (node == null)
{
nodes.RemoveAt(i);
continue;
}
float size = HandleUtility.GetHandleSize(node.transform.position);
node.transform.position = Handles.FreeMoveHandle(node.transform.position, Quaternion.identity, size, Vector3.zero, Handles.RectangleCap);
}
}
}
Note that this is untested. Since the nodes add themselfs to the static list, it’s possible that you will get additional handles if you have a prefab of that node. Prefabs might be loaded as well but not actually in the scene. It’s a bit tricky to distinguish between sceneobjects and prefabs but as far as i remember there was a solution if that really is a problem.
If the locking gives performance problems you could use a second temp / transfer list which is synchronised and only used to copy new nodes into the actual list.
If your “path” class is some sort of singleton (only possible if there’s only one instance per scene) you could of course remove all that node list stuff and just use your singleton to get access to the node list. Keep in mind that your scene GUI callback will be called no matter which scene is loaded, so make sure you don’t produce and errors (null ref).