[SOLVED]: Custom Editor OnSceneGUI Scripting

I am currently learning how to write scripts in Unity and decided to try my hand at writing a path editor for an upcoming game I am planning. I have a path class which holds the actual path data and a custom editor for the path. Now I was trying to use the SceneView to do most of my editing work, that is adding path nodes and whatnot. I can successfully display the path nodes using PositionHandles, or FreeMoveHandles. I have been able to add nodes by clicking in the SceneView. Here is where I am getting tripped up.

If I attach my path script to an empty GameObject, when I click the scene the SceneView will add the node, then select the object I clicked. I thought that by calling the Event.current.use (), the mouse click event would essentially not be processed anymore. This doesn’t seem to be the case. I have scoured the reference docs and searched the forums to come up with a good solution and have done some tests using keyboard commands which may work, but is not optimal. Is there something I am missing being a complete noob to Unity? Or am I going about the problem wrong?

Here is my code for those interested:

  public void OnSceneGUI ()
    {
      if (Event.current.type == EventType.MouseDown)
      {
        if (Event.current.button == 0)
        {
          Ray worldRay = HandleUtility.GUIPointToWorldRay (Event.current.mousePosition);
          RaycastHit hitInfo;

          if (Physics.Raycast (worldRay, out hitInfo))
          {
            Undo.RegisterUndo (target, "Add Path Node");
            ((Path)target).AddNode (hitInfo.point);
          }

          Event.current.Use ();
        }
      }

      for (int i = 0; i < ((Path)target).nodes.Count; i++)
        ((Path)target).nodes[i] = Handles.PositionHandle(((Path)target).nodes[i], Quaternion.identity);
      
      Handles.DrawPolyLine (((Path)target).nodes.ToArray ());

      if (GUI.changed)
          EditorUtility.SetDirty(target);
    }

Again any help or suggestions would be greatly appreciated. Thanks.

  • Ed Weese

For more clarification, I would basically like to disable object selection in the scene view when my path tools are active.

-Ed Weese

1 Like

Could you set a boolean variable whenever the path tools are active and then test for it in the “if” statement where the raycast is performed?

I setup a boolean variable to tell the function if the add node tool is active. However, this still presents the problem of adding the node, then the mouse click gets used again to select or deselect the object by the Scene View.

1 Like

Taking another look at the docs reveals that calling Event.current.Use () in my OnSceneGUI function should make it so the Scene View doesn’t process the event. This is not what is happening.

I am using Unity 2.6 on a windows machine and the script is C#. Has anyone else had the same problem or am I misunderstanding the whole situation? Any help is greatly appreciated. Thanks.

-Ed Weese

After searching long and hard to no avail, I finally found what my problem was. I wasn’t getting a controlID for my new control and setting it as the default. This was something that I had overlooked being so new to Unity. By doing so, the proper behavior that I was trying to achieve was obtained. All it took was some reflection. :smile: Below is my new code for anyone that is experiencing the same issue.

  void OnSceneGUI()
  {
    Event current = Event.current;
    int controlID = GUIUtility.GetControlID(mPathEditorHash, FocusType.Passive);

    switch (current.type)
    {
      case EventType.mouseUp:
        switch (mActiveTool)
        {
          case Tools.toolAdd:
            addNode();
            break;
        }

        current.Use();
        break;

      case EventType.layout:
        HandleUtility.AddDefaultControl(controlID);
        break;
    }

        for (int i = 0; i < ((Path)target).nodes.Count; i++)
          ((Path)target).nodes[i] = 
            Handles.FreeMoveHandle(((Path)target).nodes[i], 
            Quaternion.identity, 0.25f, new Vector3(1.0f, 1.0f, 1.0f), 
            Handles.DrawRectangle);

        Handles.DrawPolyLine(((Path)target).nodes.ToArray());

        if (GUI.changed)
          EditorUtility.SetDirty(target);
  }
4 Likes

thanks, man. (:

Thanks. man.
I guess one.
What means ‘mPathEditorHash’ variable in GetControlID(…) ?

mPathEditorHash is probably just GetHashCode (). It could certainly be something else, but that one works for me.

Thanks a bunch; I was pulling my hair out trying to solve a similar problem.

A long time after the fact:

Thanks for this! I’ve come back to this post twice to solve the same problem… many many months apart.

-JFFM

Thanks! I really appreciate that you shared the answer to your own problem.

nice code that simply dont work at all. unity doc is a joke and this code is the same.

… at least till anybody ‘educated’ takes 2 min to explain where the magical
‘mPathEditorHash’ comes from

After hours of googling finally found something that works. Thanks for sharing!

OMG! Years later, after hours of searching, this fixes my problem. You win the Internet, sir.

And why in blazes is this answer so well hidden?!? Is there some way I can upvote you to heaven?

1 Like

Thank you so much dagbud. I’ve been struggling with this lately and I thought I was doing something wrong because according to the documents, if I use the event, the editor should not use it as well (which wasn’t the case). I found this in this thread: http://forum.unity3d.com/threads/99909-Hurr-EventType.MouseUp-not-working-on-Left-Clicks

Really though, this post is 3 years old and it seems that people still run into this problem. Perhaps I’ll bring it up with some people on the IRC channel tonight to if anything, add some note to the documentation.

At least now my tool now allows me to populate waypoints quickly and the editor doesn’t try to use my mouse clicks to select objects in the scene.

For all the years I’m wondering about those strange control IDs and what they’re good for, until I need to solve the Event.Use() problem and found this thread. You made my day! Thanks a lot!

Thanks a lot for this.

Here is the part of code needed to solve this problem:

if (Event.current.type == EventType.layout)
    HandleUtility.AddDefaultControl(GUIUtility.GetControlID(GetHashCode(), FocusType.Passive));

I put it in the beginning of OnSceneGUI().

3 Likes

Great ! It worked !

Thanks a lot. I was wondering so long how to get Left Mouse Click Up Event !

But there is a big issue with this ‘solution’ : It disables Handles and GameObjectSelection in Scene ! Given your script receive the event mouseUp, the Unity-based script for those doesn’t get it anymore, and so, you can no more move or deselect your object by clicking in Scene…

Have someone an idea to solve this ?

Avalion

It fixes the MouseUp issue, but this still never triggers:

if(Event.current.type == EventType.MouseDrag){

Edit: now it seems to work… You can try to use Event.current.rawType instead of Event.current.type as well.