ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 유니티 이벤트 완벽하게 이해하기 3 - 이벤트
    Unity, C#/Event 2019. 2. 19. 17:18

    C#의 이벤트에 대해서 정리해 보았습니다.

     

     

    이벤트


    A, B 오브젝트 사이에 커플링이라고 부르는 집적도를 없애기 위해 사용합니다.

    커플링은 두 오브젝트가 서로 심하게 엮여 있는 정도를 말합니다. 

    커플링이 심하면 A 오브젝트가 없어지거나 변경됐을 때 B 오브젝트가 영향을 받습니다. 


    이벤트를 사용하지 않을 경우

     

     

    Dead() 함수가 실행되면 B_Run()과 C_Run()을 실행해야 한다고 할 때

    이벤트를 사용하지 않을 경우엔

    A 클래스가 B와 C 클래스를 알고 있어야 합니다. 

    즉 서로 영향을 받기 때문에 커플링이 증가합니다.

    예제를 한 번 보겠습니다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class Booster : MonoBehaviour {
        
        public void HealthBoost(Character target)
        {
            Debug.Log(target.playerName + "의 체력을 강화합니다.");
            target.hp += 10;
        }
     
        public void ShieldBoost(Character target)
        {
            Debug.Log(target.playerName + "의 방어력을 강화합니다.");
            target.defense += 10;
        }
     
        public void DamageBoost(Character target)
        {
            Debug.Log(target.playerName + "의 공격력을 강화합니다.");
            target.damage += 10;
        }
    }
    cs

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Character : MonoBehaviour {
     
        // 이벤트를 사용하지 않을 경우엔 Character가 Booster를 알고 있어야 합니다.
        public Booster booster;
     
        public string playerName = "Daebal";
     
        public float hp = 100;
        public float defense = 50;
        public float damage = 30;
     
        void Awake()
        {
            // 새로운 부스터가 추가될 때마다 코드를 추가해야 합니다. 
            booster.HealthBoost(this);
    booster.ShieldBoost(this);
            booster.DamageBoost(this);
        }
    }
    cs


    이벤트를 사용하지 않을 경우 Character가 Booster에 대해 알고 있어야 하며,새로운 부스터가 추가될 때마다 코드에 추가해야 합니다.


    이벤트를 사용할 경우

     

     

    OnDead 라는 이벤트를 만들고 B와 C는 거기에 자신의 함수를 등록합니다.

    A는 OnDead에 어떤 함수가 등록되어 있는지 알지 못하고, B와 C는 OnDead가 언제 실행되는지 알지 

    못합니다. 

    즉 커플링이 낮기 때문에 서로에게 영향을 받지 않습니다.

     

    이벤트를 발동 시키는 측을 Publisher(발행자) 라고 합니다.

    이벤트에 등록하는 측을 Subcriber(구독자) 라고 합니다.

    쉽게 신문사를 생각하면 될 것 같습니다. 신문사에 신문을 받기를 원하는 사람이 자신을 등록해 놓으면 

    신문사가 구독자들에게 신문을 배달합니다. 즉 신문사가 Publisher, 신문을 받기를 원하는 사람이 

    Subcriber 가 됩니다.

     

    예제를 한 번 보겠습니다.

     

    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
    26
    27
    28
    29
    30
    public class Booster : MonoBehaviour {
        
        public void HealthBoost(Character target)
        {
            Debug.Log(target.playerName + "의 체력을 강화합니다.");
            target.hp += 10;
        }
     
        public void ShieldBoost(Character target)
        {
            Debug.Log(target.playerName + "의 방어력을 강화합니다.");
            target.defense += 10;
        }
     
        public void DamageBoost(Character target)
        {
            Debug.Log(target.playerName + "의 공격력을 강화합니다.");
            target.damage += 10;
        }
     
        void Awake()
        {
            // 여기서 마음껐 booster를 추가하거나 제거할 수 있습니다. 
            Character player = FindObjectOfType<Character>();
     
            player.playerBoost += HealthBoost;
            player.playerBoost += ShieldBoost;
            player.playerBoost += DamageBoost;
        }
    }
    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
    26
    public class Character : MonoBehaviour {
        
        public delegate void Boost(Character target);
     
        public Boost playerBoost;
     
        public string playerName = "Daebal";
     
        public float hp = 100;
        public float defense = 50;
        public float damage = 30;
     
        void Start()
        {
            playerBoost(this);
        }
     
        void Update()
        {
            if(Input.GetKeyDown(KeyCode.Space))
            {
     
                playerBoost(this);
            }
        }
    }
    cs

    델리게이트를 사용함으로써 더이상 booster 추가 유무에 상관없이 

    Character.cs에 코드 수정이 필요 없게 됩니다.

     

    그럼 event 키워드는 어디에 사용하는 걸까요?

     

    1
    2
    3
            player.playerBoost += HealthBoost;
            player.playerBoost += ShieldBoost;
            player.playerBoost += DamageBoost;
    cs

     

    실수 1

    위에 코드에서 개발자가 실수로 player.playerBoost = DamageBoost; 라고 입력하게 되면

    앞에 두줄의 코드 값은 사라져 버리고 player.playerBoost 에는 DamageBoost 의 함수포인터만 

    저장이 됩니다. 즉 실행하면 DamageBoost 의 결과값만 출력하게 되는 것입니다.

     

    실수 2

    Character에서 만들어진 이벤트는 Character(= Publisher) 에서만  발동이 되어야 합니다. 

    그런데 실수로 외부에서 player.playerBoost(player); 이라고 코딩을 하면 발동이 되어 버립니다. 

    이런 실수를 예방하기 위해서 Booster playerBoost; 앞에 event라는 키워드를 붙여서 위와 같은 경우

    코드 에러가 발생시킵니다.

     

    즉 아래와 같이 event를 추가합니다.

    public event Boost playerBoost;

     

    event 키워드를 추가함으로써 델리게이트의 기능이 이벤트가 아닌 방향으로 작동하는 것을 막아주는 것입니다.

     

    여기서 이벤트는 델리게이트를 사용해서 함수를 받을 수 있는 A라는 타입을 만들고, 이 A타입의 멤버 변수라고 생각하면 

    될 것 같습니다. 

     

     

     

    댓글

Designed by Tistory.