게임 이벤트 발생
이벤트를 생성하고 설정한 후, 마지막 단계는 게임 로직에서 이벤트를 트리거하는 것입니다. 이 페이지에서는 게임 이벤트가 어떻게 작동하는지, 그리고 스크립트에서 이벤트를 발생시키는 방법을 설명합니다.
- ✅ 이벤트 생성 → 게임 이벤트 생성기
- ✅ 액션 설정 → 게임 이벤트 비헤이비어
- ✅ 이벤트 발생 ← 현재 단계
🎯 게임 이벤트 작동 방식
게임 이벤트는 **이벤트 발생(Raising)**과 **액션 실행(Action Execution)**을 분리(Decouple)합니다.
전통적인 방식:
// ❌ 강하게 결합됨(Tightly coupled) - 문 로직이 사운드, 애니메이션 등을 직접 알고 있어야 함
public class Door : MonoBehaviour
{
public AudioSource audioSource;
public Animator animator;
public UIManager uiManager;
public void Open()
{
audioSource.Play();
animator.SetTrigger("Open");
uiManager.ShowNotification("Door opened");
// 로직이 여러 의존성에 흩어져 있음
}
}
게임 이벤트 방식:
// ✅ 디커플링됨 - 문은 단지 "무언가 일어났다"는 것만 알면 됨
public class Door : MonoBehaviour
{
[GameEventDropdown]
public GameEvent onDoorOpened;
public void Open()
{
onDoorOpened.Raise(); // 인스펙터에서 설정된 액션들이 실행됨
}
}
핵심 차이점: 액션(사운드, 애니메이션, UI 등)은 스크립트에 하드코딩되지 않고, 이벤트 비헤이비어에서 시각적으로 설정됩니다.
📝 기본 사용법: 이벤트 발생시키기
1단계: 스크립트에서 이벤트 참조하기
using TinyGiants.GameEventSystem.Runtime;
using UnityEngine;
public class DoorController : MonoBehaviour
{
[GameEventDropdown] // 스마트 인스펙터 선택기
public GameEvent onDoorOpened;
[GameEventDropdown]
public GameEvent onDoorClosed;
public void OpenDoor()
{
// 문의 로직 처리
onDoorOpened.Raise(); // 이벤트 트리거
}
public void CloseDoor()
{
// 문의 로직 처리
onDoorClosed.Raise();
}
}
2단계: 인스펙터에서 이벤트 할당하기
[GameEventDropdown] 속성은 타입 안정성이 보장된 검색 가능한 드롭다운을 제공합니다.

주요 기능:
- 🔍 유사 검색(Fuzzy Search): 이름을 입력하여 이벤트를 필터링
- 📁 카테고리화: 데이터베이스 및 카테고리별로 그룹화된 이벤트
- 🔒 타입 안정성: 호환되는 이벤트 타입만 표시
- ⚡ 빠른 접근: 에셋을 직접 드래그할 필요 없음
대안: [GameEventDropdown] 없이 사용하기
표준 public 필드를 사용할 수도 있습니다.
public GameEvent onDoorOpened; // 표준 ScriptableObject 필드
인스펙터 뷰:

