키보드 입력 시스템 처리


13

참고 : API 제한 (SFML)으로 인해 콜백을 수행하기보다는 폴링해야합니다. 또한 '괜찮은'타이틀이없는 것에 대해 사과드립니다.

여기에 두 가지 질문이 있습니다. 수신중인 입력을 등록하는 방법 및 처리 방법

입력 처리

예를 들어, 'A'키를 눌렀다는 사실을 등록한 후 거기에서 수행하는 방법에 대해 이야기하고 있습니다.

전체 키보드 배열을 보았습니다.

bool keyboard[256]; //And each input loop check the state of every key on the keyboard

그러나 이것은 비효율적 인 것 같습니다. 예를 들어, 키 'A'를 '플레이어 왼쪽으로 이동'에 연결했을뿐만 아니라 모든 키를 초당 30-60 회 확인합니다.

그런 다음 원하는 키를 찾은 다른 시스템을 시도했습니다.

std::map< unsigned char, Key> keyMap; //Key stores the keycode, and whether it's been pressed. Then, I declare a load of const unsigned char called 'Quit' or 'PlayerLeft'.
input->BindKey(Keys::PlayerLeft, KeyCode::A); //so now you can check if PlayerLeft, rather than if A.

그러나 이것의 문제는 이제 모든 단일 키를 바인딩하지 않고도 이름을 입력 할 수 없다는 것입니다.

그런 다음 두 번째 문제가 있는데 실제로 다음과 같은 좋은 해결책을 생각할 수 없습니다.

송신 입력

이제 A 키를 눌렀거나 playerLeft가 true라는 것을 알고 있습니다. 하지만 여기서 어떻게 가나 요?

방금 확인하는 것에 대해 생각 if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
했습니다. 입력을 엔터티에 크게 연결하고 다소 지저분합니다. 나는 플레이어가 업데이트 될 때 자신의 움직임을 처리하는 것을 선호합니다. 나는 일종의 이벤트 시스템이 작동 할 수 있다고 생각했지만 그와 함께하는 방법을 모르겠습니다. (이런 종류의 작업에는 신호와 슬롯이 좋다고 들었지만 속도가 매우 느리고 그것이 어떻게 적합한 지 알 수 없습니다).

감사.

답변:


7

내가하는 것은 옵저버 패턴을 사용하고 콜백 또는 입력 처리 객체 목록을 유지 관리하는 입력 클래스를 사용하는 것 입니다. 다른 개체는 입력 시스템에 등록되어 특정 상황이 발생할 때 알림을받을 수 있습니다. 관찰자에게 알리고 자하는 입력 이벤트 유형에 따라 등록 할 수있는 다양한 유형의 콜백이 있습니다. 이것은 '키 x가 다운 / 업'또는 '점프 / 슈팅 / 이동 이벤트가 발생했습니다'와 같은 게임 특정 수준보다 낮은 수준 일 수 있습니다.

일반적으로 게임 오브젝트가 처리 입력이 구성 요소 는 입력 클래스와 자신을 등록하고, 그것이 관심 이벤트를 처리하는 방법을 제공하는 역할을한다. 운동, I는 이동 (X, Y) 메소드가 입력 가동 구성 요소를 갖는다. 입력 시스템에 자신을 등록하고 이동 이벤트 (x와 y는 -1과 0이 왼쪽으로 이동 함을 나타냄)에 대한 알림을 받으면 이동기 구성 요소는 이동 방향과 객체 속도에 따라 상위 게임 객체 좌표를 변경합니다.

이것이 좋은 해결책인지는 모르겠지만 지금까지는 효과가 있습니다. 특히 게임 패드 버튼 x와 키보드 공간이 예를 들어 점프 이벤트를 생성하도록 동일한 논리적 게임 이벤트에 매핑되는 다양한 종류의 입력 시스템을 제공 할 수 있습니다 (이보다 약간 더 복잡하여 사용자가 키를 재 할당 할 수 있음) 매핑).


