(2022) 공부 (Study)/게임 개발 (Development)

[Win32API] GetAsyncKeyState() 와 키 입력 받기 (3)

수낭 2022. 4. 20. 16:43

https://soonang2.tistory.com/30

 

[Win32API] GetAsyncKeyState() 와 키 입력 받기 (2)

https://soonang2.tistory.com/28 [Win32API] GetAsyncKeyState() 와 키 입력 받기 (1) 이번에는 가상 키 값과 키보드 입력을 받는 방법에 대해서 알아보겠습니다. _getch() 함수는 가장 마지막에 입력한 값만 받..

soonang2.tistory.com

※ 이전 포스팅과 이어지는 내용이므로, 먼저 읽고 오시는 것을 추천드립니다. 

 

※ 이번 포스팅의 Source Code는 아래 git 링크에서 볼 수 있습니다. ※

https://github.com/nr97819/Win32_ASTR_Lecture/tree/Lecture-14​​

 

GitHub - nr97819/Win32_ASTR_Lecture: Win32_ASTR_Lec

Win32_ASTR_Lec. Contribute to nr97819/Win32_ASTR_Lecture development by creating an account on GitHub.

github.com

 

이번에는, 해당 Window 창이 최소화 되어있거나, focusing 되어있지 않은 상태라면,
Key 입력을 받지 않도록 설정해보도록 하자.
(게임 이외의 창을 띄웠는데도 게임 캐릭터가 움직이면 말이 안되므로)

 

case WM_KEYDOWN:
{
    switch (wParam)
    {
    case VK_DOWN:
        // logic ...
        break;
    }
}
break;

우리만의 자체 Key 입력 매니저를 만들기 전까지는, 위와 같은 형태의
Window 자체 기능들을 이용했었고, 이러한 것들은 우리가 기능을 수정할 수 없었다.

하지만 우리는 Key Manager를 자체적으로 만들어서 사용하고 있으므로,
해당 Window 창이 focusing된 상태가 아니라면, 캐릭터가 움직이지 않도록 처리해주는건 간단할 것이다.

▶ 기존에는 Window 창을 최소화 하거나, focusing을 주지 않아도, 방향키 입력이 먹혀서 물체가 이동했었다.
(여기서는 focusing된 window 창이 1개라도 있으면, Key가 동작하도록 작성할 것이다.)

다만 주의해야 할 점이 한 가지 존재한다.

 

enum class KEY_STATE
{
	NONE,	// 계속 안눌린 있는 상태
	TAP,	// 막 누른 시점
	HOLD,	// 계속 눌린 상태
	AWAY,	// 막 뗀 시점
};

TAP 혹은 HOLD 상태라면, 현재 Key 눌려져 있는 상태일 것이다.
만약 이 상태에서 창이 비활성화 된다고 가정해보자.

여기서 바로 NONE으로 Key State를 변경시켜버리면, AWAY 시점에서 호출되도록 우리가 구성했던
로직들이 동작하지 않게 될 것이다. (우리는 전에 AWAY 시점에 KEY_UP에 대한 이벤트를 정해주었기 때문에)

그래서 TAP 혹은 HOLD의 상태에서 창이 비활성화 되었다면,
AWAY를 거쳐서 NONE으로 key state가 바뀌도록 설정해주어야 한다.

 

CCore.cpp

...
void CCore::update()
{
	Vec2 vPos = g_obj.GetPos();

	// state 기능 적용, 및, HOLD 상태로 if 조건 변경 (TAP 이었음)
	if (CKeyMgr::GetInst()->GetKeyState(KEY::LEFT) == KEY_STATE::HOLD)
	{
		vPos.x -= 300.f * CTimeMgr::GetInst()->GetfDT();
	}
	if (CKeyMgr::GetInst()->GetKeyState(KEY::RIGHT) == KEY_STATE::HOLD)
	{
		vPos.x += 300.f * CTimeMgr::GetInst()->GetfDT();
	}
	if (CKeyMgr::GetInst()->GetKeyState(KEY::UP) == KEY_STATE::HOLD)
	{
		vPos.y -= 300.f * CTimeMgr::GetInst()->GetfDT();
	}
	if (CKeyMgr::GetInst()->GetKeyState(KEY::DOWN) == KEY_STATE::HOLD)
	{
		vPos.y += 300.f * CTimeMgr::GetInst()->GetfDT();
	}

	g_obj.SetPos(vPos);
}
...

 

CKeyMgr.cpp

...
void CKeyMgr::Update()
{
	// 윈도우 포커싱 알아내기
	HWND hMainWnd = CCore::GetInst()->GetMainHwnd(); // 우리의 메인 윈도우 핸들 값 (지금은 안 씀)
	HWND hFocusWnd = GetFocus(); // 현재 포커싱된 윈도우 핸들 값 반환
	// 포커싱된 윈도우가 하나도 없으면 null이 반환된다.

	// 만약 현재 Main Window가 포커싱 된 상태라면 (강의랑 조금 다른 코드)
	//if (hMainWnd == hFocusWnd)
	if (nullptr != hFocusWnd)
	{
		for (int i = 0; i < (int)KEY::LAST; ++i)
		{
			if (GetAsyncKeyState(g_arrVK[i]) & 0x8000)
			{
				if (m_vecKey[i].ePrevPush)
				{
					m_vecKey[i].estate = KEY_STATE::HOLD;
				}
				else
				{
					m_vecKey[i].estate = KEY_STATE::TAP;
				}

				m_vecKey[i].ePrevPush = true;
			}
			else
			{
				if (m_vecKey[i].ePrevPush)
				{
					m_vecKey[i].estate = KEY_STATE::AWAY;
				}
				else
				{
					m_vecKey[i].estate = KEY_STATE::NONE;
				}

				m_vecKey[i].ePrevPush = false;
			}
		}
	}
	else
	{
		for (int i = 0; i < (int)KEY::LAST; ++i)
		{
			// 이전 키 상태를 false로 변경 (state를 위해)
			m_vecKey[i].ePrevPush = false;

			// TAP이나 HOLD 상태인 경우, 프레임 두 번에 걸쳐서 NONE으로 바뀌도록 한 것.
			if (KEY_STATE::TAP == m_vecKey[i].estate)
			{
				m_vecKey[i].estate = KEY_STATE::AWAY;
			}
			else if (KEY_STATE::HOLD == m_vecKey[i].estate)
			{
				m_vecKey[i].estate = KEY_STATE::AWAY;
			}
			else if (KEY_STATE::AWAY == m_vecKey[i].estate)
			{
				m_vecKey[i].estate = KEY_STATE::NONE;
			}
			// NONE은 그대로 NONE이므로, 별도 코드 X
		}
	}
}
...

소스 코드 핵심 내용들은 위와 같습니다.

 

이상으로 포스팅을 마치겠습니다! ⌒_⌒