[vibecoding] 실습 1 : 간단한 게임 만들기
실습 1 : “루피 vs 아카이누 불주먹” 게임 만들기
1. 실습 배경
첫 실습은 비교적 쉬운 주제였고, 단 두 번의 프롬프팅으로 개발을 완료할 수 있었습니다.
주제는 위에서 날아오는 불주먹을 피하는 게임, 흔히 말하는 “똥피하기” 스타일의 간단한 웹게임이었습니다.
2. GPT-5에 요청한 내용
먼저 GPT-5 모델에 게임 설계 요청을 했습니다.
요구사항은 다음과 같았습니다.
다음 요구사항을 구현하기위한 개발 설계 진행하라.
- 비즈니스 로직을 그룹화하고, 적절한 단위로 모듈화하라. Over Engineering을 피해 최소한의 복잡도와 코드로 구현해야한다.
- 개요, 세부 유스케이스, 주요 모듈 및 역할을 포함하여 응답하라.
- 구체적인 코드는 포함하지 않는다. 마크다운으로 응답하라.
---
(개요)
데스크탑/모바일에서 바닥에 있는 캐릭터(원피스에 나오는 루피)를 마우스/슬라이드로 움직여서 위에서 떨어지는 불주먹(원피스 아카이누의 불주먹)을 피해서 점수를 얻는 게임
(점수)
점수는 불주먹을 하나 피할때마다 10점씩 올라감
(레벨)
원피스 만화의 컨셉에 맞게 일반인부터 시작해서 해적왕이 되는 단계를 나눌꺼야.
레벨이 올라갈수록 점점 피하기 어렵게 만들꺼야.
(불주먹)
위에서 떨어지고 각 불주먹마다 속도는 랜덤 (빠른 것도 있고 느린것도 있음)
단, 모든 불주먹에 대한 점수는 같음
땅에 불주먹이 떨어지면 사라짐.
레벨마다 빠름의 속도와 느림의 속도가 점점 올라감
(디자인)
캐릭터 : /public/luffy.png
불주먹 : /public/akainu.png
좌상단에 실시간으로 아래와 같이
점수 : p
시간 : n초
레벨 : 일반인
이런식으로 나오게 할꺼야.
그리고 루피가 불주먹에 맞으면 게임오버가 되고 게임오버가되면 게임오버 라는 문구와 함께 현재 최종 점수와 진행 시간 레벨 그리고 다음레벨은 무엇인지 나오게끔할꺼야.
만약 최종 레벨이라면 최종레벨에 도달하면 최종레벨 난이도를 게임오버가 될때까지 진행하게 할꺼야.
(개발 언어 및 배포)
next.js를 사용하여 하나의 링크로 게임을 할 수 있는 웹앱(설치형x) 게임을 만들거야.
그리고 vercel로 배포할꺼야.
그 결과, 게임 개요 -> 유스케이스 -> 모듈 설계 -> 상태 흐름 -> 아키텍처까지 상세히 구조화된 프롬프트를 받을 수 있었습니다.
내용은 굉장히 체계적이었고, Next.js와 Vercel을 이용해 웹 배포까지 고려된 설계였습니다.
- 하지만 내가 의도된 것과 같았는지 꼭! 확인을 해야합니다
3. 실제 구현 & 문제 발생
받은 프롬프트를 Cursor에 입력해 바로 로컬에서 실행해 보았습니다.
아래는 받은 프롬프트 입니다.
🎮 개발 설계 — “루피 vs 아카이누 불주먹” (Next.js / Vercel)
1) 개요
플랫폼: 웹(데스크탑/모바일), 설치 불필요 — Next.js 기반, Vercel 배포
조작: 마우스 드래그(데스크탑) / 터치 슬라이드(모바일)로 루피 이동
목표: 위에서 랜덤 속도로 떨어지는 불주먹을 피하며 생존 → 불주먹 1개 회피마다 10점
레벨링: 원피스 감성 단계(일반인 → … → 해적왕). 레벨이 오를수록 스폰 빈도↑ / 속도 범위↑
종료: 루피가 불주먹에 맞으면 게임오버 → “게임오버” 문구 + 최종 점수/시간/레벨/다음 레벨 안내
최종 레벨: 도달 시 그 난이도를 무한 진행(게임오버 때까지)
디자인 리소스
캐릭터: /public/luffy.png
불주먹: /public/akainu.png
HUD(좌상단)
점수: p / 시간: n초 / 레벨: 일반인 (실시간 갱신)
2) 세부 유스케이스
UC-01 게임 시작
사용자는 페이지 접속 → 자동/버튼으로 게임 시작
초기화: 점수 0, 시간 0초, 레벨 “일반인”, 불주먹 없음, 루피 중앙 하단 배치
UC-02 캐릭터 이동
데스크탑: 마우스 다운 후 드래그 → 루피 x좌표 갱신
모바일: 터치 슬라이드 → 루피 x좌표 갱신
화면 경계 밖으로 나가지 않도록 위치 클램프
UC-03 불주먹 스폰
상단 랜덤 x좌표에서 스폰
현재 레벨 설정값에 따라 스폰 간격(평균) 및 낙하 속도 범위를 적용
바닥(y_max) 도달 시 해당 불주먹 제거(“회피 성공”은 충돌 없이 지나간 것으로 간주)
UC-04 점수 계산
불주먹이 충돌 없이 바닥에 닿아 사라질 때 +10점
HUD에 즉시 반영
UC-05 레벨 상승
조건: 누적 시간 또는 누적 회피 수(택1, 아래 설계에서는 시간 기준)
레벨 업 시: 스폰 간격 단축, 속도 범위 상향 → 난이도 증가
HUD의 레벨명 갱신, 짧은 토스트/진동(모바일)로 피드백(선택)
UC-06 충돌/게임오버
불주먹과 루피 충돌 판정 시 게임 정지
“게임오버” 오버레이 + 최종 점수/진행 시간/레벨/다음 레벨명 표시
[다시 시작] 버튼으로 UC-01 초기화 후 재시작
UC-07 기록/세션
최고 점수(로컬 저장) 표시(선택)
일시정지/재개(브라우저 포커스 잃음 시 자동 일시정지, 선택)
3) 게임 규칙 파라미터(최소 구성)
레벨 테이블(예시)
단계\t레벨명\t평균 스폰 간격(ms)\t속도 범위(px/frame)\t레벨 업 조건(경과 시간)
1\t일반인\t900\t3 ~ 5\t20초
2\t해군 신병\t800\t4 ~ 6\t20초
3\t해적단 선원\t700\t5 ~ 7\t25초
4\t부선장\t600\t6 ~ 9\t25초
5\t선장\t520\t7 ~ 10\t30초
6\t사황 도전자\t450\t8 ~ 12\t35초
7\t사황\t380\t10 ~ 14\t40초
8\t해적왕(최종)\t320\t12 ~ 16\t무한(레벨 업 없음)
단순화 원칙: 스폰 간격은 지수적까지는 아니더라도 단계별 소폭 단축, 속도 범위도 선형 증가.
점수는 모든 불주먹 동일(+10)로 규칙 단순화 유지.
4) 아키텍처(Over Engineering 방지)
핵심 원칙
Canvas 1장 + React 최소 상태
단일 페이지(/)에 게임을 모두 배치
ECS(엔진/시스템 아키텍처) 불필요 → 가벼운 모듈 함수로 분리
서버 불필요(순수 프론트) — 배포만 Vercel
페이지/컴포넌트 구조(제안)
app/page
GameCanvas: 캔버스 렌더(루프 포함)
HUD: 점수/시간/레벨
GameOverModal: 게임오버 정보/다시시작
StartOverlay(선택): 시작 안내/가이드
5) 주요 모듈 및 역할
파일/모듈 단위를 작게 유지하되, 관심사별로 딱 한 번만 쓰일 순수 함수 위주 구성.
A. gameState (상태 관리)
역할: 게임 러닝 상태, 점수, 경과 시간, 현재 레벨 인덱스, 불주먹 리스트, 루피 좌표
구성
running: boolean
score: number
elapsedMs: number
levelIndex: number
player: { x, y, width, height }
meteors: Array<{ id, x, y, vy, width, height }>
rngSeed(선택)
행위: 초기화, 시작/일시정지/종료 토글, 레벨 업데이트
B. levelConfig
역할: 레벨별 파라미터 정의(위 표)와 조회 유틸
행위: 현재 레벨의 스폰 간격/속도 범위 반환, 최종 레벨 여부 판별
C. spawnManager
역할: 다음 스폰 시점 관리(간격 랜덤화는 단순 ±10~15%)
행위: 현재 시간 기준 스폰 여부 판단, 스폰 시 엔티티 추가(랜덤 x, 속도)
D. physics
역할: 위치 업데이트(불주먹 y += vy), 경계 처리
행위: 바닥 도달 시 불주먹 제거 및 점수 +10 이벤트 발생
E. collision
역할: 충돌 판정(AABB 사각형 충돌)
행위: 루피 vs 각 불주먹 충돌 → 게임오버 이벤트
F. input
역할: 마우스/터치 이동을 루피 x좌표로 반영
행위: 좌표 변환(캔버스 기준), 경계 클램프
G. renderer
역할: 단일 Canvas에 프레임별 그리기
행위: 배경, 루피, 불주먹, HUD(텍스트는 HTML HUD로 분리해 성능/선명도 확보 가능)
H. loop
역할: requestAnimationFrame 기반 게임 루프
행위: 프레임 델타 계산 → spawn → physics → collision → render 순서 실행
I. persistence(선택)
역할: 최고 점수 로컬 저장/로드(localStorage)
6) 상태 흐름(간단 상태 머신)
IDLE(시작 대기) → RUNNING(진행) →
충돌 시 GAMEOVER
포커스 아웃/일시정지 시 PAUSED → 재개 시 RUNNING
RUNNING에서 레벨 업 조건 충족 시 레벨 인덱스+1
최종 레벨에서는 레벨 업 없음(무한 난이도 유지)
7) 렌더링 & 루프 설계
루프 주기: requestAnimationFrame(약 60fps)
델타 시간 사용: 속도(px/sec) 대신 px/frame로 단순화(기기별 큰 차이 없을 정도의 캐주얼 난이도)
Z-순서: 배경 → 불주먹 → 루피 → HUD(별도 DOM)
리소스 로딩: 페이지 진입 시 이미지 2장 프리로드 후 시작
8) 충돌 판정
AABB(축 정렬 경계 사각형)
단순 조건: abs(centerX1-centerX2) < (w1+w2)/2 && abs(centerY1-centerY2) < (h1+h2)/2
성능: 불주먹 개수 수십 개 수준 → O(N)로 충분(추가 구조 불필요)
9) 입력 처리(반응형)
데스크탑: pointerdown/move/up
모바일: touchstart/move/end 또는 통일된 Pointer 이벤트 사용
좌표 변환: 캔버스 바운딩 박스 기준 → 게임 좌표
클램프: player.x를 [0, canvasWidth - playerWidth] 범위로 제한
10) 레벨/스폰 로직(최소 복잡도)
스폰 간격: 레벨별 “평균 간격”에서 ±10~15% 랜덤
속도: 레벨별 범위에서 균일 랜덤
레벨 업 기준: 경과 시간 누적이 간단하고 직관적(HUD의 시간과 일치)
최종 레벨: 인덱스 상한 고정, 스폰/속도만 해당 수준 유지
11) HUD & 게임오버 화면
HUD(좌상단): 점수/시간/레벨 실시간 텍스트(React state 바인딩)
게임오버 오버레이
표시: “게임오버”
최종 점수, 진행 시간, 최종 레벨, 다음 레벨명(최종이면 “최종 레벨입니다”)
버튼: “다시 시작”
12) 성능/호환성
Canvas 1장 유지, 불필요한 리렌더 방지
이미지 스케일 고정(디바이스 DPR 대응은 선택)
메모리 누수 방지: 이벤트 핸들러/RAF 클린업
모바일에서의 터치 스크롤 방지(캔버스 영역에서만)
13) 접근성/UX
간단한 튜토리얼: 첫 방문 시 1회 오버레이(“드래그/슬라이드로 이동”)
모바일 진동 피드백(레벨 업/게임오버 시, 선택)
일시정지 자동화: 탭 전환 시 일시정지(선택)
14) 배포 & 환경
Next.js(App Router): CSR 중심 단일 페이지
정적 자원: /public/luffy.png, /public/akainu.png
Vercel 배포: 기본 설정(빌드 커맨드/출력 기본값), 환경 변수 불필요
도메인 연결(선택)
15) 로그 & QA 체크리스트(요약)
시작/종료/레벨업/게임오버 콘솔 로그(개발 모드)
체크리스트
캔버스 리사이즈 시 위치/충돌 정상 동작
데스크탑/모바일 입력 모두 정상
레벨 전환 시 난이도 상승 체감
최종 레벨 도달 시 무한 진행 확인
게임오버 정보 정확(점수/시간/레벨/다음 레벨명)
16) 확장 아이디어(선택)
사운드 효과(회피/충돌/레벨업)
아이템(잠깐 무적, 속도 감소) — 현재 요구사항엔 포함하지 않음
캐릭터/배경 스킨
17) 최소 구현 범위 요약(실행 순서)
Canvas & 루프 뼈대
루피 이동(입력 처리 + 경계)
불주먹 스폰/낙하
충돌/게임오버
점수/HUD/시간
레벨 시스템(시간 기반 상승)
게임오버 오버레이 + 재시작
Vercel 배포
대체적으로 잘 동작했지만 두 가지 문제가 있었습니다.
-
클릭 시 캐릭터 순간이동
마우스를 클릭하면 루피가 해당 위치로 순간이동하는 버그가 있었습니다. -
모바일 앱 같은 UI
웹게임보다는 모바일 앱에 가까운 UI가 만들어졌습니다.
4. 프롬프트 수정 및 개선
그래서 GPT-5에 추가 요청을 했습니다.
- 마우스 클릭 순간이동 → 제거
- 마우스 이동만으로 캐릭터 이동 가능하게 변경
- 방향키 입력으로도 이동 가능하게 개선
- 모바일에서도 순간이동 방지
- 전체 UI를 웹게임 느낌으로 조정
수정된 프롬프트를 적용하자 문제들이 해결되었고, 원하던 방식으로 동작했습니다.
5. 배포
로컬에서 확인 후, 바로 Vercel을 통해 배포했습니다.
👉 결과물: https://pakko-vibemafia-test1.vercel.app/
6. 느낀 점
이번 경험에서 크게 느낀 점은 다음과 같습니다.
- 단순히 “AI가 다 해주겠지”라는 생각은 부족하다.
- 잘 쓰는 사람과 못 쓰는 사람의 차이는 프롬프트의 질과 검증 과정에서 갈린다.
- 결과물이 잘 나와도, 직접 확인하고 부족한 부분을 짚어내는 과정이 반드시 필요하다.
이번 실습은 짧은 과정이었지만, 제가 왜 지금까지 바이브 코딩을 잘 못했는지를 깨닫는 계기가 되었습니다.
솔직히 좀 띵… 했습니다. 하지만 분명 한 걸음 전진했다고 생각합니다.
이제부터가 진짜 시작! 더 발전해 보겠습니다!!!!!!!
Leave a comment