Event Manager 시스템을 설계 할 때 고려해야 할 사항은 무엇입니까?


9

Java 게임 엔진의 기본 사항을 다루면서 Event Manager 시스템에 추가 할 수있는 시점에 도달했습니다.

나는 알고있다, 이론적으로 , 이벤트 관리자가해야 할 일 :에 객체가 특정 이벤트에 대해 "등록"을 허용하고, 이벤트 관리자가 이벤트를 통지됩니다 때마다 "등록"리스너에 이벤트를 방송. 내가 겪고있는 것은 그것을 구현하는 방법입니다.

온라인에서 이벤트 시스템을 처음부터 구현하는 것에 대해 아무것도 찾을 수 없었 으므로이 경우 모범 사례가 무엇인지, 내가 해야 하고 하지 않아야 할 것에 대한 정보를 찾고 있습니다.

예를 들어, 각 게임 오브젝트마다 EventManager필드 가 있어야 합니까? 모든 게임 오브젝트가 하나의 추상 상위 클래스에서 상속되므로 모든 게임 오브젝트간에 공유되는 이벤트 관리자 인스턴스가 하나만 있도록 정적 참조를 사용할 수 있어야한다고 생각합니다. 애플릿을 사용하여 이미 각 객체를 렌더링하는 데 사용하는 비슷한 작업을 수행합니다.

필자는 구독 가능한 각 이벤트에 대해 일종의 컬렉션을 유지 관리해야한다고 가정합니다. 필요에 따라 게임 개체를 목록에서 추가 및 제거합니다. 브로드 캐스트해야하는 이벤트 대기열을 만드는 것이 가능해야한다고 생각합니다.이 경우 "EventManager.Update ()"를 메인 게임 루프에 추가하고 Update()메소드가 마지막에 발생한 이벤트를 브로드 캐스트 할 수 있습니다. 각 프레임의. 마지막으로 각 객체에는 HandleEvent(Event e)적절한 구문 분석 및 응답 이 가능한 방법 이 있습니다 .


이것이 그러한 시스템을 구현하기위한 적절한 방향으로 들리나요, 아니면 궤도에서 벗어나거나 명백한 것을 놓치고 있습니까?


2
gamedev.stackexchange.com/questions/7718/… 시작에 도움이되는 이전에 제공된 Q / AI입니다.
James

@ James Ah-좋은 링크처럼 보입니다. 감사! 나는 그것을 일찍 놓쳤다 고 생각한다.
Raven Dreamer

4
몇 가지 추가 힌트 : 특히 이벤트 처리기가 추가 이벤트를 트리거하는 경우 일부 이벤트가 프레임 끝 대신에 실제로 적용되는지 여부를 결정하십시오. 이벤트 루프가 발생하면 어떻게 될지 생각해보십시오. 대기열을 사용하는 경우 우선 순위 시스템이 필요하거나 대기열을 우회하는 방법이 필요할 수 있습니다.
sam hocevar

답변:


6

이것은 원하는만큼 간단 할 수 있습니다.

for each object in the subscriber list:
    object.notify(this event) // (or 'HandleEvent' if you prefer)

이벤트 관리자가해야 할 일을 시도하지 마십시오. 필요한 작업을 수행하십시오. 나머지는 거기서부터 또는 최소한 더 구체적인 질문을 제안해야합니다.


3
"X가해야 할 일을 시도하지 말고 필요한 일을하라"는 +1 실제로 함수를 호출하는 분리 된 중앙 집중식 방법이 필요할 때까지 이벤트 관리자를 전혀 추가하지 마십시오.

@JoeWreschnig Oh god yes =) "필요한 작업을 수행하십시오."이것은 모든 개발자가 염두에 두어야 할 조언 중 3 가지입니다.
Patrick Hughes

처음에는 이벤트 관리자를 추가하지 않는 것에 대한 두 번째 문장에 동의하지 않고 싶었습니다. 대부분의 게임은 분리 된 중앙 집중 방식으로 함수를 호출하는 이점을 누릴 수 있었지만, 내가 만든 작은 게임이 몇 개인 지 모든 종류의 이벤트 관리자가 있습니다. 그래서, 그래
jhocking

3

이벤트 시스템에 필요한 세 가지 필수 메소드는 addListener () 메소드, removeListener () 메소드 및 dispatchEvent () 메소드입니다. 즉, 메소드 객체는 이벤트를 등록하는 데 사용하고, 메소드 객체는 등록을 해제하는 데 사용하며, 실제로 모든 리스너에게 이벤트를 브로드 캐스팅하는 방법입니다. 다른 모든 것은 그레이비입니다.

