Unity, C#/Event

유니티 이벤트 완벽하게 이해하기 1

DAEBAL STUDIO 2019. 2. 18. 18:43

유니티 이벤트에 대해 정리해 보았습니다.

 

 

Unity 이벤트

 

C#의 이벤트와 델리게이트를 유니티가 사용하기 편하도록 랩핑 해놓은 것입니다.

이벤트를 발동시키는 측도 그 이벤트에 기능을 등록시켜놓은 측도 서로에게 관심이 없도록 함으로써

코드가 스파게티처럼 엮이지 않도록 합니다. 

 

ex) 플레이어가 죽었을 때 일어나는 각종 상황

UI에 "죽었음" 출력

- 도전과제 출력

- 게임 재시작

 


 

이벤트를 사용하지 않을 때

 

UIManager.cs

- UI를 사용하기 위해 using UnityEngine.UI; 를 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class UIManager : MonoBehaviour {
 
    public Text playerStateText;
    public void OnPlayerDead()
    {
        playerStateText.text = "You Die!!!";
    }
}
cs

 

EventManager.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
 
public class GameManager1 : MonoBehaviour {
 
    public void OnPlayerDead()
    {
        Invoke("Restart", 5f);
    }
 
    private void Restart()
    {
        SceneManager.LoadScene(0); // 0 : 현재씬
    }
}
cs

 

 

AchievementSystem.cs

- UI를 사용하기 위해 using UnityEngine.UI; 를 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class AchievmentSystem : MonoBehaviour {
    public Text achivementText;
 
    public void UnLockachivement(string title)
    {
        Debug.Log("도전과제 해제!!! - " + title);
        achivementText.text = "도전과제 해제 : " + title;
    }
 
}
cs

 

 

PlayerHealth.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class PlayerHealth : MonoBehaviour {
 
    public UIManager uiManager;
    public AchievementSystem achivementSystem;
    public GameManager gameManager;
 
    private void Dead()
    {
        uiManager.OnPlayerDead();
        achivementSystem.UnLockachivement("뉴턴의 법칙");
        gameManager.OnPlayerDead();
 
        Debug.Log("죽었다!");
        Destroy(gameObject);
    }
 
    void OnTriggerEnter(Collider other)
    {
        Dead();
    }
}
cs

이벤트를 사용하지 않으면 PlayerHealth 클래스에서 UIManager, AchievementSystem,

GameManager를 모두 가지고 있어야 합니다. 

나중에 플레이어의 죽음에 영향을 받는 다른 클래스가 생성되면 그 클래스도 

추가해 줘야 합니다. 그러다 보면 코드가 점점 복잡해 지고, 서로의 코드에 영향을 받게

됩니다.


 이벤트를 사용할 때 (Unity에서 만들어 놓은 이벤트를 사용합니다.)

 

 

Player 아래에 Dead라는 Event를 만들고 거기에 UIManager / GameManager / AchievementSystem

에서 Dead라는 Event에 자신들의 함수를 등록해 둡니다. 

Player는 Dead에 어떤 함수가 등록되어 있는지 알지 못합니다. 상대방은 언제 함수가 실행될지 알 수

없습니다. 

 

 

UIManager.cs / UIManager.cs / AchievementSystem.cs 는 위 코드와 같습니다.

 

PlayerHealth.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;  // 유니티 이벤트를 사용하기 위해 필요합니다.
 
public class PlayerHealth : MonoBehaviour {
 
    public UnityEvent onPlayerDead;
 
    private void Dead()
    {
        onPlayerDead.Invoke(); // Invoke : 발동하다.
    }
 
    void OnTriggerEnter(Collider other)
    {
        Dead();
    }    
}
cs

 

유니티 이벤트를 사용함으로써 코드가 깔끔해졌습니다. 

플레이어의 죽음에 영향을 받는 클래스가 증가하더라도 더이상 PlayerHealth.cs 의 코드가 늘어나지도 않습니다.

 

 

유니티 에디터에 보면 Player Health에 위와 같은 리스트가 추가 되어 있는데 이것이 UnityEvent 입니다. 

여기에 플레이어가 죽었을 때 같이 실행되길 바라는 클래스의 함수를 연결해 주면 됩니다. (public 함수만 연결이 가능합니다.)

이제 플레이어가 죽으면 위에 연결해 놓은 함수들이 차례대로 실행이 됩니다. 

 

참고로 UGUI에서 Button 을 만들면 OnClick 이라는 것을 볼 수 있는데 이것도 UnityEvent 입니다. 

 

 

결론적으로 UnityEvent를 사용하면 

 

1. 코드가 깔끔해져서 보기가 편합니다.

2. 클래스끼리 서로 연결되어 있지 않기 때문에 확장성이 뛰어납니다.

3. 일반적인 C# 델리게이트와 이벤트를 사용하면 같은 형태의 함수만 등록 가능하지만 UnityEvent를 사용하면 다른

    형태의 함수도 등록이 가능합니다.