본문 바로가기
개발/게임 디자인 패턴

게임 디자인 패턴 11. 이벤트 큐 (Event Queue) 패턴

by 석시 2023. 11. 6.



이벤트 큐 패턴이다.

왜 이벤트에 큐를 사용하지? 라는 의문이 들 수 있다.

그것을 지금부터 설명해보고자 한다.


이벤트 vs 메시지

일단 모든 것을 설명하기 앞서 가장 먼저 짚고 넘어가야 할 것 중 하나다.

생각보다 이벤트와 메시지를 구분하지 못하는 경우가 많다.

정리하자면 이렇다.

이벤트이미 일어난 사건이다. 몬스터가 죽었거나, 투사체에 맞았거나 하는 등의 사건이 이벤트가 되겠다. 즉, 이 이벤트를 복수의 리스너가 들을 수 있도록 구현할수도 있는 것이다.

메시지받는 사람이 했으면 하는 행동을 표현한 것이다. 경험치를 얻는다던지, 사운드를 재생한다던지 등의 표현이 메시지가 되는 것이다. 보통은 리스너가 하나다. 여러 리스너가 하도록 구현할 수도 있지만, 모두 형식을 통일해줘야 될뿐더러 그럴 이유도 딱히 없다.


이벤트 ‘큐’를 쓰는 이유가?

그래서 이벤트에 큐를 붙이는 이유는 이벤트(메시지)를 보내는 시점과 처리하는 시점을 디커플링하기 위해서 이다.

헷갈리지 말자. 명령 패턴이나 관찰자 패턴은 이벤트를 보내는 곳과 받는 곳을 분리하는 것이다.

두 패턴 모두 처리 시점은 동일하다.

시점을 왜 나눠야 하는지 역시 궁금할 수 있을 것이다.

다음의 예시를 보자.

public void PlayShieldSound(bool isOn)
{
    Sound.clip = isOn ? Sound_ShiledOn : Sound_ShiledOff;
    Sound.Play();
}

쉴드가 켜졌을 때 사운드를 재생하는 간단한 코드이다.

해당 쉴드는 다음과 같이 이벤트에 구독이 되어있는 상태이다.

OnShieldChange += AudioManager.Instance.PlayShieldSound;

문제는 쉴드를 빠르게 연속해서 두 번 먹었을 때 나타난다.

사운드가 두 번 재생될텐데, 이게 겹쳐서 재생되는 것이 문제다.

이러면 플레이어에게는 사운드 두 개가 분리되어 들리는 것이 아니라 그냥 큰 소리가 들리는 것이다.

메시지 처리 쓰레드를 원하는대로 설정해줄 수 없다는 점은 덤이다. (이벤트가 발생한 쓰레드에서 메시지를 처리한다.)

따라서 이벤트 큐를 이용해 상황에 따라 메시지를 다르게 전달해줄 수 있는 것이다.

비동기형 관찰자 패턴이라고 생각하면 좋다.


디자인 요소

  1. 큐에 무엇을 넣을 것인가?

큐에 이벤트를 넣을 수도 있고, 메시지를 넣어야 할 수도 있다.

이벤트를 넣는 경우 리스너가 여러 개를 만들 때 좀더 쉬울 수 있다.

큐에 메시지를 넣을 경우는 보통 리스너가 한 개이다.

작동 방식이 마치 비동기 API 호출과도 같을 것이다.

  1. 누가 큐를 읽는가?

이벤트 큐의 공개 범위를 결정하는 것이다.

큐가 어떤 클래스의 일부일 때는 싱글캐스트 큐, 어디서든 큐에 접근이 가능할 경우는 브로드캐스트 큐라고 부른다.

싱글캐스트 큐의 경우는 더 캡슐화가 되어 있고, 경쟁 상태를 고려하지 않아도 된다는 장점이 있다.

리스너가 여러 개일 경우를 고려할 필요가 없도록 구성할 수 있다는 의미이다.

브로드캐스트 큐의 경우는 대부분의 이벤트 시스템이 사용하는 방식이고, 처음 구현 자체는 쉽겠지만 리스너가 없는 이벤트가 무시될 수도 있고 이벤트 필터링이 필요해질 수 있다는 단점을 가진다.

번외로 작업 큐라는 것도 있다.

큐에 들어 있는 데이터가 리스너 중 한 곳만 가는 방식으로, 동시 실행중인 스레드 풀에 작업을 나눠줘야 하는 경우 사용하는 방식이다.

  1. 누가 큐에 값을 넣는가?

넣는 측이 하나인 경우와 여러 개인 경우를 나눌 수 있을 것이다.

넣는 측을 하나로 할 경우, 어디서 이벤트가 오는지 암시적으로 알 수 있다는 아주 큰 장점이 있다.

하지만 어쩔 수 없이 여러 곳에서 이벤트를 보낼 수 있도록 구현해야 할 경우도 있을 것이다.

이 때는 이벤트 순환이라는 것을 주의해야 한다.

A 이벤트를 보낸 리스너가 B 이벤트를 보낸 후, 그것을 받은 리스너가 또 A 이벤트를 보내게 된다면, 계속해서 이벤트가 보내지고 받아질 것이다.

이는 이벤트 큐가 비동기적으로 작동하기 때문에 더욱 문제가 되는 것이다.

이런 문제들을 방지하기 위해 이벤트를 누가 보냈는지를 이벤트에 추가해야 할 수도 있는 것이다.


Uploaded by N2T