WinAPI 프레임워크에서 키보드, 마우스 입력을 관리하는 Input 클래스를 만들었다.
typedef struct _tagKeyInfo
{
string strName;
vector<DWORD> vecKey;
bool bPress;
bool bDown;
bool bUp;
_tagKeyInfo() :
bDown(false),
bPress(false),
bUp(false)
{
}
}KEYINFO, * PKEYINFO;
KEYINFO 구조체는 Input 클래스 내에 있다. vecKey는 입력해야 할 키 값'들'이다. Ctrl + S 처럼 두개 이상의 키를 동시에 입력받아야 할 경우가 있기 때문이다. strName은 vecKey의 KEYINFO의 이름이다. bPress, bDown, bUp은 각각 처음 눌렀을 때 부터 뗄 때 까지, 처음 눌렀을 때, 눌렀다가 뗐을 때 true가 된다.
template<typename T, typename... Types>
bool AddKey(const T& data, const Types&... arg)
{
if (!m_pCreateKey)
m_pCreateKey = new KEYINFO;
const char* pTType = typeid(T).name();
if (strcmp(pTType, "char") == 0 ||
strcmp(pTType, "int") == 0)
{
m_pCreateKey->vecKey.push_back((DWORD)data);
}
else
{
m_pCreateKey->strName = data;
m_mapKey.insert(make_pair(m_pCreateKey->strName, m_pCreateKey));
}
AddKey(arg...);
if (m_pCreateKey)
m_pCreateKey = NULL;
return true;
}
AddKey 함수 템플릿은 KEYINFO의 정보를 입력하는 가변인자 템플릿이다. 우선 m_pCreateKey라는 KEYINFO가 NULL일 시 생성한다. 그리고 인수를 하나씩 받아 type이 char이거나 int일 시, 입력해야 할 키이므로 vecKey에 저장한다. 아니라면 KEYINFO의 이름이므로 strName에 저장하고 strName이 key이고 m_pCreateKey가 value인 map에 저장한다. AddKey는 Input::Init에서 최초 한번 실행한다.
unordered_map<string, PKEYINFO>::iterator iter;
unordered_map<string, PKEYINFO>::iterator iterEnd = m_mapKey.end();
for (iter = m_mapKey.begin(); iter != iterEnd; ++iter)
{
int iPushCount = 0;
for (size_t i = 0; i < iter->second->vecKey.size(); ++i)
{
if (GetAsyncKeyState(iter->second->vecKey[i]) & 0x8000)
++iPushCount;
}
if (iPushCount == iter->second->vecKey.size())
{
if (!iter->second->bDown && !iter->second->bPress)
{
iter->second->bPress = true;
iter->second->bDown = true;
}
else if (iter->second->bDown)
iter->second->bDown = false;
}
else
{
if (iter->second->bDown || iter->second->bPress)
{
iter->second->bUp = true;
iter->second->bDown = false;
iter->second->bPress = false;
}
else if (iter->second->bUp)
iter->second->bUp = false;
}
}
Input::Update에서는 Init에서 설정한 것을 바탕으로 입력 감지를 한다. m_mapKey를 돌면서 value인 PKEYINFO의 vecKey가 입력될 때마다 iPushCount가 증가한다. vecKey.size와 iPushCount가 같으면 입력할 키들을 모두 입력한 것이므로 눌렀다고 처리한다. 처음에는 bPress와 bDown가 모두 true가 되고 그 다음 Update에서는 bDown이 false가 된다.
그리고 iPushCount가 vecKey.size가 같지 않으면 키를 뗀 상태이므로 bDown,bPress는 false, bUp은 true가 된다.
AddKey('W', "MoveFront");
AddKey('S', "MoveBack");
AddKey('A', "MoveLeft");
AddKey('D', "MoveRight");
AddKey("Fire", VK_SPACE);
AddKey(VK_CONTROL, "Skill1", '1');
AddKey(VK_LBUTTON, "MouseLButton");
AddKey(VK_RBUTTON, "MouseRButton");
Input::Init에서 AddKey로 키 입력을 지정하는 예시이다. W,S,A,D와 스페이스, 컨트롤, 마우스 좌클릭, 우클릭 입력은 각각의 이름을 가진다.
if (KEYPRESS("MoveLeft")) {
MoveXFromSpeed(fDeltaTime, MD_BACK);
m_pAnimation->ChangeClip("RunLeft");
m_iDir = -1;
}
if (KEYPRESS("MoveRight")) {
MoveXFromSpeed(fDeltaTime, MD_FRONT);
m_iDir = 1;
}
if (KEYDOWN("Fire")) {
Fire();
}
Player::Input에서 지정한 키 입력을 바탕으로 함수를 실행한다. KEYPRESS는 해당 strName의 KEYINFO가 bPress=true 인지, 즉 키를 누르고 유지중인 상태인지 확인하는 매크로이다. 그래서 A키, D키를 꾹 누르고 있으면 캐릭터가 부드럽게 움직인다. 그리고 KEYDOWN은 키를 최초 누른 순간만 실행되기 때문에 스페이스바를 꾹 눌러도 Fire이 한번만 실행된다.
'WinAPI' 카테고리의 다른 글
| [WinAPI] 게임 프레임워크 - 6. Render (0) | 2022.02.02 |
|---|---|
| [WinAPI] 게임 프레임워크 - 5. PathManager, 유니코드와 멀티바이트 (0) | 2022.02.02 |
| [WinAPI] 게임 프레임워크 - 3. Reference Count (0) | 2022.02.01 |
| [WinAPI] 게임 프레임 워크 - 2. Scene과 SceneManager (0) | 2022.02.01 |
| [Winapi] 게임 프레임워크 - 1. Core (0) | 2022.02.01 |