STL의 bitset 자료구조를 이용해 key매니저를 구현한 부분을 정리하는 글이다.
bool 자료형은 1바이트로 0,1을 저장한다.
하지만 1bit로도 0과 1을 표기할 수 있다. 7bit를 압축시키는 효율!
이렇게 bit를 이용해 0과 1을 저장하는 자료구조가 STL라이브러리의 bitset이다.
vector<bool> 이나 bool형 배열대신 사용하면 효율적일 것이다!
다음은 bitset의 멤버 함수들이다.
set() : bit 모두 1로 설정
reset() : bit 모두 0으로 설정
set(i,value) : i번째 값을 value로 설정
[] : 배열 형태의 access가 가능함 / bit[10]=false;
flip() : bit 값 전환 0->1 , 1->0
all() : 모든 비트가 1일 때 true
none() : 모든 비트가 0일 때 true
any() : 1개라도 1이면 true
count() : 값이 1로 세팅된 비트의 갯수 반환
이런 bitset의 원소들은 1bit인데 1bit를 표기할 수 있는 자료형이 없으므로
특별한 레퍼런스 타입으로 접근된다.
bitset::reference : bitset의 operator[]에 대한 도우미 클래스로서 개별 비트에 액세스하고 조작하는 데 사용되는 bitset에 포함된 비트를 참조하는 프록시 클래스입니다.
싱글톤 템플릿 클래스를 상속받아 하나의 키매니저만 존재하도록 한다.
private 멤버 변수로 위에 언급한 bitset을 두개 선언했다.
private:
bitset<KEYMAX> m_bitKeyUp;
bitset<KEYMAX> m_bitKeyDown;
public 멤버함수로 각 키의 상태에 따른 함수들을 선언했다
public:
void Setup(); //키 매니저 초기화
bool isOnceKeyDown(int key); //키가 한번 눌림
bool isOnceKeyUp(int key); //키를 눌렀다 땜
bool isStayKeyDown(int key); //키를 누르고있음
bool isToggleKey(int key); //토글 키
일단 keymanager코드를 보기 전에 알아야할 함수가 있다.
인자 값인 key의 상태를 반환하는 함수다.
반환값으로 네 가지 값이 존재한다.
이 네 값을 가지고 키 입력 판단을 한다.
void KeyManager::Setup()
{
m_bitKeyUp.reset();
m_bitKeyDown.reset();
}
두 개의 bitset자료구조를 리셋시킨다.
bool KeyManager::isOnceKeyDown(int key)
{
if (GetAsyncKeyState(key) & 0x8000) {
//키가 이전에 눌려있지 않은 상태
if (!m_bitKeyDown[key]) {
//눌린 상태로 변환
m_bitKeyDown.set(key, true);
return true;
}
}
else
{
m_bitKeyDown.set(key, false);
}
return false;
}
GetAsyncKeyState함수를 통해 key의 상태를 알아온다.
0x8000값과 &연산자를 통해 true가 나오려면 GetAsyncKeyState함수의 반환값이
0x8001이거나 0x8000이면 된다.
따라서 if (GetAsyncKeyState(key) & 0x8000)의 의미는
현재 해당 버튼이 눌려있는 지 체크하는 것이다.
이전에 이미 눌려있는 상태라면 (m_bitKeyDown[key] = true)
사용자가 계속 누르고 있는 상황이므로 false를 return한다.
m_bitKeyDown[key]가 false여야만 처음 누른 상황이므로 true를 반환하도록 구현하였다.
bool KeyManager::isOnceKeyUp(int key)
{
if (GetAsyncKeyState(key) & 0x8000) {
m_bitKeyUp.set(key, true);
}
else {
//이전에 키를 누르고 있었다면
if (m_bitKeyUp[key]) {
//뗀 상태로 변환
m_bitKeyUp.set(key, false);
return true;
}
}
return false;
}
위 설명에서 GetAsyncKeyState(key) & 0x8000 조건문은 현재 해당 키가 눌려있는 지 조사하는 역할이므로
눌려있다면 m_bitKeyUp.set(key, true); 체크해준 후 false를 return한다.
else문ㅇ내부로 진입했다는 뜻은 0x0000 또는 0x0001을 반환한 상황이므로
키를 안 누르는 상황이다.
if (m_bitKeyUp[key]) 조건문 내부로 들어왔다는 말은
이전에 누르고 있었다는 뜻이므로 방금 키를 떼었다는 뜻이다.
따라서 m_bitKeyUp[key]값을 false로 세팅해주고 true를 반환한다.
bool KeyManager::isStayKeyDown(int key)
{
if (GetAsyncKeyState(key) & 0x8000) return true;
return false;
}
key를 누르고 있는가 체크하는 함수다.
0x8000과 &연산을 통해 누르고 있는지 체크한다.
bool KeyManager::isToggleKey(int key)
{
if (GetAsyncKeyState(key) & 0x0001) return true;
return false;
}
키가 눌려있다가 떼어질 때를 측정하는 함수이다.
0x0001과 &연산을 통해 0x0001과 다른 값이 나오면 모두 0이 되므로
0x0001만 통과할 수 있다.
눌렀을 때를 체크할 때는 0x8000과 비교하면 되고, 떼었을 때 비교할 때는 ( isToggleKey함수 )
0x0001과 비교한다는 게 처음 구현할 때 좀 긴가민가했다.
0x8000과 &연산을 하면 0x8001이든 0x8000이든 상위 비트에서 1이 나오므로
두 16진수 값이 다 통과하는데
0x0001과 &연산을 하면 0x0000도 0이 나오므로 0x0001만 통과시킨다.
0x0000과 &연산하면 당연한 말이지만 모든게 0으로 나온다