https://soonang2.tistory.com/28
이전 포스팅을 보고 오시는 것을 추천드립니다.
이번 포스팅에 해당되는 코드는 아래 git에서 확인 가능하다.
https://github.com/nr97819/Win32_ASTR_Lecture/tree/Lecture-12
(강의 13으로 교체 필요)
void CCore::update()
{
Vec2 vPos = g_obj.GetPos();
if (GetAsyncKeyState(VK_LEFT) & 0x8000)
{
vPos.x -= 300.f * CTimeMgr::GetInst()->GetfDT();
}
if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
{
vPos.x += 300.f * CTimeMgr::GetInst()->GetfDT();
}
if (GetAsyncKeyState(VK_UP) & 0x8000)
{
vPos.y -= 300.f * CTimeMgr::GetInst()->GetfDT();
}
if (GetAsyncKeyState(VK_DOWN) & 0x8000)
{
vPos.y += 300.f * CTimeMgr::GetInst()->GetfDT();
}
g_obj.SetPos(vPos);
}
기존의 update() 함수는 위와 같았다.
이것을 이제 KeyManager 클래스로 별도로 빼서 수정할 것이다.
< KeyManager 클래스가 별도로 필요한 이유 > (1) 프레임 동기화 동일 프레임 내에서 같은 키에 대해 동일한 이벤트를 가져간다. (2) 키 입력의 다양한 State 처리 키 눌림 State에 대한 상세한 처리(Tap, Hold, Away) 방법이 Window에는 없어서, 직접 구현해줘야 한다. (예를 들어, 키가 안눌린 상태와 이미 눌린 키를 떼는 상태는 각기 다른 이벤트가 적용되어야 한다.) |
각 개체들의 동작에 대한 처리는 모두가 동일하게 적용받아야 하므로
즉, 일괄적으로 각 개체들의 변경된 상태에 대한 내용들을 Update() 시에 체크해서 fix해 놓고,
이후에 Render()에서 한번에 일괄적으로 동작을 적용 및 반영시켜야 한다.
즉, 매 프레임의 프레임이 시작하는 초입 부분에서 KeyManger 클래스를 거쳐서 1차적으로 해당 Key가 눌렸는지,
혹은 눌린 State를 검사하고, 이후에 각 개체들의 변경된 상태들을 Update() 함수에서 기록한 뒤,
최종적으로 Render() 함수에서 변경된 점들을 일괄적으로 동작을 적용시키는 순서가 된다.
KeyManager에서 해당 Key 상태 검사 → 모두에게 변경 사항 적용 Update( ) → 최종 확정 동작을 일괄 Render( ) |
main.cpp
...
MSG msg;
while (true)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
CCore::GetInst()->progress();
}
}
return (int) msg.wParam;
...
CCore.cpp
...
void CCore::progress()
{
// Manager Update
CTimeMgr::GetInst()->Update();
CKeyMgr::GetInst()->Update(); // KeyMgr 역시 매 프레임마다 update하며, 키 눌림 체크
update();
render();
}
void CCore::update()
{
Vec2 vPos = g_obj.GetPos();
if (CKeyMgr::GetInst()->GetKeyState(KEY::LEFT) == KEY_STATE::TAP)
{
vPos.x -= 300.f;
}
/*if (GetAsyncKeyState(VK_LEFT) & 0x8000)
{
vPos.x -= 300.f * CTimeMgr::GetInst()->GetfDT();
}*/
if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
{
vPos.x += 300.f * CTimeMgr::GetInst()->GetfDT();
}
if (GetAsyncKeyState(VK_UP) & 0x8000)
{
vPos.y -= 300.f * CTimeMgr::GetInst()->GetfDT();
}
if (GetAsyncKeyState(VK_DOWN) & 0x8000)
{
vPos.y += 300.f * CTimeMgr::GetInst()->GetfDT();
}
g_obj.SetPos(vPos);
}
...
CKeyMgr.h
#pragma once
// 가상키 값이 아닌, 내가 자체적으로 정의
enum class KEY
{
LEFT,
RIGHT,
UP,
DOWN,
Q, W, E, R, T,
Y, U, I, O, P,
A, S, D, F, G,
Z, X, C, V, B,
ALT,
CTRL,
LSHIFT,
SPACE,
ENTER,
ESC,
LAST // 반복문(for)에서 쉽게 LAST 원소를 지정하기 위함
};
enum class KEY_STATE
{
NONE, // 계속 안눌린 있는 상태
TAP, // 막 누른 시점
HOLD, // 계속 눌린 상태
AWAY, // 막 뗀 시점
};
struct tKeyInfo
{
KEY_STATE estate;
bool ePrevPush; // 이전 프레임에 눌린 상태였는지
};
class CKeyMgr
{
SINGLE(CKeyMgr);
private:
// vector 내의 index가 곧, enum class KEY의 값이다.
vector<tKeyInfo> m_vecKey;
public:
void Init();
void Update();
KEY_STATE GetKeyState(KEY _eKey) { return m_vecKey[(int)_eKey].estate; }
};
CKeyMgr.cpp
#include "pch.h"
#include "CKeyMgr.h"
// 반드시 cpp 파일에 전역으로 생성해야 하는 것 주의
int g_arrVK[(int)KEY::LAST] =
{
VK_LEFT,
VK_RIGHT,
VK_UP,
VK_DOWN,
'Q', 'W', 'E', 'R', 'T',
'Y', 'U', 'I', 'O', 'P',
'A', 'S', 'D', 'F', 'G',
'Z', 'X', 'C', 'V', 'B',
VK_MENU, // ALT 키
VK_CONTROL,
VK_LSHIFT,
VK_SPACE,
VK_RETURN,
VK_ESCAPE
};
CKeyMgr::CKeyMgr()
{
}
CKeyMgr::~CKeyMgr()
{
}
void CKeyMgr::Init()
{
// Key 값/상태 vector 초기화
for (int i = 0; i < (int)KEY::LAST; ++i)
{
// 처음에는 모두 {None, 눌린적 없음} 으로 초기화
m_vecKey.push_back(tKeyInfo{ KEY_STATE::NONE, false });
}
}
void CKeyMgr::Update()
{
for (int i = 0; i < (int)KEY::LAST; ++i)
{
// 해당 키가 [지금] 눌려있다면
if (GetAsyncKeyState(g_arrVK[i]) & 0x8000) // 비트 연산으로도 가능
{
if (m_vecKey[i].ePrevPush)
{ // prev:O, now:O
m_vecKey[i].estate = KEY_STATE::HOLD;
}
else
{ // prev:X, now:O
m_vecKey[i].estate = KEY_STATE::TAP;
}
m_vecKey[i].ePrevPush = true;
}
// 해당 키가 [지금] 안눌려있다면
else
{
if (m_vecKey[i].ePrevPush)
{ // prev:O, now:X
m_vecKey[i].estate = KEY_STATE::AWAY;
}
else
{ // prev:X, now:X
m_vecKey[i].estate = KEY_STATE::NONE;
}
m_vecKey[i].ePrevPush = false;
}
}
}
https://soonang2.tistory.com/39
위 포스팅에서 Key 입력 3번째 시리즈로 이어집니다.
'(2022) 공부 (Study) > 게임 개발 (Development)' 카테고리의 다른 글
[Win32API] File 입출력 (0) | 2022.04.16 |
---|---|
2진수 그리고 16진수에 대한 정리 (0) | 2022.04.16 |
[Win32API] Rendering과 Double Buffering (0) | 2022.04.13 |
[Win32API] GetAsyncKeyState() 와 키 입력 받기 (1) (0) | 2022.04.13 |
[Win32API] 오브젝트 이동 : 시간 동기화 (2) (0) | 2022.04.13 |