2020 이전/DirectX

DirectX input 시스템

이상해C++ 2019. 1. 22. 15:58

다이렉트X에서 지원해주는 input 라이브러리 dinput.h을 이용한다.



fucntional은 c++11부터 추가된 표준 라이브러리이다. 전역함수 기준으로 함수명은 그 자체가 주소가 되므로 함수명을 쓰고 인자를 넘겨주면 함수가 호출이된다. 이것이 함수포인터의 개념인데 멤버함수를 함수포인터로 호출하기는 까다로웠다. c++11부터는 functional을 지원하여 같은 interface로 전역과 멤버함수에 접근 가능하게끔 해준다. 이를 통해 멤버클래스의 멤버함수를 bind하여 키가 입력되면 호출할 수 있도록 한다.



  

키를 얻어오는 방법에는 GetAsyncKeyState도 있지만 GetAsyncKeyState는 윈도우 메세지를 후킹하는 방법이라 시간 효율이 썩 좋지않아 DirectX Input을 사용한다. 다이렉트 인풋은 입력을 할 수 있는 장치(마우스, 키보드, 조이스틱, 패드 등)가 연결되어있으면 장치에 대한 디바이스 객체를 생성하여 입력을 체크하게끔 한다.


FAILED( HRESULT ) 는 해당 작업이 실패했는지 체크해주는 매크로이다. 



ReadKeyboard() 함수는 현재 키보드의 상태를 불러온다. 해당 키가 입력되었는가에 대한 정보를 얻어오며, 만약 이 작업이 최초에 실패할시 창을 닫거나하는 등의 이유로 keyboard 상태를 읽는것이 실패할 수 있으므로 키보드 장치를 다시 얻어온다.



key state를 체크해주는 구조체


<Axis System>

언리얼에서의 입력 동작 및 축 매핑 시스템 : https://www.unrealengine.com/ko/blog/input-action-and-axis-mappings-in-ue4


동작 및 축 매핑이 뭔가요?

동작 및 축 매핑은 입력 행위와 그것을 실행하는 키 사이에 간접 레이어를 삽입함으로써 키와 축을 입력 행위에 편리하게 매핑시키는 메커니즘을 제공합니다. 동작 매핑은 키 누르고 떼는 데 대한 것이고, 축 매핑은 연속적인 범위가 있는 입력에 대한 것입니다.


axis system: using scale

축 매핑 역시도 상당히 단순합니다. 동시 입력 키를 지정하는 대신, 스케일을 지정합니다. 스케일은 축의 값을 합할 때 키의 값에 적용되는 배수입니다. 이 기능은 키보드 키에서 축을 만들고자 할 때 특히나 유용합니다


구현 : 무조건 함수 호출이 일어나지만 키 인풋이 들어오지않으면 scale에 0이 넘어가므로 아무일도 일어나지 않고 키 인풋이 들어왔을 때 자신의 scale로 값이 바뀐다. 



BindAxis는 scale과 deltatime을 인자로 받으며 리턴타입을 void로 가지는 함수를 binding한다. 



void BindAxis 함수가 하는 일은 아래와 같다.

1. 현재 해당 Action이 등록되어있는지를 확인한다. 

1-1 등록되어있지 않다면 만든다.

2. 해당 바인드 액션에 함수가 매핑되어 있다는 것을 체크하고 함수를 바인드 한다.

(Action에 매핑된 함수는 변경이 가능하다)

3. 함수 바인드 시, placeholders::_1, placeholders::_2는 인자의 위치이므로 가급적 바꾸지 않도록 한다.



void AddAxisKey 함수가 하는 일은 아래와 같다.

1. 해당 Action이 등록되어있는지 확인한다.

1-1. 없다면 해당 Action을 등록해준다.  

2. 해당 Action에 등록할 키 스케일 객체를 만들고, 해당 Action에 등록된 키 리스트를 탐색한다.

2-1. Action에 등록된 키가 이미 있다면 따로 CInput에서 관리하는 m_KeyList에는 추가하지 않는다.

2-2. 없다면 m_KeyList에 추가해준다.

3. 해당 Action에 키를 추가해준다. 


보완 사항:

1. pKeyScale의 키 값과 스케일 값이 완전히 동일하다면 따로 추가하지 않도록 한다.

2. 같은 키 값에 대해 스케일 값만 다르게 추가한다면 (w,-1), (w,2)를 차례로 입력했을때 w키를 누르면 스케일은 1이 된다. 하지만 우리의 의도는 2로 바꾼다에 가까울 가능성이 높다. 이 경우에 대해서는 스케일 값을 대체할 수 있도록 한다.


이제 업데이트 해주자



PART1

1. ReadKeyboard()로 m_cKey에 현재 키보드 디바이스에 들어온 입력 정보를 갱신한다.
2. 클라이언트/엔진 에서 등록한 keylist를 전부 돌면서 해당 key input이 들어왔는지 체크하며, state정보를 갱신한다.


PART2 : 위에서 갱신해준 키 정보들을 가지고 실질적으로 Action을 처리해주는 부분이다.

1. 클라이언트/엔진에서 사용하는 Action정보들을 돌면서
2. Action마다 등록된 키 리스트를 돌며 해당하는 키들의 state를 체크해서 매핑된 함수를 호출한다.

AxisSystem은 매 프레임마다 호출된다.


https://github.com/keukdong/DInputStudy


코어클래스랑 매크로 몇개가 빠져서 실행은 안되지만 윈도우 인스턴스만 만들어서 넘겨주면 된다.