본문 바로가기
PROGRAMING📚/Unity📑

[유니티 Unity] 유니티 이벤트(Unity Event) 이해하기

Ta이니 2022. 6. 5.
728x90
반응형

 

이벤트(Event)란 무엇인가?

 

Events는 이벤트를 '발생 시키는 쪽'과 이벤트에 대해 '반응하는 쪽'으로 되어 있다.

예를들어서 한개의 채널이 있을 경우 이 채널에 존재하는 구독자들이 있다고 생각했을 때, 채널 주인이 글을 올렸을 때 구독자들에게는 채널장(이벤트 게재자)이 글을 올렸다고 알림이 가는 것 처럼 알려주는 것을 이벤트라고 생각하면 된다. 

 

이벤트 게재자(Publisher)가 글을 올렸는데 구독이 되어있어어지 게시글을 확인 할 수 있다면 구독자(Subscribers)가 없을 경우 글에 대한 반응(처리)를 할 수 없을 것이다. 

그리고 게재자와 구독자가 1명이라도 있을 경우 Publisher가 글을 올렸을 때 Subscriber 에게 게재가가 글을 올렸다는 알림을 보내주는 과정(처리)를 [이벤트 처리자(Event Handler)] 라고 한다.

 

EventHandler 처리하기

 

1. 기본 Event 처리하는 방법

 

using System;

 

    //Evnet
    public event EventHandler OnSpacePressed;

 

시스템 내부에서 사용하는 event EvnetHandler 를 사용하기 위해서 using System; 을 선언해주어야한다.

그리고 space Bar 를 눌렸을 때마다 Console 창에 "스페이스 바 눌렸음!" 을 띄워줄 것이다.

 

    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //함수인것처럼 이벤트를 호출 함
            //이벤트에 아무것도 없을 경우,Null Erro가 생김
            //if(OnSpacePressed != null )OnSpacePressed(this,EventArgs.Empty);
            OnSpacePressed?.Invoke(this,EventArgs.Empty);
        }
    }

 

업데이트(Update()) 안에 스페이스 바를 입력 했을때 EventHandler OnSpacePressed()함수를 호출 하도록 작성하였다.

 

OnSpacePressed(this,EventArgs.Empty);

 

함수를 호출하는 것 처럼 호출하면 되지만 이벤트가 아무것도 없을 경우에 Null  Error가 생기기 때문에 널이 아닐 경우라는 조건을 달아주어야한다. 

 

//if 문
if(OnSpacePressed != null )OnSpacePressed(this,EventArgs.Empty);
//삼항 연산자
OnSpacePressed?.Invoke(this,EventArgs.Empty);

형식을 다르지만 두 개 다 같은 결과를 출력한다.

 

 2. 이벤트를 수신 할 함수 정의하기 & 이벤트 핸들러 추가하기

    //Evnet
    public event EventHandler OnSpacePressed;
    public void Start()
    {
        OnSpacePressed += Call_OnSpacePressed;
    }
    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //함수인것처럼 이벤트를 호출 함
            //이벤트에 아무것도 없을 경우,Null Erro가 생김
            //if(OnSpacePressed != null )OnSpacePressed(this,EventArgs.Empty);
            OnSpacePressed?.Invoke(this,EventArgs.Empty);
        }
    }

    private void Call_OnSpacePressed(object sender, EventArgs e)
    {
        Debug.Log("스페이스 바 눌렸음!");
    }

 

여기에서   OnSpacePressed += Call_OnSpacePressed; OnSpacePressed 라는 채널을 Call_OnSpacePressed()라는 구독자가 구독했다 생각하면된다.

 

+= 연산자는 이벤트핸들러에 이벤트를 추가하는 의미를 가지고 있기 때문에 OnSpacePressed EventHandler안에 함수를 추가 했다고 생각하면 된다. 함수를 추가하고 나면 이 이벤트가  나면 기존에 Update 안에 있던 OnSpacePressed 이벤트 안에 추가된 Call_OnSpacePressed()가 실행되는 것을 볼 수 있다.

 

 

3. 다른 스크립트 안에서 Event 스크립트 가져오기

 

새로운 SubEvent라는 스크립트를 하나 만들어서 함수를 하나 생성하고 다음과 같이 MyEvent 안에있는 EventHandler안에 에 SubEvent 안에 있는 함수를 추가해 주면 여러개의 이벤트가 같이 동시에 작동하는 것을 알수있다.

 

public class SubEvent : MonoBehaviour
{
    private void Start()
    {
        MyEvent myEvnets = GetComponent<MyEvent>();
        myEvnets.OnSpacePressed += MyEvnets_OnSpacePressed;
    }

    private void MyEvnets_OnSpacePressed(object sender, System.EventArgs e)
    {
        Debug.Log("In SubEvent: 스페이스바 눌림!");
    }
}

각각의 스크립트 안에있는 이벤트가 호출되고 있음

 

이벤트 핸들러 삭제하기

 

-=연산자는 += 반대로 이벤트 핸들러를 삭제 하는 의미를 가지고 있다.

 

public class SubEvent : MonoBehaviour
{
    MyEvent myEvnets;
    private void Start()
    {
        myEvnets = GetComponent<MyEvent>();
        myEvnets.OnSpacePressed += MyEvnets_OnSpacePressed;
    }

