📚 입력 시스템 시리즈
🚀 들어가며
이전 글에서는 GetAsyncKeyState를 이용해 입력 상태 관리하는 방법을 살펴봤습니다.
하지만 실제 게임을 만들다 보면 단순히 “키가 눌려 있는지”만으로는 부족합니다.
스페이스바를 누르면 점프한다 → 한 번만 점프해야 한다 왼쪽 키를 누르면 이동한다 → 누르고 있는 동안 계속 이동해야 한다
즉, 우리는 다음을 구분해야 합니다.
막 눌린 순간 누르고 있는 상태 막 뗀 순간
이번 글에서는 이 세 가지 상태를 구분하는 방법을 구현해보겠습니다.
🎯 문제 상황
아래 코드를 보면 어떤 문제가 있을까요?
if (GetAsyncKeyState(VK_SPACE) & 0x8000)
{
Jump();
}
이 코드는 스페이스바를 누르고 있는 동안 매 프레임 Jump()를 호출합니다.
스페이스바 누름 ↓ 1프레임: Jump() 2프레임: Jump() 3프레임: Jump() ...
결과적으로 점프가 한 번이 아니라 계속 실행됩니다.
이 문제를 해결하려면 입력 상태를 더 정교하게 구분해야 합니다.
🧩 입력 상태 3가지
Pressed : 이번 프레임에 막 눌림 Held : 계속 누르고 있음 Released : 이번 프레임에 막 뗌
이 개념을 적용하면 입력 처리가 훨씬 자연스러워집니다.
Pressed → 점프 Held → 이동 Released → 버튼 해제 처리
🧠 핵심 아이디어
이 세 가지 상태를 구분하는 방법은 매우 간단합니다.
현재 프레임 상태 이전 프레임 상태 ↓ 두 값을 비교
🔧 KeyState 구조 만들기
struct KeyState
{
bool current = false;
bool previous = false;
};
현재 상태와 이전 상태를 저장합니다.
🔧 상태 업데이트
void UpdateKeyState(KeyState& keyState, int keyCode)
{
keyState.previous = keyState.current;
keyState.current = (GetAsyncKeyState(keyCode) & 0x8000) != 0;
}
매 프레임 호출하면 됩니다.
🎯 상태 판별 함수
bool IsPressed(const KeyState& key)
{
return key.current && !key.previous;
}
bool IsHeld(const KeyState& key)
{
return key.current && key.previous;
}
bool IsReleased(const KeyState& key)
{
return !key.current && key.previous;
}
🎮 사용 예제
KeyState spaceKey;
void ProcessInput()
{
UpdateKeyState(spaceKey, VK_SPACE);
if (IsPressed(spaceKey))
{
std::cout << "Jump\n";
}
if (IsHeld(spaceKey))
{
std::cout << "Holding\n";
}
if (IsReleased(spaceKey))
{
std::cout << "Released\n";
}
}
이제 입력 상태를 정확하게 제어할 수 있습니다.
🎯 입력 시스템으로 확장
키가 하나만 있다면 위 구조로 충분하지만, 실제 게임에서는 여러 키를 다룹니다.
class Input
{
public:
void Update()
{
UpdateKeyState(space, VK_SPACE);
UpdateKeyState(left, VK_LEFT);
UpdateKeyState(right, VK_RIGHT);
}
bool IsJumpPressed() const
{
return IsPressed(space);
}
private:
KeyState space;
KeyState left;
KeyState right;
};
이제 입력 처리가 하나의 시스템으로 정리됩니다.
🔥 다음 단계: 이벤트 시스템으로 연결
이 구조를 한 단계 더 확장하면 이벤트 시스템으로 연결할 수 있습니다.
if (input.IsJumpPressed())
{
OnJump.Broadcast();
}
이제 입력 → 델리게이트 → 게임 로직으로 이어집니다.
입력 감지 ↓ Pressed 판별 ↓ Delegate 호출 ↓ 게임 로직 실행
🎯 핵심 정리
- Pressed / Held / Released는 입력 시스템의 핵심 개념이다
- 현재 상태와 이전 상태를 비교하면 구현할 수 있다
- 이 구조는 이벤트 시스템으로 확장된다
- 게임 엔진 입력 구조의 기반이다
이 구조를 이해하면
게임 엔진의 입력 시스템과 이벤트 흐름이 어떻게 연결되는지 보이기 시작합니다.
🎯 다음 글 예고
다음 글에서는 입력 시스템을 배열 기반으로 확장하고, 여러 키를 효율적으로 관리하는 구조를 구현해보겠습니다.
🚀 한 단계 더 나아가고 싶다면
입력 시스템은 게임 루프, 델리게이트, Actor 구조와 깊게 연결됩니다.
단순히 사용하는 것을 넘어서,
엔진이 어떻게 동작하는지 이해하는 데 초점을 맞춘 내용입니다.