3. 먼저 온 사람
폴링? 이벤트?
왔는지 계속 체크한다
폴링(Pooling)
1. 성능 문제
폴링 방식은 주기적으로 상태를 체크해야하므로 성능 저하를 야기한다.
2. 정확성 문제
만약 잠깐 업데이트를 쉬는 사이에,
누군가 다녀갔다면 문 앞의 사람을 놓칠 수도 있다.
3. 자원 문제
문 앞에 사람이 없을 경우에도 계속해서 체크해야하므로 불필요하게 비효
율적이다.
이렇게 할 바에 그냥 도착하면 알려주세요…
4. 헐리우드 원칙
•"Don't call us, we'll call you.“
우리한테 연락하지 마세요. 우리가 당신에게 연락할게요.
프로그래밍 측면에서 보았을 때
놀라울 정도로 효율적인 문 열어주는 시스템!
이벤트(Event)
5. 탄생 배경
윈도우 프로그래밍
(Multi Task)
• 동시에 여러 프로그램 실행
• 다양한 이벤트 발생으로 흐름 예
측이 어려움
콘솔 프로그래밍
(Single Task)
• 한번에 하나의 프로그램만 실행
• 흐름을 예측할 수 있음
EDA(Event Driven Architecture)는
동시에 여러 프로그램이 실행되는 환경,
즉, 예측이 힘든 복잡한 상황에 대처하기위해 탄생했다.
6. Event
:일어나는 일
Driven
:특정 방향으로 몰고가다
Event-Driven
:어떤 일의 발생에 의해
특정 방향으로 가도록 된
Event Driven Architecture
이벤트에 의해 프로그램의 흐름이 결정되는 설계 방식
• 입력 (마우스, 키보드 등)
• 네트워크의 송수신
• 다른 프로그램으로부터의 메시지
• 기타 등등…
7. 게임과 이벤트
게임이란 복잡함의 결정체
온갖 이벤트가 난무하는 이벤트 대환장 파티
고로 게임 역시 이벤트 주도 방식으로 돌아간다
게임에는 대게 A이벤트(ex:타격) 발생 시,
연관된 게임 객체(ex:몬스터)들에게 이벤트를 알
려주고,
그 객체들이 이벤트에 반응할 수 있도록 도와주
는 이벤트 핸들링 이라는 방식을 사용한다.
이렇게 이벤트와 이벤트 핸들링은
이벤트 주도 방식의 핵심 요소!
• 플레이어가 몬스터에게 가까이 다가간다.
• 몬스터가 플레이어를 발견한다.
• 플레이어가 몬스터를 타격한다
• 몬스터의 HP가 줄어든다
기타 등등 거의 모든 것들이 이벤트로서 발생하고 처리 됨
8. 이벤트
이벤트는 간단하게 타입(Type) / 인자(Argument) 로 이뤄져있다
타입은 체력 수치 변동, 타격, 폭발, 아이템 획득과 같은 것들이고
인자는 해당 이벤트에 대한 구체적인 정보
Type : HP 수치 변동
Argument
대상 : 1번 플레이어
수치 : -10
이벤트는 함수의 인자로 넘기거나, 클래스로 만들어 넘기는 방식 등이 있음
9. 이벤트 캡슐화
• 이벤트 캡슐화의 이점
1. 단일 이벤트 핸들러 함수
여러 이벤트 타입에 대해 void OnEvent(Event& event) 와 같은
가상함수 하나만 있다면 모든 이벤트 타입에 대해 처리가 가능
2. 재사용성
함수 호출 방식으로는 함수 리턴 이후, 이벤트 인자를 사용 불가능
나중에 처리되도록 지연처리 방식으로 사용할 수도 있고
복사해서 사용하는등 다방면으로 이점이 있음
3. 이벤트 핸들링 용이
이벤트를 수신한 객체가 이벤트에 대해 전혀 몰라도 사용할 수 있음
예를들어 ‘탈것을 내린다’ 라는 이벤트의 경우
탈것 자체가 내린다 라는 개념이 없어도
승객 객체에 전달하는 식으로 사용할 수 있음
인자를 아예 하드코딩으로 박아버릴 수도 있고
Variant를 이용해 구현하는 방식도 있으며
해당 방식의 경우 고정크기(인자 4개,8개, 12개…) 식으로
메모리 할당 오버헤드를 피할 수도 있음
10. 이벤트 핸들러
• 객체가 이벤트(or 메시지,커맨드)를 받으면 어떤 식으로든 반응해야하는데
이 과정을 이벤트 핸들링이라고 부른다
이렇게 이벤트를 받아서 처리하는 함수를
‘핸들러’ 혹은 ‘콜백’ 이라 부른다
해당 코드와 같이 사용하게 될 경우 이벤트가 늘어날 수록
switch문이 기하 급수적으로 늘어남
윈도우 프로그래밍을 해보신 분이라면
뭔가 익숙한 모양새의 코드 일 것..
윈도우 메시지 역시 같은 방식으로 이벤트를 핸들링 한다
이벤트 주도 개발에 대해 어렵게 생각할 것 없이
윈도우도 이벤트 드리븐으로 이뤄졌다고 보면 됨
Switch문이 늘어나는게 싫다면
MFC의 메시지맵과 같은 방식을 적용할 수도 있음
11. 핸들러 바인딩과 델리게이트
이렇게 만들어진 핸들러를 어디에선가 호출하게 되는데
구현이 호출 위치에 묶이기 때문에 바인딩(Binding)
동적인 환경에서 바인드를 변경 불가능하기 때문에
이벤트 핸들러를 정적 바인딩(Static Binding)했다고 부른다.
(#컴파일러에서의 타입 바인딩과는 다름)
하지만 보통 이벤트 드리븐에서
진짜로 원하는 방식은 ‘동적 바인딩’ 이다
보통 C#이나 다른 언어에서는 Delegate 등으로
동적 바인딩을 지원하지만, C++에서는
동적 바인딩을 자체적으로 구현해 사용해야한다
런타임중 바인딩 변경이 가능한 동적 바인딩( Delegate 방식 )
런타임중 바인딩 변경이 불가능한 정적 바인딩
13. 이벤트 큐
보통은 이벤트가 보내진 즉시,
동기적으로 처리하는게 일반적이지만
모든 이벤트가 즉시 처리된다면,
이벤트 함수들이 불리는 순서는
예측 불가능하고 제어가 어려움
게임 객체들간의 이벤트 처리에는
순서에 민감한 영향을 받는 경우도 있기때문에
이를 위해 이벤트 큐를 사용함
생성자
중개자 핸들러
(CallBack)
이벤트 발생 소비자
이벤트 큐
이벤트
이벤트
이벤트
이벤트
14. 이벤트 큐
타이머 이벤트 우선순위 고려
CallStack
...
Character::OnEvent()
Event::Send()
Audio::PlayeSound()
Car::OnEvent()
Event::Send()
Animaiton::PlayerAnimation()
Car::OnEvent()
Event::Send()
Character::OnEvent()
Event::Send()
Car::OnEvent()
Event::Send()
Character::OnEvent()
Event::Send()
Car::Update()
GameWorld::UpdateObject()
Engine::GameLoop()
main
이벤트 즉시 처리시 보게되는 콜 스택
이벤트 큐를 사용 시
타이머로 지연 처리를 시킬수도 있고,
우선순위를 통해 처리 순서를 보장해줄 수도 있다.
또한 콜스택이 간결해지는 효과도 볼 수 있음
15. 데이터 드리븐과의 결합
그러나 여전히 이벤트를 보내고 받는 과정이 모두 하드코딩 되어있어,
모든 이벤트의 관리의 책임은 프로그래머의 일.
이벤트 주도 개발 시, 프로그래머는 언어가 지원하는
정적 바인딩 방식을 뛰어넘는 유연성을 가지는 이점이 있다
하지만 데이터 드리븐 방식을 결합하여
데이터에 의해, 이벤트가 실행되게 만든다면?
16. 정리
• 이벤트 드리븐에 대해 각자 해석이 다 다르다. 헷갈린다.
EDA, EDP, EDD 등등 용어도 많다.
• 이벤트 드리븐 아키텍쳐는 이벤트에 의해 흐름이 결정되도록 만드는
개발 방식을 말한다.
• 알게 모르게 전부 이벤트 드리븐으로 동작한다
(OS, 게임, GUI 등등)
• 언리얼도 고급진 이벤트 드리븐 시스템이 구축되어있다