Unity: OnMouseEnter() and OnMouseExit() are repeatedly called while OnMouseDrag()

Viewed 58

While OnMouseDrag() is called, if I move mouse fast then OnMouseEnter() and OnMouseExit() are repeatedly called, so I made a new script but the same problem happens. If I move mouse slowly, they aren't called. I don't know what's the problem. Anyone can help me?

I hope they are not called while dragging. While I drag, the object is attached to the mouse so I think OnMouseEnter() and OnMouseExit() shouldn't be called.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    private void OnMouseEnter()
    {
        // If mouse enters the object, the color of the object becomes red and prints "Enter"
        Debug.Log("Enter");
        GetComponent<SpriteRenderer>().color = Color.red;
    }

    private void OnMouseExit()
    {
        // If mouse exits the object, the color of the object becomes white and prints "Exit"
        Debug.Log("Exit");
        GetComponent<SpriteRenderer>().color = Color.white;
    }

    private void OnMouseDrag()
    {
        // If I click the object and drag, it follows mouse
        // Then OnMouseEnter() and OnMouseExit() is called repeatedly
        // and the color becomes red and white and both "Enter" and "Exit" are printed
        // Utilities.MousePos has the position of mouse, and it doesn't have any problem.
        transform.position = Utilities.MousePos;
    }
}
1 Answers

It happens because OnMouseEnter() and OnMouseExit() is handled before OnMouseDrag(). So every frame there are things like this happen:

  1. You move your mouse and Unity handle that its position changed
  2. Unity checked the mouse and object positions and see, that mosue moved outside the object, so OnMouseExit() is being called. As your metion it happens if you move your mouse fast enough to make it leave object with one frame
  3. Unity hande drag event and call OnMouseDrag(). The position of object changed in it.
  4. Cause position of object changing Untiy again checking for mouse and object positions and find out that mouse cursor is over the object. And call OnMouseEnter()

The workaround, that I cant suggest is to implement own dragging logic like this:

using UnityEngine;

public class DraggableObj : MonoBehaviour
{

    private bool _hovered;
    private bool _dragged;
    
    private bool Hovered {
        set
        {
            _hovered = value;
            UpdateState();
        }
        get => _hovered;
    }
    
    private bool Dragged {
        set
        {
            _dragged = value;
            UpdateState();
        }
        get => _dragged;
    }
    
    private void OnMouseEnter()
    {
        Hovered = true;
    }
    
    private void OnMouseExit()
    {
        Hovered = false;
    }

    private void OnMouseDown()
    {
        Dragged = true;
    }

    private void OnMouseUp()
    {
        Dragged = false;
    }

    private void UpdateState()
    {
        if (Hovered || Dragged)
            gameObject.GetComponent<Renderer>().material.color = Color.red;
        else 
            gameObject.GetComponent<Renderer>().material.color = Color.white;
    }

    private void FixedUpdate()
    {
        if (Dragged)
        {
            // Here you should implement your positioning logic. This one is just for example.
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition + Vector3.forward * 10f);
        }
    }
}

Related