Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity editor capture "hold mouse down and move" event

I am creating a simple tilemap editor extention in unity because the default one lacks a lot of functionality my project needs. I am inheriting EditorWindow. When holding the left mouse button and dragging the mouse i want to place tiles in the scene (in editor mode).

The picture below illustrates what behavior i want.

enter image description here:

The problem i face is how to recognize this event. This is the function for handling mouse input that i use:

void HandleMouseInput() {
    Event e = Event.current;
    switch (e.type) {
    case EventType.MouseDown:
        if (e.button == 0) PlaceTile();
        break;
    case EventType.MouseMove:
        Debug.Log("Moving");
        Debug.Log(e.button); // <-- always show 0 (left click) even though mouse is not clicked.
        break;
    }
}

The first case (single tile placement) works as expected. But i fail to capture the "left mouse button held down" event. I can capture a mouse move event EventType.MouseMove but i then need whether there was a left click. According to unity docs, e.button == 0 indicates a left click (which works as expected in the first switch case). But in the second case e.button is always 0, regardless of what mouse button is clicked. There is a EventType.MouseDrag aswell but it seems to only trigger when you select a gameobject in the scene and drag it.

In Unity, when holding down the left mouse button and moving the mouse the default behavior seems to be creating a selection box:

enter image description here

Or dragging the entire scene if the hand icon is selected in the top left corner of the editor.

Essentially i want to capture this event and override the result with my own functionality.

EDIT: I think i could solve this by creating a custom tool https://docs.unity3d.com/ScriptReference/EditorTools.EditorTool.html

like image 421
Tagor Avatar asked Jan 30 '26 09:01

Tagor


1 Answers

Alright so instead of inheriting EditorWindow i created a custom tool TileTool and put all the logic in there.

In its OnToolGUI (OnGUI equivalent?) i can disable the box selection:

HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));

And automagically the event EventType.MouseDrag is captured correctly and i achieve the desired effect.

The whole script:

[EditorTool("Tile Tool")]
class TileTool : EditorTool
{
    // Serialize this value to set a default value in the Inspector.
    [SerializeField]
    Texture2D icon;



    public override GUIContent toolbarIcon =>
        new GUIContent() {
            image = icon,
            text = "Tile Tool",
            tooltip = "Tile Tool"
        };


    public override void OnToolGUI(EditorWindow window) {
        HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
        HandleMouse();
    }

    void HandleMouse() {
        Event e = Event.current;
        switch (e.type) {
            case EventType.MouseDown:
                if (e.button == 0) ApplyLeftClickTool();
                break;
            case EventType.MouseDrag:
                if (e.button == 0) ApplyLeftClickTool();
                break;
        }
    }



    void ApplyLeftClickTool() {
        switch (TilemapEditor.Instance().ActiveTool) {
        case TilemapEditor.TileTool.BRUSH:
                PlaceTile();
                break;
        case TilemapEditor.TileTool.ERASER:
                EraseTile();
                break;
        }
    }

    void PlaceTile() {
        GameObject prefab = TilemapEditor.Instance().Selected;
        GetTilemap().Place(prefab, MouseInWorld());
    }

    void EraseTile() {
        GetTilemap().Erase(MouseInWorld());
    }

    PrefabTilemap GetTilemap() {
        PrefabTilemap tilemap = FindObjectOfType<PrefabTilemap>();
        if (tilemap == null) {
            GameObject tilemapGO = new GameObject("Tilemap");
            tilemap = tilemapGO.AddComponent<PrefabTilemap>();
            tilemap.Init();
        }
        return tilemap;
    }

    Vector2 MouseInWorld() {
        return HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin;
    }
}
like image 138
Tagor Avatar answered Jan 31 '26 23:01

Tagor