워크플로우:
- 프로젝트 창(이벤트 데이터베이스)에서 이벤트 에셋을 찾음
- 인스펙터 필드로 드래그 앤 드롭
권장 사항: 더 빠르고 타입 안정성이 보장되는 **[GameEventDropdown]**을 사용하는 것이 좋습니다.
🎨 타입 지정 이벤트 (인자 포함)
이벤트는 액션에 데이터를 전달할 수 있습니다.
Void 이벤트 (데이터 없음)
[GameEventDropdown]
public GameEvent onGameStart;
void Start()
{
onGameStart.Raise(); // 인자 없음
}
단일 인자 이벤트
[GameEventDropdown]
public GameEvent<float> onHealthChanged;
private float health = 100f;
public void TakeDamage(float damage)
{
health -= damage;
onHealthChanged.Raise(health); // 현재 체력 값을 전달
}
타입 안정성: 드롭다운에 GameEvent<float> 타입의 이벤트만 표시되어 타입 불일치를 방지합니다.
송신자(Sender) + 인자 이벤트
[GameEventDropdown]
public GameEvent<GameObject, DamageInfo> onPlayerDamaged;
public void ApplyDamage(DamageInfo damageInfo)
{
// Sender = 이 GameObject, Args = 데미지 정보
onPlayerDamaged.Raise(this.gameObject, damageInfo);
}
사용 사례: 액션에서 누가 이벤트를 트리거했는지와 어떤 데이터를 처리해야 하는지 모두 알아야 할 때 사용합니다.
🔒 타입 안정성 작동 원리
드롭다운은 필드 타입에 따라 이벤트를 자동으로 필터링합니다.
public class ScoreManager : MonoBehaviour
{
[GameEventDropdown]
public GameEvent<int> onScoreChanged; // GameEvent<int>만 표시됨
[GameEventDropdown]
public GameEvent<int> onLevelUp; // GameEvent<int>만 표시됨
private int score = 0;
public void AddScore(int points)
{
score += points;
onScoreChanged.Raise(score); // 정수형 점수 전달
}
}
드롭다운 필터링 예시:
GameEvent<int>에 사용 가능한 이벤트:
✅ OnScoreChanged (int)
✅ OnLevelUp (int)
✅ OnComboMultiplier (int)
❌ OnPlayerDeath (void) — 필터링됨 (타입 불일치)
❌ OnDamage (float) — 필터링됨 (타입 불일치)
이 기능이 중요한 이유: 런타임이 아닌 에디터 수정 시점에서 타입 오류를 잡아낼 수 있습니다.
🔄 예약된 이벤트 취소하기
이벤트가 지연(Delay) 또는 반복(Repeat) 설정( **게임 이벤트 비헤이비어**에서 설정)을 사용하는 경우, 실행을 취소할 수 있습니다.
[GameEventDropdown]
public GameEvent repeatingSoundEvent;
void StartAmbientSound()
{
repeatingSoundEvent.Raise(); // 반복 시작 (비헤이비어 설정 기준)
}
void StopAmbientSound()
{
repeatingSoundEvent.Cancel(); // 예약된 실행 중지
}
사용 사례:
- 플레이어가 트리거 구역을 벗어남 → 주변 환경 사운드 취소
- 게임 일시 정지 → 예약된 타이머 이벤트 취소
- 오브젝트 파괴 → 예약된 액션 정리
🔧 고급: 인스펙터 리스너 제어
자주 사용되지는 않지만, 런타임에 인스펙터에서 설정된 액션을 비활성화할 수 있습니다.
[GameEventDropdown]
public GameEvent myEvent;
void DisableCutsceneUI()
{
myEvent.SetInspectorListenersActive(false);
// 인스펙터 액션은 실행되지 않고, 코드 리스너만 실행됨
}
void EnableCutsceneUI()
{
myEvent.SetInspectorListenersActive(true);
// 인스펙터 액션이 다시 실행됨
}
사용 사례:
- 컷씬 동안 UI 업데이트를 일시적으로 중단
- 게임 상태에 따라 액션 세트 간 전환
💡 전체 워크플로우 예시
시각적 워크플로우를 사용하여 완전한 문(Door) 시스템을 만들어 봅시다.
1단계: 이벤트 생성
**게임 이벤트 생성기**에서:

OnDoorOpened(void 이벤트) 생성OnDoorClosed(void 이벤트) 생성
2단계: 액션 설정
**게임 이벤트 비헤이비어**에서:

OnDoorOpened 이벤트:
- 액션:
AudioSource.PlayOneShot(doorOpenSound) - 액션:
Animator.SetTrigger("Open") - 액션:
ParticleSystem.Play()(먼지 효과)
OnDoorClosed 이벤트:
- 액션:
AudioSource.PlayOneShot(doorCloseSound) - 액션:
Animator.SetTrigger("Close")
3단계: 스크립트 작성
using TinyGiants.GameEventSystem.Runtime;
using UnityEngine;
public class DoorController : MonoBehaviour
{
[GameEventDropdown]
public GameEvent onDoorOpened;
[GameEventDropdown]
public GameEvent onDoorClosed;
private bool isOpen = false;
public void ToggleDoor()
{
if (isOpen)
{
isOpen = false;
onDoorClosed.Raise(); // 모든 액션이 자동으로 실행됨
}
else
{
isOpen = true;
onDoorOpened.Raise(); // 모든 액션이 자동으로 실행됨
}
}
// 이 메서드는 다음에서 호출될 수 있습니다:
// - 인스펙터의 Button OnClick
// - 충돌/트리거 감지
// - 기타 게임 시스템
}
4단계: 인스펙터에서 이벤트 할당

