개념공부

Unity Event System

Cadi 2025. 1. 25. 20:13

Unity Event System : UI와 상호작용하거나 게임오브젝트간 이벤트를 처리하기 위한 중앙 관리자 역할

 

역할

  • 이벤트 라우팅 : 특정 입력(클릭, 터치)를 적절한 요소나 게임 오브젝트로 전달
  • 이벤트 처리 : UI 요소와의 상호작용을 처리
  • 인터페이스 구현 : 이벤트 처리를 위한 인터페이스 제공

주요 클래스

  • EventSystem : 모든 이벤트 데이터 처리 중앙 관리자
  • PointEventData : 포인트 이벤트 데이터와 관련된 입력 데이터 저장
  • BaseEventData : 모든 이벤트 데이터의 기본 클래스
  • ExecuteEvent : 이벤트를 실행하거나 전달하는 정적 클래스
  • StandAloneInputmodule : 마우스, 키보드 ,터치 입력을 지원하는 기본 입력 모듈

예를 들어 과정을 설명하자면

 

클릭 > EventData 생성 > Execute로 어떤 데이터인지 전달 > IPointDownHandler를 그 오브젝트가 구현하고 있으면 데이터를 전달해서 기능을 실행

 

더 자세히 예시를 통해 알아보자면. 

using UnityEngine;
using UnityEngine.EventSystems;

public class CustomEventSystem : MonoBehaviour
{
    void Update()
    {
        // 1. 입력 데이터 수집
        PointerEventData pointerEventData = new PointerEventData(EventSystem.current)
        {
            position = Input.mousePosition
        };

        // 2. 레이캐스트로 대상 탐색
        RaycastResult raycastResult = RaycastTarget(pointerEventData);

        if (raycastResult.gameObject != null)
        {
            // 3. 이벤트 실행
            ExecuteEvents.Execute(raycastResult.gameObject, pointerEventData, ExecuteEvents.pointerDownHandler);
        }
    }

    private RaycastResult RaycastTarget(PointerEventData eventData)
    {
        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(eventData, results);

        return results.Count > 0 ? results[0] : new RaycastResult();
    }
}

 

PointeEventData는 BaseData를 상속받는 클래스로 포인터(마우스, 터치) 와 관련된 추가 정보를 제공한다.

예를 들어, position, delta, button, clickCount, pointerEnter, pointerPress,pointerDrag,scrollDelta 등이 있다.

그래서 EventSystem.current를( 보통씬에 하나 존재) 사용하여 PointerEventData를 생성하고 

이 PointerEventData의 position값을 캡슐화해서 raycastResult로 전달한다. 

그리고 포지션의 레이케스트에 무언가가 닿았다면, 닿은 게임 오브젝트에 ExeccuteEvent로 데이터를 보내준다.

마지막 매개변수인 ExecuteEvents.pointerDownHandler는 이 받은 데이터로 무언가를 실행할 수 있는 함수가 있어야 한다는 것으로, 두 가지 방법으로 핸들러에서 구현할 수 있다. 

1. IPointerDownHandler 인터페이스로 구현

2. EventTrigger (컴포넌트)

 

이런 식으로 이벤트 시스템에 등록된 Event들을 활용할 수 있다. 

다음 링크는 유니티에서 제공하는 이벤트들의 목록이다. (핸들러로 정의된)

 

https://docs.unity3d.com/2019.1/Documentation/ScriptReference/EventSystems.ExecuteEvents.html

 

Unity - Scripting API: ExecuteEvents

You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see: You've told us there are code samples on this page which don't work. If you know ho

docs.unity3d.com

 

목록들은 다음과 같다. 

 

1. 포인터 이벤트 ( Pointer Events)

  • PointerDown : 포인터가 UI 요소를 클릭했을 때 호출
  • PointerUP : 포인터가 클릭한 UI 요소에서 버튼을 뗐을 때 호출
  • PointerClick : 포인터가 클릭 이벤트를 완료했을 때 호출 (Down - > Up)
  • PointerEnter : 포인터가 UI 요소 위로 진입했을 때 호출
  • PointerExit : 포인터가 UI 요소를 떠났을 때 호출
  • BeginDrag : 포인터가 UI 요소를 드래그 시작했을 때 호출
  • Drag : 드래그 중인 동안 계속 호출
  • EndDrag : 드래그가 종료되었을 때 호출
  • Drop : 드래그한 오브젝트가 다른 UI 요소 위에서 드롭되었을 때 호출