참고로 등록 된 리스너를 추적하려면 일종의 데이터 구조가 필요합니다. 가장 간단한 방법은 벡터 (또는 언어에 따라 간단히 배열)를 이벤트와 연결하는 연관 배열 (사전 또는 JavaScript의 객체)입니다. 이 벡터는 등록 된 모든 리스너의 목록입니다. 목록에 리스너를 추가하거나 add / removeListener () 메소드에서 리스너를 제거하십시오.

dispatchEvent ()에서 이벤트를 브로드 캐스트하려면 벡터를 반복하는 것만 큼 간단 할 수 있습니다. 이벤트 우선 순위 등을 정렬하여 디스패치에 복잡성을 추가 할 수 있지만 필요할 때까지 걱정하지 않아도됩니다. 많은 경우에 필요하지 않습니다.

이벤트와 함께 전달할 데이터를 고려할 때 dispatchEvent ()에는 약간의 뉘앙스가 있습니다. 가장 기본적인 수준에서는 추가 데이터를 전달하지 않을 수 있습니다. 모든 청취자는 이벤트가 발생했다는 것을 알아야합니다. 그러나 대부분의 이벤트에는 이벤트와 함께 추가 데이터가 있습니다 (예 : 이벤트가 발생한 위치) dispatchEvent ()가 일부 매개 변수를 수락하고 전달하도록 할 수 있습니다.

예를 들어, 각 게임 오브젝트 각각에 "EventManagner"필드가 있어야합니까? 내 게임 오브젝트는 모두 하나의 추상 부모 클래스에서 상속되므로 모든 게임 오브젝트간에 공유되는 EventManager 인스턴스가 하나만 있도록 정적 참조를 사용할 수 있어야한다고 생각합니다.

모든 게임 오브젝트에 EventManager 클래스에 대한 참조를 제공하는 방법에는 여러 가지가 있습니다. 정적 참조는 확실히 한 가지 방법입니다. 다른 하나는 싱글 톤입니다. 그러나이 두 가지 접근 방식은 모두 융통성이 없으므로 대부분의 사람들은 서비스 로케이터 또는 종속성 주입을 권장합니다. 의존성 주입을하고 있습니다. 그것은 각 객체에 대해 별도의 EventManager 필드를 의미하므로 피하고 싶은 것처럼 보이지만 왜 이것이 문제인지는 잘 모르겠습니다. 많은 포인터를 저장하는 데 많은 오버 헤드가있는 것은 아닙니다.


그렇습니다. 처음으로 종속성 주입을 파악하고 구현 한 것은 EventDispatcher 객체에 대한 것이 었습니다. 내 벨트 아래로 가져 가면 그 패턴으로 많은 것들을 리팩토링하는 데 가려워했습니다.
jhocking

0

기권

Java 프로그래머는 아니지만 가장 쉬운 언어 중 하나 인 C89에서 이벤트 시스템을 만드는 방법을 설명하는 기사를 작성했습니다.

https://prdeving.wordpress.com/2017/04/03/event-driven-programming-with-c-89/

이벤트 처리의 기본 사항은 매우 간단합니다.

  • 콜백으로 이벤트 등록
  • 트리거 이벤트
  • 리스너를 반복하여 일치하는지 확인하십시오.
  • 발견되면 소방관
  • 반복

이것을 알고 있지만 (Java로 구현하는 방법을 모르는 경우), 일부 처리기 (이벤트를 처리하는 함수)가 필요하다는 것을 이해하고 이벤트 이름과 쌍을 이루는 배열 (C의 포인터 포함)에 추가 할 수 있습니다. 이벤트를 트리거하면 트리거 된 이벤트 이름과 인수가 스택에 저장되며이를 이벤트 풀이라고합니다.

그런 다음 해당 스택의 첫 번째 이벤트를 팝업하고 처리기를 찾은 다음 이벤트 매개 변수를 사용하여 이벤트 다이제스트 (간단한 루프)를 수행합니다.

물론이 이벤트 다이제스트는 원할 때마다 (예 : Update()함수 를 호출 한 후 프레임 당 한 번) 트리거 될 수 있습니다 .


-2

EventManager 필드의 경우 정적 변수를 사용하십시오. EventManager의 싱글 톤도 좋은 아이디어입니다.

당신의 접근 방식은 좋아 보이지만 스레드로부터 안전하게 만드는 것을 잊지 마십시오.

"GameEvent"이전 또는 이후에 IO 이벤트를 실행하는 것이 좋습니다. 따라서 "GameEvent"마다 한 프레임에서 동일한 데이터를 처리합니다.


"나사 저장"? 흠
U62

완전히 불필요하고 정당화되지 않은 싱글 톤 제안의 경우 -1입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.