    private void MyEvnets_OnSpacePressed(object sender, System.EventArgs e)
    {
        Debug.Log("In SubEvent: 스페이스바 눌림!");
        myEvnets.OnSpacePressed -= MyEvnets_OnSpacePressed;
    }
}

 

위의 코드 처럼 InSubEvent 에서 한번 호출 되면 

      myEvnets.OnSpacePressed -= MyEvnets_OnSpacePressed; 문장으로 인해서

 EventHandler안에 있던 MyEvents_OnSpacePressed() 함수가 삭제 되면서

다시 한번더 눌렀을 때 "In SubEvent: 스페이스바 눌림!" 

한번만 입력 받고 이벤트가 나오지 않는 것을 확인 할 수 있다.

 

4.특정 이벤트 인수, 매개 변수로 전달하기

SpaceBar를 눌렀을 때 누른 갯수 만큼 숫자를 카운트 해주는 기능을 넣어 보려고 한다.

그러기 위해서 EventArgs를 상속 받고 있는 OnSpacePressedEventArgs 클래스를 하나 만들어주고 EventHandler에 OnSpacePressedEventArgs를 매개변수로 넣어준다.

 

원래 EventHandler를 사용하기 위해 사용되었던 Invoke 함수의 매개 변수는 OnSpacePressed?.Invoke(this,EventArgs.Empty); 로 EventArgs.Emty로 되어있었으나  EventHandler<OnSpacePressedEventArgs> OnSpacePressed; 를 보면 이벤트 핸들러 안에

< OnSpacePressedEventArgs> 가 매개변수로 들어가 있기 때문에 만들어준 클래스를 생성 해주어야한다.

 

public class MyEvent : MonoBehaviour
{
    //Evnet
    public event EventHandler<OnSpacePressedEventArgs> OnSpacePressed;
    public class OnSpacePressedEventArgs: EventArgs
    {
        public int spaceCount;
    }
    private int spaceCount;
    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            spaceCount++;
            OnSpacePressed?.Invoke(this,new OnSpacePressedEventArgs { spaceCount = spaceCount})
        }
    }
}
public class SubEvent : MonoBehaviour
{
    MyEvent myEvnets;
    private void Start()
    {
        myEvnets = GetComponent<MyEvent>();
        myEvnets.OnSpacePressed += MyEvnets_OnSpacePressed;
    }
    private void MyEvnets_OnSpacePressed(object sender, MyEvent.OnSpacePressedEventArgs e)
    {
         Debug.Log("In SubEvent: 스페이스바 눌림!"+e.spaceCount);
    }
}

OnSpacePressed?.Invoke(this,new OnSpacePressedEventArgs { spaceCount = spaceCount}) 

spaceCount 는 OnSpacePRessedEventArgs 클래스 안에 있는 spaceCount 이고 spaceCount 는 private 로 되어있는 MyEvnet 스크립트에 선언 되어있는 spaceCount이다.

 

 

4.델리게이트 형식으로 이벤트 정의하기 

 

    public event MyEventDelegate OnFloatEvent;
    public delegate void MyEventDelegate(float f);
    
 	public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            OnFloatEvent?.Invoke(5.5f);
        }
    }
  private void Start()
    {
        myEvnets.OnFloatEvent += MyEvents_OnFloatEvent;
        myEvnets.OnActionEvent += MyEvnets_OnActionEvent;
    }
    private void MyEvents_OnFloatEvent(float f)
    {
        Debug.Log("Float : " + f);
    }

 

5.Unity Action 형식으로 이벤트 정의하기

 

   public event Action<bool,int> OnActionEvent;
   
    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            OnFloatEvent?.Invoke(5.5f);
        }
    }
public class SubEvent : MonoBehaviour
{
    MyEvent myEvnets;
    private void Start()
    {
        myEvnets.OnActionEvent += MyEvnets_OnActionEvent;
    }
    private void MyEvnets_OnActionEvent(bool b, int i)
    {
        Debug.Log("Bool : " + b + "int :" + i);
    }
}

 

6. UnityEvent 를 형식으로 이벤트 정의하기

 

UnityEvent  형식은 다른 형식들과 달리 public으로 하면 인스펙터 창안에서 Event를 추가하고 삭제하는 것이 가능한 속성창이 생긴다

여기에 원하는 함수가 들어있는 오브젝트를 넣고 사용하길 원하는 스크립트 함수를 설정해주고 Invoke() 해주면 다른 형식과 마찬가지로 안에 있는 함수들이 실행된다.

    private UnityEvent OnUnityEvent;
    
      public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            OnUnityEvent?.Invoke();
        }
    }
    public void MyEvents_UnityEvent()
    {
        Debug.Log("UnityEventScript");
    }

UnityEvent는 다른 애들과 달리 += 추가 기능을 사용하면 에러가 생기는데 

오브젝트를 인스펙터 창에서 하나 하나 끌어 넣기 힘들거나 public이 아닌 private 로 스크립트를 작성 할 경우, AddListener()를 사용해서 함수를 등록하는 형식으로 작성해야한다.

 

      myEvnets.OnUnityEvent.AddListener(MyEvents_UnityEvent);

 

UnityEvent.AddListener(등록 원하는 함수); 를 초기에 등록해두고 Event에 등록 된 함수를 실행하기 위해서 UnityEvent.Invoke() 해주면 등록된 함수들이 실행된다.

728x90
반응형

댓글