본문 바로가기

메모장/Unity

[Unity/C#] UI에 마우스 이벤트 적용 시키기

Unity에서 기본적으로 제공하는 마우스 이벤트에 대한 콜백함수는 다음과 같다.

  • 1. OnMouseDown - 오브젝트 위에서 마우스 왼쪽 버튼이 눌렸을 때 호출
  • 2. OnMouseDrag - OnMouseDown이 일어나고 마우스 버튼을 때기 전까지 계속 호출됨
  • 3. OnMouseEnter - 마우스가 오브젝트 위로 올라갔을 때 호출
  • 4. OnMouseExit - 마우스가 오브젝트에서 벗어났을 때 호출
  • 5. OnMouseOver - 마우스가 오브젝트 위에 있으면 계속 호출됨
  • 6. OnMouseUp - OnMouseDown이 일어난 후에 마우스를 때면 호출 (OnMouseDown이 일어나지 않으면 호출되지 않음)
  • 7. OnMouseUpAsButton - OnMouseDown이 호출된 오브젝트 위에 마우스가 위치한 상태에서 OnMouseUp이 호출됬을 때

위의 함수들은 Collider, GUIElement에서 발생한다... 라고 설명 되어 있지만 NGUI에서는 발생하지 않는다.
(Collider를 붙여도 작동하지 않는다!)

대체 왜 호출이 안될까.

 

또 마우스 왼쪽 버튼에 대해서만 구현이 되있기 때문에 굳이 UI가 아니더라도 개선의 필요성이 보인다.

 

 

using UnityEngine;
using UnityEngine.Experimental.UIElements;

public class MouseEventTester : MonoBehaviour
{
    private Camera _uiCamera;
    private Collider _collider;

    private bool _isMouseOver;
    private bool _isMousePushed;
    
    private void Awake()
    {
        _uiCamera = FindObjectOfType<Camera>(); // 해당 오브젝트를 비추고 있는 카메라
        _collider = GetComponent<Collider>(); // 오브젝트의 Collider
    }

    private void Update()
    {
        var ray = _uiCamera.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        Physics.Raycast(ray, out hit);

        var leftMouse = (int)MouseButton.LeftMouse; // Test를 위해 왼쪽 버튼을 입력으로 받는다.

        if (hit.collider != null && hit.collider == _collider && !_isMouseOver)
        {
            _isMouseOver = true;
            OnMouseEnter();
        }else if (hit.collider != _collider && _isMouseOver)
        {
            _isMouseOver = false;
            OnMouseExit();
        }

        if (_isMouseOver) OnMouseOver();
        if (_isMouseOver && Input.GetMouseButtonDown(leftMouse))
        {
            _isMousePushed = true;
            OnMouseDown();
        }
        if (_isMousePushed && Input.GetMouseButton(leftMouse)) OnMouseDrag();
        if (_isMousePushed && Input.GetMouseButtonUp(leftMouse))
        {
            _isMousePushed = false;
            OnMouseUp();
            if(_isMouseOver) OnMouseUpAsButton();
        }
    }

    private void OnMouseDown()
    {
        Debug.Log("OnMouseDown");
    }
    private void OnMouseUp()
    {
        Debug.Log("OnMouseUp");
    }
    private void OnMouseExit()
    {
        Debug.Log("OnMouseExit");
    }
    private void OnMouseOver()
    {
        Debug.Log("OnMouseOver");
    }
    private void OnMouseDrag()
    {
        Debug.Log("OnMouseDrag");
    }
    private void OnMouseUpAsButton()
    {
        Debug.Log("OnMouseUpAsButton");
    }
    private void OnMouseEnter()
    {
        Debug.Log("OnMouseEnter");
    }
}

카메라에서 마우스 위치를 향해 raycast를 한 후 UI의 Collider와 충돌 했는지 확인하는 방법으로 문제를 해결하였다.

NGUI에서는 별 문제 없이 잘 작동하나, UGUI는 ScreenSpace - Overlay일 경우 카메라를 이용하지 않기 때문에,
Canvas의 Render Mode를 Screen Space - Camera로 바꿔줘야 정상적으로 작동한다.

 

 

+ 05/30 추가

Screen Space - Overlay일 경우에도 돌아가도록 하려면 EventSystems 를 사용하면 된다.

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

public class Drag : MonoBehaviour, IDragHandler // IDragHandler는 Interface
{

    float distance = 10.0f;
    public void OnDrag(PointerEventData eventData)
    { 
        Vector3 mousePosition = new Vector3(Input.mousePosition.x, 
				Input.mousePosition.y, distance);
        transform.position = mousePosition;
    }

}