Don't Get Pooped!
좌우 드래그만으로 버티는 한 손 회피 게임을 만들었습니다. 일시정지 버튼이 일부만 눌리던 문제와, 이어하기를 고려한 최고점·랭킹 저장을 다듬은 경험을 담았습니다.
AI Tools Lab · 소개 글 작성 · 수정

좌우 이동만으로 버티는 게임을 만들었다
Don’t Get Pooped!는 세로 화면에서 손가락으로 좌우 이동하며 떨어지는 장애물을 피하는 게임입니다. 초반에는 쉽게 시작하고 시간이 지날수록 압박이 커지는 흐름을 목표로 만들었습니다. 공격 버튼을 늘리기보다 피하고 버티는 판단에 집중하도록 구성했습니다.
조작이 단순해도 화면에는 서로 다른 행동이 있습니다. 플레이 중의 드래그는 캐릭터를 움직이고, 일시정지 버튼은 게임을 멈춥니다. 사망 뒤에는 이어하기와 종료가 갈립니다. 이 행동들이 섞이지 않도록 입력과 상태 전환을 다듬어야 했습니다.
2026년 7월 4일에는 일시정지 버튼이 일부 영역에서만 눌리는 문제를 고쳤고, 7월 9일에는 최고점 보존과 랭킹 저장 시점을 나눴습니다. 두 작업 모두 규칙을 추가하는 일이 아니라, 한 판이 끊기거나 다시 이어질 때 기본 동작이 맞도록 하는 수정이었습니다.
드래그와 버튼 입력을 구분하기
논리 화면은 1080×1920으로 두고 플레이어의 기본 Y 좌표는 1740으로 잡았습니다. 캐릭터는 화면 아래에서 좌우로 움직입니다. 손가락 위치를 목표 X 좌표로 받아 이동시키되, 캐릭터의 절반 폭을 고려해 화면 양 끝을 제한했습니다. 목표 위치로 보간해 움직이므로 입력 순간에 그대로 순간 이동하지 않습니다.
캐릭터가 아래에 있다고 해서 입력을 화면 하단에서만 받는 것은 아닙니다. 이동 입력에서 제외할 곳은 따로 정했습니다. 상단 HUD 영역과 일시정지 버튼의 범위에 들어온 터치는 캐릭터 이동으로 처리하지 않습니다.
일시정지를 누르는 손가락도 같은 포인터 입력으로 들어옵니다. 버튼을 누른 행동이 동시에 이동 명령이 되면 플레이어에게 뜻밖의 변화가 생길 수 있습니다. 그래서 이동 입력을 받는 곳과 화면 위 기능을 누르는 곳을 구분했습니다. 한 손 조작을 유지하는 데 필요한 경계였습니다.
버튼 그림의 크기와 입력 좌표가 달랐다
일시정지 버튼은 화면에서 132×132 크기로 표시했습니다. 원본 텍스처는 512px였는데, 직접 만든 입력 영역에는 128px 크기를 가정한 좌표가 들어가 있었습니다. 버튼 전체가 아니라 좌상단 일부만 눌린 이유였습니다.
화면에서 작게 표시하는 것과 텍스처 좌표로 입력 영역을 정하는 것은 다른 계산입니다. 저는 임의로 만든 사각형을 제거하고, 전체 텍스처를 기준으로 하는 기본 입력 판정을 사용하도록 바꿨습니다. 표시 크기는 그대로 유지했습니다.
변경 전에는 다음처럼 영역을 직접 지정했습니다.
this.pauseBtn.setInteractive({
useHandCursor: true,
hitArea: new Phaser.Geom.Rectangle(-24, -24, 176, 176),
hitAreaCallback: Phaser.Geom.Rectangle.Contains
});
수정한 설정은 더 짧아졌습니다.
this.pauseBtn.setDisplaySize(132, 132);
this.pauseBtn.setInteractive({ useHandCursor: true });
버튼 크기는 그대로 두고 입력 판정이 사용하는 좌표계를 맞췄습니다. 다음 버튼을 검수할 때는 중앙뿐 아니라 가장자리도 누르고, 텍스처를 교체하거나 화면 크기를 바꾼 뒤에도 입력 영역이 맞는지 살피려 합니다.
사망 순간에 최고점은 보존하고 랭킹은 기다리기
이 게임에는 이어하기가 있습니다. 사망해서 결과 화면이 열렸다고 곧바로 한 판이 끝난 것은 아닙니다. 반면 결과 화면에서 새로고침하거나 탭을 닫아도 이미 얻은 최고점 후보는 보존돼야 합니다. 이 두 요구를 같은 저장 시점으로 처리하기는 어렵습니다.
그래서 GameOver 진입 전에 recordBestCandidate(score)를 호출해 최고점 후보를 즉시 저장하도록 바꿨습니다. 결과 화면에는 점수와 신기록 여부를 전달합니다. 랭킹은 정식으로 한 판을 종료하는 recordScore()에서 확정하고, 같은 판이 중복 기록되지 않도록 가드를 뒀습니다.
저장 검수도 두 조건으로 나눴습니다. 하나는 사망 뒤 새로고침해도 최고점은 남고 랭킹은 아직 기록되지 않는 조건입니다. 다른 하나는 최종 기록 함수를 두 번 호출해도 랭킹에 한 건만 남는 조건입니다. 최고점의 보존과 한 판의 결과 확정을 따로 확인할 수 있게 했습니다.
“게임오버 때 저장한다”는 한 줄만으로는 이어하기와 종료의 차이가 드러나지 않습니다. 저는 유지해야 할 최고점 후보와 확정해야 할 랭킹 결과를 나눠 이 흐름을 정리했습니다. 저장 함수를 어디에 넣을지보다, 어떤 순간에 무엇이 확정되는지를 먼저 정한 수정입니다.
직접 플레이하며 살펴볼 부분
브라우저에서 플레이하기로 바로 시작할 수 있습니다. 좌우 이동이라는 기본 조작을 다음 세 장면에서 살펴보면 입력과 저장을 나눈 이유가 더 잘 보입니다.
- 좌우로 드래그하며 화면 끝에서 캐릭터가 어떻게 멈추는지, 버튼을 누를 때 이동이 섞이는지 봅니다.
- 일시정지 버튼의 중앙과 가장자리를 눌러 보고, 재개 뒤에 다시 이동해 봅니다.
- 사망 뒤 이어하기와 종료를 각각 선택해 보고, 새로고침 후 최고점이 어떻게 남는지 확인합니다.
후반의 보스와 아이템은 피해야 할 상황과 이동 판단을 바꾸지만 기본 조작은 좌우 이동입니다. 새로운 버튼을 배우는 대신 같은 조작으로 다른 패턴을 버티는 구조입니다. 이 흐름이 이어지려면 일시정지와 재개, 사망과 이어하기도 플레이의 일부로 다뤄야 합니다.
다음 게임에도 가져갈 두 가지 기준
이번 수정에서 다음 게임에 가져갈 기준은 입력 좌표와 저장 시점입니다. 버튼에는 표시 크기와 텍스처 크기, 입력 영역을 함께 살피는 조건을 남겼습니다. 결과 저장에는 중간 실패와 최종 종료를 구분하고, 같은 판의 결과가 두 번 들어가지 않도록 확인하는 조건을 남겼습니다.
드래그와 결과 화면을 따로 확인하는 데서 그치지 않고, 일시정지를 누른 뒤 이동이 어떻게 이어지는지까지 봐야 합니다. 사망 뒤 이어하기나 종료를 선택했을 때 어떤 값이 남는지도 함께 살펴야 합니다.
개발 자료
게임 프로젝트
한 손 회피 게임의 입력 판정과 결과 저장을 다듬으며 정한 개발·검수 기준을 담았습니다.
GitHub 게임 저장소 · coreline-ai ↗ · 문의·정정 요청