이것은 확실히 나에게 관심이있다. 입력 컴포넌트가 특정 이벤트 (playerInput 레지스터 '왼쪽', '오른쪽'등)에 대해 자체적으로 등록됩니까? 아니면 등록 된 모든 입력 컴포넌트가 모든 메시지를 수신합니까?
공산주의 오리

그것은 실제로 요구 사항과 구현 방법에 달려 있습니다. 필자의 경우 리스너는 특정 이벤트에 등록하고 적절한 입력 핸들러 인터페이스를 구현합니다. 모든 입력 구성 요소가 모든 메시지를 수신하게하면 작동하지만 메시지 형식은 내가 가지고있는 것보다 더 일반적이어야합니다.
Firas Assaad

6

OP의 논의는 많은 것들을 한꺼번에 모으고 있으며, 문제를 조금 풀어서 문제를 크게 단순화 할 수 있다고 생각합니다.

나의 제안:

키 상태 배열을 유지하십시오. 전체 키보드 상태를 한 번에 가져 오는 API 호출이 없습니까? (대부분의 작업은 콘솔에서 이루어지며 연결된 컨트롤러의 경우 Windows에서도 전체 컨트롤러 상태를 한 번에 얻을 수 있습니다.) 키 상태는 키보드 키의 "하드"맵입니다. 번역되지 않은 것이 가장 좋지만 API에서 가장 쉽게 얻을 수 있습니다.

그런 다음 키가이 프레임을 올렸는지 여부를 나타내는 몇 개의 병렬 배열을 유지하십시오. 다른 프레임은 키가 다운되었음을 나타냅니다. 그리고 다른 하나는 키가 "다운"임을 나타냅니다. 키를 현재 상태로 유지 한 시간을 추적 할 수 있도록 타이머를 넣을 수 있습니다.

다음으로 키를 동작에 매핑하는 방법을 만듭니다. 이 작업을 몇 번 수행하고 싶을 것입니다. UI 항목에 대해 한 번 ( 'A'를 누를 때 스캔 코드를 가정 할 수 없으므로 사용자의 컴퓨터에서 A를 제공하기 때문에 Windows 매핑을 쿼리하도록주의하십시오). 게임 내 각각의 "모드"마다 다릅니다. 이것들은 키 코드와 액션의 매핑입니다. 수신 시스템에서 사용하는 열거 형을 유지하는 것, 상태 변경시 호출 할 함수를 나타내는 함수 포인터가 될 수 있습니다. 목표와 요구에 따라 두 가지를 혼합 한 것일 수도 있습니다. 이러한 "모드"를 사용하면 컨트롤러 모드 스택으로 푸시 및 팝할 수 있습니다. 플래그를 사용하면 무시 된 입력으로 스택을 계속 내려갈 수 있습니다.

마지막으로 이러한 주요 작업을 처리하십시오. 모션의 경우 까다로운 작업을 원할 수 있습니다. 'W'를 아래로 이동하여 "앞으로 이동"을 의미하지만 이진 솔루션 일 필요는 없습니다. "W is down"은 "최대 Y까지 속도가 X 씩 증가 함"을 의미하고 "W up"은 "0이 될 때까지 Z만큼 속도 감소"를 의미합니다. 일반적으로 말하자면, "게임 시스템의 컨트롤러 처리 인터페이스"가 상당히 좁기를 원합니다. 모든 주요 번역을 한 곳에서 수행 한 다음 그 결과를 다른 곳에서 사용하십시오. 이것은 스페이스 바가 코드에서 임의의 위치에 눌려져 있는지 직접 확인하는 것과 대조적입니다. 임의의 스폿에 있으면 원하지 않는 임의의 시간에 충돌 할 수 있습니다. 그 문제를 다루고 싶지 않습니다 ...

패턴에 대한 디자인을 실제로 혐오하고 구성 요소가 개발 비용보다 더 많은 개발 비용을 가져다 준다고 생각합니다. 구성 요소와 마찬가지로 패턴이 예정되어 있으면 패턴이 나타나지만 처음부터 시작하면 인생이 복잡해집니다.


