C++ 입력 시스템 구현: Pressed / Held / Released 상태 관리하기

📚 입력 시스템 시리즈


//
//

🚀 들어가며

이전 글에서는 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 구조와 깊게 연결됩니다.

👉 게임 엔진 구조를 더 깊이 이해하고 싶다면

아래 강의를 통해 직접 구현해보는 것을 추천드립니다.

C++로 만드는 게임 엔진 프레임워크 강의

👉 C++로 만드는 게임 엔진 프레임워크 강의 바로가기

단순히 사용하는 것을 넘어서,
엔진이 어떻게 동작하는지 이해하는 데 초점을 맞춘 내용입니다.

//
   

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다