Unity Event System
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 인터페이스를 구현해 게임 오브젝트간의 상호작용에도 활용 가능함.