
2024-07-09

주로 GUI 프로그래밍 , 비동기 작업, 특정 조건이 충족되었을 때 실행되는 동작을 처리하는 데 사용한다.
Delegate 를 기반으로 하며, Event 를 구독하고 발생시키는 방식으로 동작한다.
구독자 패턴을 통해 여러 메서드를 한 번에 호출할 수도 있다.
퀘스트를 완료했을 때,
보상을 주는 메서드와 퀘스트 UI 를 업데이트 하는 메서드를
구독하고 호출하는 예시이다.
public class Quest : MonoBehaviour
{
public event Action onQuestCompleted;
public void CompleteQuest()
{
Debug.Log("Quest completed");
onQuestCompleted?.Invoke(); // 이벤트 호출
}
void Start()
{
onQuestCompleted += GiveReward;
onQuestCompleted += UpdateQuestUI;
}
private void GiveReward() // 보상 지급 로직
{
Debug.Log("Player received reward.");
}
private void UpdateQuestUI() // 퀘스트 UI 업데이트 로직
{
Debug.Log("Quest UI updated.");
}
}
대표적인 UnityEvent 로는 OnClick 이 있다.
버튼을 클릭한 후, 놓으면 호출되는 OnClick 이벤트를 통해
등록한 메서드를 호출할 수 있다.
💡 [캐릭터 피격 기능 연결]
레이어가 데미지를 받을 때 여러 기능이 한번에 작동하도록 시스템을 만드려고 합니다.
상태 메시지가 출력되고, 피격 이펙트가 나오며, 피격 사운드가 재생되는 메서드가 구현되어 있는 상황입니다.
DisplayStatus: 데미지 상태를 출력하는 메서드입니다.DisplayHitEffect: 피격 이펙트를 표시하는 메서드PlayHitSound: 피격 사운드를 재생하는 메서드
1) TakeDamage 함수 내에서 플레이어가 데미지를 받을 때 이벤트를 발생(Publish)시키는 코드를 작성합니다.
2) DisplayAndSound 클래스의 생성자에서 이벤트 발생 시 호출될 메서드(DisplayStatus,DisplayHitEffect,PlayHitSound)를 연결합니다.
⚠️주의!!!
조건 : 데미지를 받는 로직을 처리하는 TakeDamage 메서드 안에서DisplayStatus,DisplayHitEffect,PlayHitSound를 직접 호출하지 않고 코드를 완성해봅시다.
using System;
namespace GameEventExample
{
// 이벤트 데이터를 담는 EventArgs 파생 클래스
public class PlayerDamagedEventArgs : EventArgs
{
public int Damage { get; set; }
}
// 플레이어 클래스
public class Player
{
public int HP { get; private set; } = 100;
// 플레이어가 데미지를 받을 때 발생하는 이벤트를 정의하세요.
public event EventHandler<PlayerDamagedEventArgs> PlayerDamaged;
// 플레이어가 데미지를 받는 메서드
public void TakeDamage(int damage)
{
HP -= damage;
PlayerDamagedEventArgs e = new PlayerDamagedEventArgs { Damage = damage };
//
Q1. 이벤트가 등록되어 있는지 확인하고 이벤트를 발생
//
}
}
public class DisplayAndSound
{
public DisplayAndSound(Player player)
{
//
Q2. 각각의 이벤트 핸들러를 등록하세요.
//
}
// 데미지 상태를 출력하는 메서드
void DisplayStatus(object sender, PlayerDamagedEventArgs e)
{
Player player = sender as Player;
Console.WriteLine($"Player took {e.Damage} damage!");
Console.WriteLine($"Remaining HP: {player.HP}");
}
// 피격 이펙트를 표시하는 메서드
void DisplayHitEffect(object sender, PlayerDamagedEventArgs e)
{
Console.WriteLine("Displaying hit effect...");
}
// 피격 사운드를 재생하는 메서드
void PlayHitSound(object sender, PlayerDamagedEventArgs e)
{
Console.WriteLine("Playing hit sound...");
}
}
class Program
{
static void Main(string[] args)
{
Player player = new Player();
DisplayAndSound displayAndSound = new DisplayAndSound(player);
// 플레이어가 데미지를 받아 이벤트를 발생
player.TakeDamage(20);
Console.WriteLine($"Player HP: {player.HP}");
}
}
}
Q1
PlayerDamaged?.Invoke(this, e);
Q2 :
player.PlayerDamaged += DisplayStatus;
player.PlayerDamaged += DisplayHitEffect;
player.PlayerDamaged += PlayHitSound;
event 의 형식인 EventHandler 에 대해 먼저 알아보자.
문제에 사용된 event 는 EventHandler 이다.
System NameSpace 에서 지원하는 object 와 EventArgs 를 매개변수로 가지는
void 형식의 Delegate 이다.
문제에서
object sender 는 Player 이므로 this,
EvnetArgs e 는 PlayerDamagedEventArgs e 이다.
이벤트핸들러 구독과 취소 방법은 + , - 이다.
DisplayStatus, DisplayHitEffect, PlayHitSound 메서드를
PlayerDamager 이벤트핸들러에 구독하고 호출하여 사용할 수 있다.
유니티 에디터를 잘 다루는 것도 중요하지만, 이러한 이벤트와 델리게이트를 잘 활용하여
서로 관련이 없는 클래스들이 독립적으로 동작하게 하거나,
특정 이벤트가 발생할 때 호출되는 로직을 쉽게 재사용하는 방식도 알아둬야겠다.