이벤트를 그래픽 프레임에 바인딩하는 것이 더럽다고 생각하지 않습니까? 나는 그것이 분리되어야한다고 생각합니다.
Jo So

거의 모든 경우에 플레이어는 그래픽 카드가 프레임을 방출하는 것보다 버튼을 입력하는 속도가 느리지 만 실제로는 독립적이어야하며 실제로 네트워크에서 수집 한 것과 같은 다른 이벤트 유형에 대한 것입니다. .
Jo So

과연; 키보드 (또는 다른 입력 장치) 폴링을 디스플레이와 다른 속도로 실행할 수없는 이유는 없습니다. 실제로 100Hz에서 입력을 폴링하면 비디오 하드웨어 업데이트 빈도에 관계없이 실제로 일관된 사용자 제어 환경을 제공 할 수 있습니다. 데이터를 처리하는 방법 (래칭 등)에 대해 좀 더 영리해야하지만 제스처와 같은 것을 일관성있게 만드는 방법이 더 쉬워 질 것입니다.
dash-tom-bang

3

SFML에는 KeyPressed 이벤트 유형으로 누른 순서대로 키가 있습니다. while (getNextEvent ())에서 각 키를 처리합니다.

따라서 누른 키가 Key-> Action 맵에있는 경우 해당 조치를 실행하고 그렇지 않은 경우이를 필요한 위젯 / 항목으로 전달하십시오.

두 번째 질문과 관련하여 게임 플레이를 쉽게 조정할 수 있기 때문에 이와 같이 유지하는 것이 좋습니다. 신호 등을 사용하는 경우 "RunKeyDown"용 슬롯과 "JumpKeySlot"용 슬롯을 만들어야합니다. 그러나 게임에서 두 가지를 눌렀을 때 특별한 행동이 수행되면 어떻게됩니까?

입력과 엔터티를 꾸미려면 입력을 상태 (RunKey = true, FireKey = false, ...)로 설정하고 AI에 다른 이벤트를 보내는 것처럼 플레이어에 보낼 수 있습니다.


실시간 감지 IIRC이기 때문에 sf :: Event가 아닌 sf :: Input으로 키보드 이벤트를 처리하지 않습니다. 가능한 한 API에 독립적으로 유지하려고했습니다. : P (질문, 즉)
공산주의 오리

1
그러나 Calvin1602의 요점은 "SFML (API 제한으로 인해 콜백을하기보다는 폴링해야 함)"이라는 질문에 대한 원래의 진술이 사실이 아니라는 것입니다. 이벤트가 있으므로 이벤트를 처리 할 때 콜백을 발행 할 수 있습니다.
Kylotan

3

올바른 해결책은 종종 논의하는 두 가지 방법의 조합입니다.

사전 정의 된 키 세트가있는 게임 플레이 기능의 경우 모든 프레임을 폴링하는 것이 완벽하며 실제로 무언가에 바인딩 된 키만 폴링해야합니다. 이것은 실제로 콘솔 게임에서 컨트롤러 입력을 쿼리하는 방법과 유사하며 특히 아날로그 입력 장치와 관련하여 완전히 폴링됩니다. 일반적인 게임 플레이 중에 키 누르기 이벤트를 무시하고 폴링을 사용하고 싶을 것입니다.

이름과 같은 입력을 입력 할 때는 게임을 다른 입력 처리 모드로 전환해야합니다. 예를 들어, "이름 입력"프롬프트가 표시되면 입력 코드의 기능을 수정할 수 있습니다. 콜백 인터페이스를 통해 키 누르기 이벤트를 수신하거나 필요한 경우 각 키에 대한 폴링을 시작할 수 있습니다. 일반적으로 이벤트를 입력하는 동안 성능에 대해서는 크게 신경 쓰지 않으므로 폴링은 그렇게 나쁘지 않습니다.

따라서 게임 플레이 입력에 선택적 폴링을 사용하고 이름 입력 입력에 대한 이벤트 처리 (또는 이벤트 처리를 사용할 수없는 경우 모든 키보드 폴링)를 사용하려고합니다.


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