Unity3D Scene View is one of the most essential interface elements. Everyone who at least once started Unity3D used Scene View for visual arrangement of objects on a scene, and also for their setup. Extending the functionality of Scene View may be needed to create your own level editor, edit the mesh, create your own gizmos and much more. It is worth noting that when using Terrain in your project, its editing (drawing textures, changing heights, and planting trees and vegetation) is done using Scene View.
In order to be able to write scripts working in the Scene view, first of all the class you are working with must be inherited from Editor or EditorWindow, which implies connecting the namespace UnityEditor. This gives access to several Unity3D "magic" methods, such as OnGUI () and OnSceneGUI (). The OnSceneGUI method allows the Editor to manage Scene View events.
A small lyrical digression. Among the developers there is an opinion that the “magic” methods (Update, Start, OnSceneGUI and others) are implemented by means of System.Reflection in C #, however there is
information that this is not so, and it is worthwhile to thank the C ++ core Unity3D for their work. In general, the
article will be useful to all who sin with multiple Update () in their code.
')
Let's return to the interception of events. The idea is to designate the object for which we are developing the functionality, as an element of the Unity interface, on par with the Label or Button from IMGUI.
In api, there is an
Event class that is used for various GUI events, such as keystrokes, mouse buttons, rendering events, and Unity layout.
In addition to the Event to intercept clicks need such a thing as control. Any element of IMGUI can act as control in Unity. For example Button or Label. In order for your object to intercept a click, you need to tell Unity that it is also a control and is going to participate in event handling. To do this, use the
GUIUtility class.
Each control must have its own unique id, with which Unity will get all the necessary information about it. The id is an int, but it's worth noting that it must be unique. You can generate a random number (other than 0) and consider it the id of your control, but there is no guarantee that the system no longer has a control with the same id, and in this case the click will not go to the element you were counting on. To create a unique id, use the method from the GUIUtility class.
public static int GUIUtility.GetControlID(FocusType focus)
The parameter received at the input by this method is responsible for the ability of the control to receive any input from the keyboard. Information about it can be obtained in the
documentation . Since keyboard input is not needed when using Scene View, the FocusType.Passive value will do.
int controlId = GUIUtility.GetControlID(FocusType.Passive);
Now that we’ve figured out how to get an id, it’s time to figure out how to intercept events. We can get information about the current event using the Event.current property. To get the type of event that occurred in Unity, do the following
int controlId = GUIUtility.GetControlID(FocusType.Passive); Event.current.GetTypeForControl(controlId)
This call will return an
EventType of type for our control. Next, you only need to decide exactly what events you need and intercept them. Directly intercept the event as follows.
GUIUtility.hotControl = controlId;
In the case of a mouse click, you say that your control is “hot”, that is, it will first of all respond to mouse events, and they will not go further to other conltrols.
This aspect is described in detail in the
documentation . To return access to mouse events to other controls, you need to do
GUIUtility.hotControl = 0;
By this you say that the following mouse events can intercept any other control. Also, events will be available to other control, if you do not use them. That is, do not mark as
Used Event.current.Use();
I will give a complete example of a script that handles clicks on Scene View.
using UnityEngine; using UnityEditor; [CustomEditor(typeof(MyCustomComponent))] public class MyCustomEditor : Editor { void OnSceneGUI() { int controlId = GUIUtility.GetControlID(FocusType.Passive); switch (Event.current.GetTypeForControl(controlId)) { case EventType.MouseDown: GUIUtility.hotControl = controlId;
Someone may have a question about the need for the material described above. An example is the creation of an editor for 2d tile levels. You can write a similar custom editor for the map class, and when intercepting events, obtain mouse coordinates to determine the specific child element that was clicked. You can determine a specific element by making Raycast, which in Scene View will work exactly the same as in the course of your game.
On this, allow me to bow out, I hope that this article will be useful for someone.