2. 키보드 및 입력 이벤트 ( KeyBoard and Input Events)

  • Submit : UI요소가 Submit(제출) 동작을 수행했을 때 호출
  • Cancel : Ui요소에서 Cancel(취소) 동작을 수행했을 때 호출

3. 스크롤 및 이동 이벤트 ( Scroll and Navigation Events)

  • Scroll : 마우스 휠이나 터치 스크롤 동작이 발생했을 때 호출
  • Move : 키보드 또는 게임패드 입력으로 UI 요소 간 이동이 발생했을 때 호출

4. 선택 및 업데이트 이벤트 (Selection Events)

  • Select : UI 요소가 선택되었을 때 호출
  • Deselect : UI 요소가 선택 해제되었을 때 호출
  • UpdateSelected : 선택된 UI 요소가 매 프레임 업데이트 될 때 호출

 

이렇게 이벤트들이 있고 이 이벤트들을 받아서 동작할 핸들러를 인터페이스로 갖고 있는 클래스가

ExecuteEvents.~~Handler로 동작을 전달받으면 동작하는 것이다. 

 

즉, ExecuteEvents의 역할은 게임 오브젝트에서 특정 이벤트를 처리할 수 있는 핸들러를 찾고, 실행하는 

 

예를 들어, 유니티에서 보여지는 Button 클래스는 다음과 같다. 

 

using System;
using System.Collections;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;

namespace UnityEngine.UI
{
  
    [AddComponentMenu("UI/Button", 30)]
    public class Button : Selectable, IPointerClickHandler, ISubmitHandler
    {
        [Serializable]
       
        public class ButtonClickedEvent : UnityEvent {}

        [FormerlySerializedAs("onClick")]
        [SerializeField]
        private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();

        protected Button()
        {}

       
        public ButtonClickedEvent onClick
        {
            get { return m_OnClick; }
            set { m_OnClick = value; }
        }

        private void Press()
        {
            if (!IsActive() || !IsInteractable())
                return;

            UISystemProfilerApi.AddMarker("Button.onClick", this);
            m_OnClick.Invoke();
        }

        public virtual void OnPointerClick(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;

            Press();
        }

      

        public virtual void OnSubmit(BaseEventData eventData)
        {
            Press();

            if (!IsActive() || !IsInteractable())
                return;

            DoStateTransition(SelectionState.Pressed, false);
            StartCoroutine(OnFinishSubmit());
        }

        private IEnumerator OnFinishSubmit()
        {
            var fadeTime = colors.fadeDuration;
            var elapsedTime = 0f;

            while (elapsedTime < fadeTime)
            {
                elapsedTime += Time.unscaledDeltaTime;
                yield return null;
            }

            DoStateTransition(currentSelectionState, false);
        }
    }
}

 

Selectable, IPointerClickHandler, ISubmitHandler들이 있다  !!

* IPiointerClickHandler : 유니티의 이벤트시스템에서 PointerClick 이벤트를 처리

* ISubmitHandler : 키보드나 게임패드로 선택된 UI 요소를 처리

즉 이 두 요소들을 통해 버튼은 클릭 및 키보드 입력 모두 지원

 

예를 들어서, 빈 화면을 클릭한 경우

PointerEventData는 항상 생성된다. (마우스 위치, 클릭 버튼, 포인터 이동 등의 입력 정보 포함)

그런데 평상시에는 레이캐스트 결과가 없어서 이벤트 전달을 실패하는 것이다.

그러다가 데이터를 받을 수 있는 오브젝트 ( 예: 버튼) 을 만나면 데이터를 전달하고, 그 데이터를 바탕으로 버튼이 동작하는 것이다. 

 

추가로 EventSystem은 GraphiRaycaster와 PhysicsRaycaster 등 다양한 레이케스트를 지원함.

UI 요소 외에도 EventSystem 인터페이스를 구현해 게임 오브젝트간의 상호작용에도 활용 가능함.