DoorControllerGameObject 선택- 드롭다운을 사용하여
OnDoorOpened이벤트 할당 - 드롭다운을 사용하여
OnDoorClosed이벤트 할당
완료! 스크립트에는 사운드, 애니메이션 또는 VFX 참조가 전혀 없으며, 모든 것이 시각적으로 설정되었습니다.
🆚 왜 UnityEvent보다 나은가요?
전통적인 UnityEvent 방식에는 게임 이벤트가 해결해 주는 몇 가지 한계가 있습니다.
전통적인 UnityEvent의 한계
// ❌ 문제 1: 설정이 여러 GameObject에 흩어져 있음
public class Button1 : MonoBehaviour
{
public UnityEvent onClick; // Button1의 인스펙터에서 설정됨
}
public class Button2 : MonoBehaviour
{
public UnityEvent onClick; // Button2의 인스펙터에서 설정됨
}
// ❌ 문제 2: 모든 사용처를 찾기 어려움
// 씬의 모든 GameObject를 수동으로 뒤져야 함
// ❌ 문제 3: 중앙 제어 불가
// 버튼 사운드를 전역적으로 켜고 끌 수 없음
// ❌ 문제 4: 중복 작업
// 50개의 버튼에 동일한 사운드/VFX 설정이 반복됨
게임 이벤트의 장점
// ✅ 해결책: 모든 버튼이 동일한 이벤트를 발생시킴
public class ButtonController : MonoBehaviour
{
[GameEventDropdown]
public GameEvent onButtonClick; // 모든 버튼에 동일한 이벤트 사용
public void OnClick()
{
onButtonClick.Raise();
}
}
이점:
| 기능 | UnityEvent | 게임 이벤트 |
|---|---|---|
| 중앙 집중식 설정 | ❌ GameObject마다 설정 | ✅ 하나의 이벤트 비헤이비어 |
| 모든 사용처 찾기 | ❌ 수동 검색 | ✅ 이벤트 파인더 |
| 전역 제어 | ❌ 50개 오브젝트 수정 | ✅ 하나의 이벤트 수정 |
| 재사용성 | ❌ 복사 붙여넣기 | ✅ 동일한 에셋 참조 |
| 조건부 로직 | ❌ 코드 작성 필요 | ✅ 시각적 조건 트리 |
| 디버깅 | ❌ 인스펙터만 가능 | ✅ 플로우 그래프 시각화 |
각각 언제 사용해야 하나요?
UnityEvent 사용:
- 일회성 단순 콜백 (예: 튜토리얼 버튼)
- 컴포넌트 전용 로직 (예: 슬라이더가 자신의 라벨을 업데이트)
- 재사용성이 필요 없는 경우
게임 이벤트 사용:
- 재사용 가능한 로직 (예: 모든 버튼 클릭 시 동일한 사운드 재생)
- 복잡한 시퀀스 (예: 컷씬, 문의 퍼즐)
- 중앙 제어가 필요한 경우 (예: 모든 UI 사운드 음소거)
- 시각적 디버깅이 필요한 경우 (플로우 그래프)
❓ 문제 해결
드롭다운에 "Manager Missing"이라고 뜸
원인: 씬에 GameEventManager가 없습니다.
해결 방법:
유니티 상단 툴바에서 게임 이벤트 시스템을 엽니다.
Tools > TinyGiants > Game Event System
"Initialize Event System" 버튼을 클릭하면 씬에 Game Event Manager GameObject(싱글톤)가 생성됩니다.
드롭다운에 "No Active Databases"라고 뜸
원인: GameEventManager에 할당된 데이터베이스가 없습니다.
해결 방법:
- 씬에서
GameEventManager선택 - 인스펙터 → Databases 섹션
- 이벤트 데이터베이스 추가
드롭다운에 "No Matching Events"라고 뜸
원인: 필드 타입과 일치하는 이벤트가 없습니다.
예시:
[GameEventDropdown]
public GameEvent<string> textEvent; // GameEvent<string>이 필요함
// 하지만 데이터베이스에는 다음만 있는 경우:
// - GameEvent (void)
// - GameEvent<int>
// - GameEvent<float>
결과: 일치하는 이벤트 없음!
해결 방법: 게임 이벤트 생성기를 사용하여 올바른 타입의 이벤트를 생성하세요.
이벤트가 발생하지 않음
체크리스트:
- ✅ 인스펙터에 이벤트 에셋이 할당되어 있습니까?
- ✅
Raise()가 호출되고 있습니까? (Debug.Log로 확인) - ✅ 게임 이벤트 비헤이비어에서 액션이 설정되어 있습니까?
- ✅ 조건이 충족되고 있습니까? (조건 트리 확인)
- ✅ 씬에 GameEventManager가 있습니까?
이제 전체 시각적 워크플로우를 익혔습니다:
- ✅ 이벤트 생성기에서 이벤트 생성
- ✅ 이벤트 비헤이비어에서 액션 설정
- ✅ UnityEvent 또는
GameEventDropdown으로 이벤트 발생
결과: 디커플링되고 유지보수가 쉬우며 디자이너 친화적인 게임 로직 완성!
이 페이지는 시각적 워크플로우(인스펙터 할당을 통한 스크립트 내 이벤트 발생)를 다룹니다. 고급 코드 기법(런타임 리스너, 조건부 트리거, 이벤트 체인 등)은 **런타임 API**를 참조하세요.