
DirectX 11 · 약 4분
키 입력으로 사각형 움직이기: 눌림 상태와 시간 기반 이동
GetAsyncKeyState의 상위 비트로 지속 입력을 읽고, 대각선 속도와 포커스 이탈을 고려한 이동 갱신을 만듭니다.
Wolfgadeok · 업데이트
한 번 눌렀는지와 계속 누르는지는 다르다
이동키는 누르고 있는 동안 매 갱신마다 영향을 주지만 메뉴 선택이나 공격은 한 번 누른 순간만 처리하고 싶을 수 있습니다. 입력 이벤트와 현재 눌림 상태를 같은 것으로 취급하면 자동 반복이나 중복 실행 때문에 원하지 않는 동작이 생깁니다. 이 글에서는 방향키를 누르고 있는 동안 사각형을 움직이는 지속 입력부터 다룹니다.
GetAsyncKeyState에서는 상위 비트로 현재 키가 눌렸는지 확인할 수 있습니다. 하위 비트의 ‘최근 눌림’ 정보에 의존하여 게임의 중요한 단발 이벤트를 구성하지 않습니다. 단발 입력은 메시지나 이전 프레임 상태와의 비교 등 별도 방식을 고려합니다. 문자 입력은 키 상태 폴링만으로 해결하려 하지 말고 운영체제의 문자·입력기 흐름을 사용합니다.
속도 단위는 초당 거리로 정하기
매 프레임 고정된 거리를 더하면 갱신 횟수가 많은 환경에서 더 빨리 움직입니다. 더하는 값을 작게 바꾸어도 실행 속도에 따라 이동량이 달라지는 문제는 남습니다. 초당 속도와 dt를 사용하고, 두 방향을 동시에 누를 때 벡터 길이를 정규화하면 대각선만 빨라지는 현상도 막을 수 있습니다. 아래는 GetAsyncKeyState와 이동 계산을 보여주는 부분 예제이며 dt는 초 단위의 유효한 경과 시간이라고 가정합니다.
예제 · cpp
#include <Windows.h>
#include <cmath>
const auto down = [](int key) {
return (GetAsyncKeyState(key) & 0x8000) != 0;
};
float axisX = float(down(VK_RIGHT)) - float(down(VK_LEFT));
float axisY = float(down(VK_DOWN)) - float(down(VK_UP));
if (GetForegroundWindow() != hwnd) axisX = axisY = 0.f;
const float length = std::sqrt(axisX * axisX + axisY * axisY);
if (length > 0.f) {
const float speed = 180.f; // 좌표 단위 / 초
x += axisX / length * speed * dt;
y += axisY / length * speed * dt;
}실제 게임으로 확장하기 전에 검사할 것
위 예제는 좌표만 바꾸므로 벽과 화면 경계를 통과합니다. 충돌이 있는 게임에서는 후보 위치를 계산한 후 충돌 규칙으로 허용 위치를 정해야 합니다. 입력을 화면 좌표에 곧바로 더하는 대신 이동 의도를 게임 로직에 전달하면 카메라와 충돌 처리를 추가하기 쉽습니다. 렌더러가 캐릭터의 실제 위치를 결정하지 않도록 책임도 나눕니다.
창을 다른 프로그램 뒤로 보냈을 때 움직임이 멈추는지, 반대 방향 두 키를 동시에 눌렀을 때 정책이 일관적인지, 30과 60 FPS에서 같은 시간 동안 비슷한 거리를 가는지 확인합니다. 긴 일시 정지 이후의 dt는 별도 정책으로 처리합니다. dt를 제한하면 과도한 점프를 줄일 수 있지만 시간이 느려지는 효과가 있으므로 고정 스텝이나 일시 정지 처리와 비교해 선택합니다.
- 오른쪽 키를 일정 시간 눌러 이동 거리를 기록합니다.
- 프레임 제한을 바꾸어 같은 시간의 거리를 비교합니다.
- 대각선·반대 방향 동시 입력과 Alt+Tab 이후 복귀를 점검합니다.
참고 자료
예제는 학습용이며, 모든 환경에서 실행 검증된 완성 프로젝트는 아닙니다. 적용 전 사용 중인 버전과 프로젝트 환경에서 동작을 확인하세요.