Unity Chapter 8-3. C# 프로그래밍 [고급] : 이벤트

Date:     Updated:

카테고리:

태그:

인프런에 있는 이제민님의 레트로의 유니티 C# 게임 프로그래밍 에센스 강의를 듣고 정리한 필기입니다. 😀
🌜 [레트로의 유니티 C# 게임 프로그래밍 에센스] 강의 들으러 가기!


Chapter 8. C# 프로그래밍 : 고급


🔔 이벤트

  • 이전 포스트에서 공부했던 유니티 이벤트C#에서 제공하는 delegateEvent기능을 쉽게 사용할 수 있게끔 유니티에서 제공하는 기능이었다.

커플링

커플링 : 두 오브젝트가 잘 알고 지내고 하드하게 연결되어 있는 정도를 뜻한다.

  • 코드를 간결하게 하려면 커플링을 줄여야 한다.
    • A 와 B 사이에 커플링이 심하다는 말은 A 와 B 가 서로 엮여있는 정도가 높기 때문에 A 가 없어지면 B 의 코드를 수정하기가 쉽지 않다는 의미다.
    • 커플링을 줄이면 A 와 B 가 서로 모르는 사이가 되기 때문에 둘 중 하나가 없어져도 코드를 수정하기 수월해지거나 수정할 필요가 없게 된다.


이벤트를 사용하는 이유

커플링을 줄여 주기 때문.

  • A 클래스의 Dead() 함수가 실행될 때 B 클래스의 함수와 C 클래스의 함수가 실행될다고 할 때
    • 이벤트를 사용하지 않은 경우
      • image
      • A 클래스는 B, C 클래스를 알고 있어야 한다.
        • 따라서 B, C 클래스 참조 변수를 선언하고 슬롯에 B, C 스크립트가 붙은 오브젝트를 넣어주는 작업이 필요하다.
      • 커플링이 증가한다.
        • 따라서 B, C 클래스가 없어지면 A 클래스를 수정해야 하는 부분이 많이 생긴다.
    • 이벤트를 사용한 경우
      • image
      • A 클래스는 B, C 클래스에 대해 몰라도 된다.
        • A 클래스의 OnDead 이벤트에 B, C 클래스의 함수를 등록만 해두면 OnDead 이벤트가 실행되었을 때 알아서 B, C 클래스의 함수들이 실행되기 때문이다.
      • 커플링이 없다.
        • B, C 클래스가 없어져도 A 클래스 코드엔 영향이 없다.


이벤트 용어

  • 이벤트를 발동 시키는 측 👉 Publisher
  • 이벤트에 자기 자신의 기능을 등록시켜 놓고 대기하는 측 👉 Subcriber


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

📜Booster.cs

  • 📜Character의 hp, defense, damage를 증가시켜 준다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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;
    }
}

📜Character.cs

  • 📜Booster.cs 정보를 알고 있어야 한다.
    • 📜Booster.cs의 세 함수를 써야 📜Character의 hp, defense, damage를 증가시킬 수 있으므로.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Character : MonoBehaviour
{
    public Booster booster;

    public string playerName = "anso";
    public float hp = 100;
    public float defense = 50;
    public float damage = 30;

    void Awake()
    {
        booster.HealthBoost(this);
        booster.DamageBoost(this);
        booster.ShieldBoost(this);
    }
}
  • booter의 유니티 슬롯에 📜Booster.cs 가 붙은 오브젝트를 붙여주어야 한다.

booster.HealthBoost(this);, booster.DamageBoost(this);, booster.ShieldBoost(this); 이렇게 일일이 나열할 필요 없이 Event를 사용하여 Boost라는 이벤트HealthBoost, DamageBoost, ShieldBoost를 등록해 놓고 Boost라는 이벤트만 발생시키면 코드가 훨씬 간결해질 수 있다.


이벤트 사용한 경우

  • 사용 방법 👉 delegate와 일맥상통한다.
    • delegate로 이벤트를 만들 수 있다.
  • 📜Character.cs 가 📜Booster.cs를 알 필요가 없다.

📜Booster.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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()
    {
        Character player = FindObjectOfType<Character>();

        player.playerBoost += HealthBoost;
        player.playerBoost += ShieldBoost;
        player.playerBoost += DamageBoost;
    }
}
  • void Awake
    • 📜Booster에서 playerBoost 델리게이트에 📜Booster의 함수들을 등록해준다.
    • 📜Character에서 playerBoost 델리게이트를 void Start() 에서 실행할 것이라서 델리게이트 등록은 미리 void Awake에서 해주었다.
    • Character player = FindObjectOfType<Character>();
      • 📜Character.cs 가 붙은 player 오브젝트를 가져온 후
    • 델리게이트와 마찬가지로 +- 연산을 이용하여 델리게이트를 등록해준다.

📜Character.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Character : MonoBehaviour
{
    // public Booster booster;  알 필요가 없다.

    public delegate void Boost(Character target);

    public Boost playerBoost;

    public string playerName = "anso";
    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);
        }
    }
}
  • public delegate void Boost(Character target);
    • Boost라는 델리게이트를 선언
    • 리턴은 없으며 Character타입의 인수를 1개 받는 함수만 등록할 수 있다.
  • public Boost playerBoost;
    • 위에서 선언한 Boost 델리게이트 타입인 playerBoost를 정의했다.
    • BoostplayerBoost을 찍어냄.
  • playerBoost(this)
    • playerBoost에 등록된 모든 함수들을 실행시킨다.
      • 📜Character.cs가 붙은 오브젝트인 자기 자신을 인수로 넘긴다.


delegateevent 키워드 차이

delegate로 이벤트를 만들 수 있는데 C#엔 왜 event 키워드가 있을까?

  • delegate생성시 event를 앞에 붙여주면 델리게이트가 이벤트가 아닌 방향으로 사용되는 것을 엄격히 제한한다.

📜Character.cs

public delegate void Boost(Character target);

public event Boost playerBoost;  // event 키워드를 붙여 줌
  • playerBoost 델리게이트 생성시 event를 다음과 같이 써주면 함수를 이벤트에 등록할 때 덮어씌워지는 것을 방지해준다.

📜Booster.cs

player.playerBoost += HealthBoost;
player.playerBoost += ShieldBoost;
player.playerBoost = DamageBoost;  // 덮어씌우기 방지. 에러💥
  • +연산을 하지 않고 실수로 =만 해버리면 이벤트에 그대로 DamageBoost 함수 한개만 덮어씌워져 playerBoost실행시 DamageBoost 함수만 실행된다.
    • 이러면 이벤트를 사용하는 의미가 작아진다.
  • event를 붙여주면 이렇게 덮어씌워지는 것을 방지해준다. 에러가 난다.
    • event를 사용하면 이벤드 등록시 =는 안되고 +, -만 가능하다.

📜Booster.cs

player.playerBoost += HealthBoost;
player.playerBoost += ShieldBoost;
player.playerBoost(player); // 밖에서 실행 방지. 에러💥
  • event를 사용하면 밖에서 이벤트를 발동시킬 수 없다.
    • 이곳 저곳에서 멋대로 이벤트를 발동시키는 것을 방지.
    • 📜Character.cs 에서만 델리게이트를 발동시킬 수 있고 📜Character.cs 밖인 📜Booster.cs에선 발동시킬 수 없다.

📜Booster.cs

player.playerBoost += HealthBoost;
player.playerBoost += ShieldBoost;
player.playerBoost += DamageBoost;
  • 👆 event 사용시 올바른 등록 방법


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기


Unity Lesson 1 카테고리 내 다른 글 보러가기

댓글 남기기