XBox 컨트롤러를 추상화하는 올바른 방법


12

응용 프로그램의 입력으로 사용하려는 XBox360 컨트롤러가 있습니다.

내가 해결할 수없는 것은 인터페이스를 통해 이것을 노출시키는 가장 좋은 방법입니다.

배후에서 컨트롤러를 처리하는 클래스는 폴링 버튼 상태에 의존합니다.

나는 처음에 무언가를 시도했다.

Event ButtonPressed() as ButtonEnum

어디 ButtonEnum했다 ButtonRed, ButtonStart등 ...

이것은 버튼 누름 만 지원하고 보류 / 패턴 (두 번 누르기 등)이 아니라는 점에서 약간 제한적입니다.

다음 아이디어는 단순히 버튼 상태를 앱에 노출시키는 것입니다.

Property RedPressed as Boolean
Property StartPressed as Boolean
Property Thumb1XAxis as Double

이것은 매우 유연하지만 실제로 앱에 너무 많은 작업을 강제하고 앱이 폴링해야합니다. 가능하면 이벤트 중심을 선호합니다.

여러 이벤트를 추가하는 것을 고려했습니다. 예 :

Event ButtonPressed(Button as ButtonEnum)
Event ButtonPressedTwice(Button as ButtonEnum)
Event ButtonHeldStart(Button as ButtonEnum)
Event ButtonHeldEnd(Button as ButtonEnum)

그러나 이것은 약간 어렴풋하게 보이고 "바인드 버튼"화면에서 실제 고통이었습니다.

누군가 컨트롤러의 입력을 처리하는 "올바른"방법을 알려 주시겠습니까?

NB : 인터페이스를 구현하는 클래스 내에서 SlimDX를 사용하고 있습니다. 이를 통해 상태를 매우 쉽게 읽을 수 있습니다. 내 문제를 해결할 수있는 대안도 높이 평가됩니다.

답변:


21

360 컨트롤러에 적합한 대부분의 식별자가 PlayStation 컨트롤러 (X 대신 A, Circle 대신 B)에 맞지 않기 때문에 플랫폼 별 추상화를 제공하는 완벽한 매핑은 없습니다. 물론 Wii 컨트롤러는 또 다른 것입니다.

이 문제를 해결하는 가장 효과적인 방법은 세 가지 구현 계층을 사용하는 것입니다. 하위 계층은 전적으로 플랫폼 / 컨트롤러에 따라 다르며 사용 가능한 디지털 버튼 및 아날로그 축 수를 알고 있습니다. 이 계층은 하드웨어 상태를 폴링하는 방법을 알고있는이 계층이며, 버튼을 눌렀을 때 또는 한 번 이상 눌렀는지 또는 눌리지 않았는지 알 수있을 정도로 이전 상태를 충분히 기억하는 계층입니다. . 그 외에는 바보입니다-단일 유형의 컨트롤러를 나타내는 순수한 상태 클래스. 실제 값은 컨트롤러 상태를 중간 계층에서 멀리 쿼리하는 것이 중요합니다.

중간 레이어는 실제 버튼에서 게임 개념으로의 실제 컨트롤 매핑입니다 (예 : A-> 점프). 더 이상 특정 컨트롤러 유형에 바인딩되지 않기 때문에 버튼 대신 임펄스라고 부릅니다. 이 레이어에서 컨트롤을 다시 매핑 할 수 있습니다 (개발 중에 또는 사용자의 요청에 따라 런타임에). 각 플랫폼에는 가상 임펄스에 대한 고유 한 컨트롤 매핑이 있습니다 . 당신은 이것으로부터 도망 칠 수 없으며 그렇게해서는 안됩니다. 모든 컨트롤러는 고유하며 고유 한 매핑이 필요합니다. 버튼은 둘 이상의 임펄스에 매핑 될 수 있으며 (게임 모드에 따라 다름), 둘 이상의 버튼이 동일한 임펄스에 매핑 될 수 있습니다 (예 : A 및 X는 가속, B 및 Y는 감속). 매핑은 그 모든 것을 정의합니다.

