이벤트 핸들러에 열광 할 수 있습니까? 내 디자인으로 "잘못된 길"을 가고 있습니까?


12

이벤트 핸들러를 정말 좋아하기로 결정했습니다. 분석 마비로 인해 약간의 고통을 겪을 수 있지만 디자인이 다루기 어려워 지거나 디자인 결정에 예기치 않은 다른 결과가 발생할 수 있습니다.

내 게임 엔진은 현재 패닝 오버 헤드 카메라로 기본 스프라이트 기반 렌더링을 수행합니다. 내 디자인은 다음과 같습니다.

SceneHandler

SceneListener 인터페이스를 구현하는 클래스 목록을 포함합니다 (현재 Sprite 만). 틱당 한 번 render ()를 호출하고 onCameraUpdate ()를 보냅니다. SceneListener에 메시지를 보냅니다.

입력 핸들러

틱당 한 번 입력을 폴링하고 간단한 "onKeyPressed"메시지를 InputListener에 보냅니다. SceneHandler 인스턴스를 보유하고 updateCamera ()를 트리거하는 Camera InputListener가 있습니다. 입력이 무엇인지에 따라 이벤트.

AgentHandler

틱당 한 번 모든 상담원 (AI)에 대한 기본 작업을 호출하고 등록 된 새 이벤트가 있는지 스택을 확인하여 필요에 따라 특정 상담원에게 전달합니다.

따라서 장면 주위를 이동하고 기본적인 조향 동작을 사용하여 이동할 수있는 기본 스프라이트 오브젝트가 있습니다. 충돌 감지에 착수했습니다. 여기가 제 디자인의 진행 방향이 확실하지 않은 곳입니다. 많은 작은 이벤트 처리기를 갖는 것이 좋은 방법입니까? 필자는 일종의 CollisionHandler를 구현해야한다고 생각합니다.

하나의 클래스에서 AI, 충돌 업데이트 및 기타 엔티티 상호 작용을 처리하는 더욱 통합 된 EntityHandler를 사용하는 것이 더 나을까요? 아니면 어떤 종류의 이벤트인지에 따라 서로에게 메시지를 전달하는 다양한 이벤트 처리 하위 시스템을 구현하는 것이 좋을까요? 이러한 모든 하위 이벤트 처리기를 조정하는 데 책임이있는 EntityHandler를 작성해야합니까?

InputHandler 및 SceneHandler와 같은 일부 경우에는 매우 구체적인 유형의 이벤트라는 것을 알고 있습니다. 내 게임 코드의 대부분은 입력에 신경 쓰지 않으며, 대부분은 장면 렌더링에서 발생하는 업데이트에 대해서는 신경 쓰지 않습니다. 따라서 나는 그 시스템의 고립이 정당하다고 생각한다. 그러나 나는이 질문을 구체적으로 게임 로직 유형 이벤트에 접근하고 있습니다.

답변:


21

이벤트 기반 디자인은 주로 Reactor 디자인 패턴을 구현합니다 .

컴포넌트를 설계하기 전에 그러한 패턴의 한계를 살펴 봐야합니다 (이에 대한 많은 정보를 찾을 수 있습니다).

문제의 첫 번째 및 가장 중요한 문제는 일부 serius를 수행 한 모든 GUI 기반 프레임 워크 및 Javascript 기반 응용 프로그램에서 잘 알고 있기 때문에 처리기가 신속하게 반환 해야 한다는 것입니다.

적절한 복잡성 을 가진 모든 응용 프로그램을 개발할 때 조만간 시간이 필요한 복잡한 작업 수행하는 처리기에 직면하게 됩니다 .

이 경우 두 가지 상황을 구별 할 수 있습니다 (상호 적으로 배타적이지는 않음).

복잡한 사건 관련 책임과 복잡한 사건 관련 책임.

복잡한 이벤트 관련 책임 :

첫 번째 경우에는 너무 많은 책임을 단일 구성 요소 처리기로 병합했습니다 . 예를 들어 이벤트에 대한 응답으로 너무 많은 작업이 수행되거나 동기화가 실행되고 있습니다.

이 경우 해결책은 처리기를 다른 처리기 (필요한 경우 다른 객체에서) 로 나누고 처리 코드를 직접 호출하는 대신 이벤트를 발생시키는 핸들을 만드는 것입니다. 이를 통해 이벤트 큐에 이벤트를 추가 한 후 기본 핸들러가 리턴 된 이후에 우선 순위가 높은 이벤트를 관리 할 수 ​​있습니다.

또 다른 해결책은 외부 엔티티가 이벤트를 발생 시키고 다른 사용자가 관심이있는 경우 구독하도록 허용하는 것입니다 (타이밍 이벤트는 일반화 할 수있는 가장 간단한 예입니다).

복잡한 사건 관련 책임 :

두 번째 경우 는 이벤트 이후에 수행해야 할 작업이 본질적으로 복잡 할 때 발생합니다 . 예를 들어 이벤트 후에 피보나치 수를 계산해야합니다.

여기서 Reactor 패턴은 기본적으로 실패 합니다. 피보나치 생성 알고리즘을 다음 단계를 트리거하기 위해 종료시 이벤트를 발생시키는 작은 청크로 분할 할 가치가 거의 없습니다.

여기서 해결책은 나사산 설계를 반응기 에 혼합하는 것입니다. 복잡성이 본질적인 경우 (따라서 올바른 섹션을 읽으면) 작업을 수행하고 독립적 인 나사산을 시작할 수있을 가능성이 큽니다. 나머지 Reactor 관련 구성 요소에 대해서는 거의 또는 전혀 알 필요가 없습니다.

상황의이 종류를 처리하기 위해, 나는 채택 유용하다고 작업 대기열을 넘는 유연한 스레드 풀 .

핸들러는 긴 조치를 시작해야하는 경우 해당 조치 를 작업 단위로 캡슐화 하여 작업 큐에 넣습니다. 이 캡슐화 된 조치에는 이벤트 를 원자로 스레드 에 트리거수단 이 있어야합니다 . 작업 큐 관리자는 자체 스레드 또는 리액터 스레드에서 실행될 수 있으며 "newJob"이벤트에 반응 할 수 있습니다.

작업 큐 관리자는 다음을 수행합니다.

  • 풀이 하나의 스레드를 제공 할 수있는 경우 (사용 가능한 스레드가 있거나 새 스레드 작성이 허용되는 경우) shedule 알고리즘을 사용하여 유연한 스레드 풀에서 스레드에 작업 단위를 할당합니다.

  • 풀 자체를 청취하여 작업 장치가 완료되었는지 확인하여 스레드가 복구되어 보류중인 장치를 하나 이상 실행할 수 있습니다 (있는 경우).

이벤트 발생 메커니즘을 사용하여 작업 단위는 완료, 업데이트 상태, 경고, 오류 또는 필요할 때마다 알리는 이벤트를 트리거 할 수 있습니다. 유연한 스레드 풀은 리소스를 효율적으로 사용하는 동시에 스레드가 전체 시스템을 정지시키는 것을 방지합니다. 작업 대기열을 사용하면 일관된 양의 계산 리소스가 필요하다는 것을 알기 때문에 다른 종류의 작업에 할당 할 우선 순위를 선택할 수 있습니다.


3
매우 철저한 +1 호기심 많은 독자들을위한 몇 가지 링크는 대단 할 것입니다.
sam hocevar

1

대부분의 경우 다른 옵션보다 이벤트를 사용하면 속도와 분산이 향상 될 수 있습니다. 많은 이벤트를 사용할 수 있다면 가야한다고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.