이벤트(event)란?
이벤트(event)는 델리게이트(delegate)를 안전하게 캡슐화(encapsulation)한 것입니다. 외부에서는 이벤트(event)를 구독하거나 구독 해제만 할 수 있고, 직접 호출할 수 없습니다.
이벤트(event)의 장점
- 캡슐화(encapsulation): 외부에서 직접 호출 불가
- 안전성: 클래스(class) 내부에서만 이벤트(event) 발생 가능
- 구독 패턴: 여러 구독자가 이벤트(event)를 구독 가능
이벤트(event) 선언 및 사용
using UnityEngine;
using System;
public class EventPublisher : MonoBehaviour
{
// 이벤트 선언
public event Action OnPlayerDeath;
public event Action<int> OnScoreChanged;
void Start()
{
// 이벤트 발생
OnPlayerDeath?.Invoke();
OnScoreChanged?.Invoke(100);
}
}
public class EventSubscriber : MonoBehaviour
{
public EventPublisher publisher;
void Start()
{
// 이벤트 구독
publisher.OnPlayerDeath += HandlePlayerDeath;
publisher.OnScoreChanged += HandleScoreChanged;
}
void OnDestroy()
{
// 이벤트 구독 해제 (메모리 누수 방지)
if (publisher != null)
{
publisher.OnPlayerDeath -= HandlePlayerDeath;
publisher.OnScoreChanged -= HandleScoreChanged;
}
}
void HandlePlayerDeath()
{
Debug.Log("플레이어가 사망했습니다!");
}
void HandleScoreChanged(int score)
{
Debug.Log($"점수가 변경되었습니다: {score}");
}
}
Unity 이벤트(event) 예시
using UnityEngine;
using UnityEngine.Events;
public class Button : MonoBehaviour
{
// Unity 이벤트 (Inspector에서 설정 가능)
public UnityEvent OnButtonClicked;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// 이벤트 발생
OnButtonClicked?.Invoke();
}
}
}
public class GameManager : MonoBehaviour
{
public Button button;
void Start()
{
// 이벤트 구독
button.OnButtonClicked.AddListener(HandleButtonClick);
}
void HandleButtonClick()
{
Debug.Log("버튼이 클릭되었습니다!");
}
}
델리게이트(delegate) vs 이벤트(event)
| 특징 | 델리게이트(delegate) | 이벤트(event) |
|---|---|---|
| 외부 호출 | ✅ 가능 | ❌ 불가능 |
| 구독/해제 | ✅ 가능 | ✅ 가능 |
| 캡슐화(encapsulation) | ❌ 없음 | ✅ 있음 |
| 안전성 | 낮음 | 높음 |
실전 활용 예시
예시 1: 게임 이벤트(event) 시스템
using System;
using UnityEngine;
public class GameEventManager : MonoBehaviour
{
// 싱글톤 패턴
public static GameEventManager Instance;
// 게임 이벤트들
public event Action OnGameStart;
public event Action OnGameOver;
public event Action<int> OnScoreChanged;
public event Action<int> OnHealthChanged;
void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
}
public void StartGame()
{
OnGameStart?.Invoke();
}
public void GameOver()
{
OnGameOver?.Invoke();
}
public void ChangeScore(int newScore)
{
OnScoreChanged?.Invoke(newScore);
}
public void ChangeHealth(int newHealth)
{
OnHealthChanged?.Invoke(newHealth);
}
}
// 사용 예시
public class UIManager : MonoBehaviour
{
void Start()
{
// 이벤트 구독
GameEventManager.Instance.OnGameStart += HandleGameStart;
GameEventManager.Instance.OnGameOver += HandleGameOver;
GameEventManager.Instance.OnScoreChanged += HandleScoreChanged;
}
void OnDestroy()
{
// 구독 해제
if (GameEventManager.Instance != null)
{
GameEventManager.Instance.OnGameStart -= HandleGameStart;
GameEventManager.Instance.OnGameOver -= HandleGameOver;
GameEventManager.Instance.OnScoreChanged -= HandleScoreChanged;
}
}
void HandleGameStart()
{
Debug.Log("게임 시작!");
}
void HandleGameOver()
{
Debug.Log("게임 오버!");
}
void HandleScoreChanged(int score)
{
Debug.Log($"점수: {score}");
}
}
예시 2: 플레이어 이벤트(event)
using System;
using UnityEngine;
public class Player : MonoBehaviour
{
public event Action<int> OnHealthChanged;
public event Action OnPlayerDeath;
public event Action<int> OnLevelUp;
private int health = 100;
private int level = 1;
public void TakeDamage(int damage)
{
health -= damage;
OnHealthChanged?.Invoke(health);
if (health <= 0)
{
OnPlayerDeath?.Invoke();
}
}
public void GainExperience(int exp)
{
// 경험치 획득 로직...
if (ShouldLevelUp())
{
level++;
OnLevelUp?.Invoke(level);
}
}
bool ShouldLevelUp()
{
// 레벨업 조건 체크
return true;
}
}
주의사항
- 메모리(memory) 누수: 이벤트(event) 구독 후 반드시 구독 해제
- null 체크: 이벤트(event) 호출 전 null 체크 필수
- 구독 해제: OnDestroy나 OnDisable에서 구독 해제
실전 활용 팁
팁 1: 이벤트(event) 구독 해제 패턴
void OnEnable()
{
// 구독
EventManager.OnEvent += HandleEvent;
}
void OnDisable()
{
// 반드시 구독 해제 (메모리 누수 방지)
EventManager.OnEvent -= HandleEvent;
}
팁 2: 안전한 이벤트(event) 호출
// ✅ 안전한 호출
OnEvent?.Invoke();
// 또는
if (OnEvent != null)
{
OnEvent.Invoke();
}
팁 3: UnityEvent 사용
using UnityEngine.Events;
// Inspector에서 설정 가능한 이벤트
public UnityEvent OnButtonClick;
// 코드에서 호출
OnButtonClick?.Invoke();
// Inspector에서 함수를 드래그 앤 드롭으로 연결 가능