상위 계층은 게임 계층입니다. 충동이 필요하며 어떻게 생성되었는지는 신경 쓰지 않습니다. 컨트롤러 나 컨트롤러의 녹음에서 나왔거나 AI에서 나왔을 수도 있습니다. 이 수준에서는 상관 없습니다. 당신이 신경 쓰는 것은 새로운 점프 임펄스가 있거나 가속 임펄스가 계속되었거나 다이브 임펄스 가이 틱의 0.35 값이라는 것입니다.

이러한 종류의 시스템을 사용하면 각 컨트롤러에 대해 맨 아래 계층을 한 번 작성합니다. 상위 계층은 플랫폼 독립적입니다. 중간 계층의 코드는 한 번만 작성하면되지만 각 플랫폼 / 컨트롤러마다 데이터 (리 맵핑)를 다시 작성해야합니다.


이것은 매우 깨끗하고 우아한 접근법처럼 보입니다. 감사합니다!
기본

1
아주 좋아요 내 것보다 훨씬 낫다 : P
Jordaan Mylonas

3
아주 좋은 추상화. 그러나 구현할 때주의하십시오 : 모든 사용자 조치에 대해 새 임펄스 오브젝트를 작성 및 파괴하지 마십시오. 풀링을 사용하십시오. 가비지 수집가가 감사합니다.
grega g

물론. 최대 동시 임펄스 수로 크기가 정해지는 정적 배열은 거의 항상 최선의 선택입니다. 거의 항상 한 번에 하나의 각 임펄스 인스턴스 만 활성화하기를 원하기 때문입니다. 대부분의 경우 해당 배열에는 몇 개의 항목 만 있으므로 반복하는 것이 빠릅니다.
MrCranky

@grega 모두 감사합니다-나는 그것을 생각하지 못했습니다.
기본

1

솔직히 말해서, 최적의 인터페이스는 게임의 사용법에 크게 의존 할 것입니다. 그러나 일반적인 사용 시나리오의 경우 이벤트 기반 및 폴링 기반 방식을 분리하는 2 계층 아키텍처를 제안합니다.

하위 계층은 "폴링 기반"계층으로 간주 될 수 있으며 버튼의 현재 상태를 노출합니다. 그러한 인터페이스 중 하나는 단순히 2 개의 기능을 가질 수 있으며 GetAnalogState(InputIdentifier), GetDigitalState(InputIdentifier)어디에 InputIdentifier어떤 버튼, 트리거 또는 스틱을 검사하고 있는지를 나타내는 열거 된 값이 있습니다. 단추에 대해 GetAnalogState를 실행하면 1.0 또는 0.0이 반환되고, 아날로그 스틱에 대해 GetDigitalState를 실행하면 사전 설정된 임계 값을 초과하면 true를, 그렇지 않으면 false를 반환합니다.

두 번째 계층은 하위 계층을 사용하여 상태 변경시 이벤트를 생성하고 요소가 콜백에 등록 할 수 있도록합니다 (C # 이벤트는 영광 스럽습니다). 이러한 콜백에는 보도, 릴리스, 탭, 길게 누르기 등의 이벤트가 포함됩니다. 아날로그 스틱의 경우 격투 게임의 QCF와 같은 제스처를 포함 할 수 있습니다. 노출되는 이벤트 수는 발송하려는 이벤트의 세부 사항에 따라 다릅니다. ButtonStateChanged(InputIdentifier)다른 모든 것을 별도의 논리로 처리하려는 경우 간단하게 실행할 수 있습니다 .

따라서 입력 버튼 또는 컨트롤 스틱의 현재 상태를 확인해야하는 경우 하위 계층을 확인하십시오. 입력 이벤트시 단순히 기능을 시작하려면 두 번째 계층에서 콜백을 등록하십시오.

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