본문 바로가기

Unity

유니티 c# - 델리게이트(Delegate) Action 사용해 보기

반응형

 

델리게이트에 대해 찾아보면 첫 설명이 대부분 대리자라고 나옵니다.

예제로 제공되는 소스들은 함수 두어 개를 델리게이트에 연결하여 불러오는 방식입니다.

대충 어떻게 돌아가는지는 알겠는데 처음 접하면 별로 사용할 일이 없어 보입니다. 

실제 게임에서 델리게이트를 어떻게 사용하면 좋을지 간단한 예제로 알아보겠습니다.

 

프로그램 어디서나 쉽게 접근할 수 있는 싱글톤 패턴으로 정의된 GameManager.cs 가 있습니다.

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    
    void Awake() {
        if (instance == null) {
            instance = this;
            DontDestroyOnLoad(this.gameObject);
        } else {
            Destroy(this.gameObject);
        }
    }
 }

 

그리고 음악 재생을 위한 SoundManager.cs 가 있습니다.

public class SoundManager : MonoBehaviour 
{
    List<SoundList> listSound = new List<SoundList>();
    
    private void PlaySound(int num) {
         listSound[num].SoundPlay();
    }
 }

SoundManager의 사운드 소스는 List로 묶여 PlaySound(int num) 함수로 실행됩니다.

PlaySound를 실행해야 될 클래스가

Enemy1.cs

Enemy2.cs

Enemy3.cs

Enemy4.cs

4개의 클래스에서 PlaySound를 불러와 실행하는 코드를 필요로 합니다.

 

GameManager처럼 SoundManager도 싱글톤 패턴으로 만들어 사용하면 간편하게 사용할 수 있겠지만

Action으로도 비슷하게 사용할 수 있습니다.

 

우선 GameManager에 Action을 선언해 줍니다.

using System;

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    
    public Action<int> actionSoundPlay;
    
    void Awake() {
        if (instance == null) {
            instance = this;
            DontDestroyOnLoad(this.gameObject);
        } else {
            Destroy(this.gameObject);
        }
    }
 }

Action 사용을 위해선 using System을 선언해야 합니다.

public Action<int> actionSoundPlay;  <- int 값을 받는 actionSoundPlay 명의 Action 선언

 

이제 SoundManager의 음악을 플레이할 수 있는 함수 인 PlaySound 함수를 actionSoundPlay에 등록해 주시면 됩니다.

public class SoundManager : MonoBehaviour 
{
    ListSound<SoundList> listSound = new ListSound<SoundList>();

    void Start() {
    	GameManager.instance.actionSoundPlay = PlaySound;
    }

    private void PlaySound(int num) {
         listSound[num].SoundPlay();
    }
 }

GameManager.instance.actionSoundPlay = PlaySound;

actionSoundPlay 델리게이트에 PlaySound 함수를 등록해 줍니다.

같은 조건의 함수를 더 등록 하려면 actionSoundPlay += 추가 함수명으로 해주시면 되며

등록된 함수를 빼려고 한다면 actionSoundPlay -= 빼고 싶은 함수명으로 해주시면 됩니다.

 

"위 코드에서 보시면 PlaySound는 private으로 되어 있습니다.

하지만 Action에 연결 하면 어떤 클래스에서도 사용 가능하게 됩니다."

 

이제 준비는 끝났습니다.

실제 Enemy1 ~ 4.cs에서 사용만 하면 됩니다.

 

public class Enemy1 : MonoBehaviour 
{
    private void EnemyDamage() {
         GameManager.instance.actionSoundPlay.Invoke(1);
    }
 }

EnemyDamage는 몬스터가 대미지를 입으면 사운드를 발생시킵니다. 

GameManager.instance.actionSoundPlay.Invoke(1);

actionSoundPlay에 등록된 PlaySound가 실행됩니다. 

Action에 등록된 함수를  실행하기 위해선 Invoke() 를 사용하셔야 하며 Invoke(1)의 숫자 1은

Action<int> -> int값이며 이 int값이 SoundManager의 PlaySound(int num) int num 값이 됩니다.

 

Action이 싱글톤 패턴의 GameManager에 선언되어 있기에 

Enemy1.cs 와 같이 GameManager.instance.actionSoundPlay.Invoke(1); 로 불러올 수 있습니다.

Enemy1 ~ 4.cs 뿐 아니라 사운드 효과가 필요한 어느 곳에서나 간편하게 사용이 가능합니다.

 

SoundPlay  함수와 같이 여러 곳에서 광범위하게 사용되는 함수가 있다면 이렇게 Action 델리게이트에 연결하여

사용하시면 간편하게 사용하실수 있습니다.

리턴 값이 있는 함수라면 func를 아니면 Action을 사용하시면 됩니다.

 

 


조금 다른 형식의 Action도 한번 살펴보겠습니다.

 

public static class ClickeEvent {
    public static void AddEventListener<T>(this Button button, T param, Action<T> OnClick) {
        button.onClick.AddListener(delegate () {
            OnClick(param);
        });
    }
}

AddEventListener는 리스트나 나열된 아이템 등등에서 버튼을 스크립트로 달아야 할 때 사용할 수 있습니다.

T라는 제네릭을 받아 Action의 OnClick에 연결된 메서드에 T 제네릭인 param를 button에 연결해 줍니다.

조금 어렵습니다. 어떻게 동작하는지 계속 사용해 보셔야 이해가 되실 거라 봅니다.

 

public class Test : MonoBehaviour {
    Button testButtonA;
    Button testButtonB;
    string message = "테스트";
    DataModel dataModel;

    void Start() {
        dataModel = new DataModel();

        testButtonA = GetComponent<Button>();
        testButtonB = GetComponent<Button>();

        testButtonA.AddEventListener(message, TestButtonEventA);
        testButtonB.AddEventListener(dataModel, TestButtonEventB);
    }

    public void TestButtonEventA(string _messge) {
        print(_messge);
    }

    public void TestButtonEventB(DataModel _dataModel) {
        print(_dataModel.test);
    }
}

public class DataModel {
    public string test;
    public float no;
}

위에 코드는 실제 사용할 수 있는 예시입니다.

testButtonA 와 testButtonB라는 두 개의 버튼을 만들었습니다. 버튼이 두 개라면 당연히 리스트나 아이템에 들어갈 UI에 버튼이 달려 있어야 합니다.

 

testButtonA.AddEventListener(message, TestButtonEventA);

첫 번째 버튼에는 message라는 string을 연결하고 버튼이 클릭되었을 때 연결될 TestButtonEventA라는 메서드를 연결해 줍니다.

message 는 위에 보시면 T param 의 제네릭 값이 됩니다. 그리고

TestButtonEventA는 Action의 OnClick의 Button에 연결됩니다.

ButtonA에는 string을 전달했지만 제네릭 이기에 다른 것도 연결됩니다.

 

testButtonB.AddEventListener(dataModel, TestButtonEventB);

buttonB 에는 DataModel을 연결해서 전달해 주고 있습니다.

 

위에 이미지처럼 일반적은 버튼은 직접 메서드를 연결해 주지만 위에 예시처럼 Action을 사용해서 메서드를 연결해 주는 방법도 있습니다.

 

 

 

이상 델리게이트를 이해하는데 조금이나마 도움이 되었으면 합니다.

반응형