게임은 다 만들었고, 그래서 나는 뭘 배운 거지
퐁 게임을 브라우저로 옮긴 이야기랑 그 뒤에 벌어진 세 번의 재판까지 풀어놓고 나니, 문득 이런 생각이 들더라고. 게임은 어찌어찌 완성했는데, 그래서 나는 이 며칠 동안 뭘 배운 거지? 남는 게 있어야 다음에 벽돌깨기든 슈팅이든 또 만들 거 아니야.
그래서 AI 조카를 불러다 정리를 시켰어.
"퐁에서 배운 거 표로 좀 만들어줘."
다음에 뭘 만들든 써먹을 수 있는 패턴
| 하고 싶은 것 | 이렇게 하면 된다 |
|---|---|
| 화면에 그림을 그리고 싶다 | <canvas> 태그 하나 놓고 getContext("2d")로 그리기 도구를 받는다. 이후 도형/글자는 다 이 도구로 그린다 |
| 사각형/원/글자를 그리고 싶다 | fillRect(네모), arc(원), fillText(글자) — 이 세 개만 알면 웬만한 2D 게임 화면은 다 그린다 |
| 게임을 멈추지 않고 계속 움직이게 하고 싶다 | 함수 하나(loop) 안에서 "계산 → 그리기"를 하고, 마지막에 requestAnimationFrame(loop)로 자기 자신을 다시 예약한다. 이게 한 번 걸리면 알아서 1초에 60번씩 반복된다 |
| 키보드 입력을 받고 싶다 | 키를 누르는 순간 처리하지 말고, keys라는 객체에 "지금 눌려있다/안 눌려있다"만 기록해두고, 매 프레임마다 그 상태를 확인한다 |
| 여러 정보를 하나로 묶어 다루고 싶다 (패들, 공, 캐릭터 등) | { x: 0, y: 0, vx: 5 }처럼 객체 하나로 묶는다. 클래스까진 필요 없고, 관련된 값들을 한 덩어리로 들고 다니면 편하다 |
| 비슷한 값이 여러 개 있고 반복해서 쓰고 싶다 (난이도, 아이템 목록 등) | 배열에 담아두고 forEach로 하나씩 꺼내 쓴다. 값 추가/수정할 때 코드 안 건드리고 배열만 고치면 된다 |
| 두 물체가 부딪혔는지 확인하고 싶다 | 각 물체를 사각형(x, y, 가로, 세로)으로 보고, 겹치는지 좌표 비교 함수를 하나 만들어둔다. 한 번 만들어두면 어떤 게임에도 재사용 가능 |
| 게임이 "대기 중 / 진행 중 / 일시정지 / 끝남" 같은 여러 상태를 오갈 때 | 상태마다 true/false 값(플래그)을 하나씩 만들어두고, 계산하는 함수 맨 앞에서 "지금 이 상태면 계산 건너뛰기"부터 체크한다 |
| 상황에 따라 다른 색/문구를 보여주고 싶다 | 조건 ? A : B 한 줄로 "맞으면 A, 아니면 B" 처리 (if문을 짧게 쓴 버전) |
| 문자열 안에 변수 값을 끼워 넣고 싶다 | `${변수}` 형태로 그냥 문자열 안에 넣으면 된다 (문자열을 + 로 이어붙일 필요 없음) |
캔버스 준비 → 반복 루프 걸기 → 입력 기록해두기 → 물체는 객체로 묶기 → 부딪힘은 좌표 비교로 확인.
하고 싶은 것 → 품질을 높이는 요청법
| 하고 싶은 것 | 이렇게 요청하면 더 좋다 | 왜 |
|---|---|---|
| 패들이랑 공을 화면에 만들고 움직이고 싶다 | "화살표 키로 패들을 움직이게 해줘. 화면 밖으로는 못 나가게" | 경계 조건을 안 말하면 패들이 화면 밖으로 사라지는 버그가 생기기 쉬움 |
| 공이 벽이나 패들에 부딪히면 튕기게 하고 싶다 | "패들의 어디에 맞았는지에 따라 반사각이 달라지게 해줘" | 이거 없으면 공이 똑같은 경로로만 왕복하다 영원히 안 끝나는 버그가 남 (실제로 겪었던 무한 랠리 버그) |
| 게임이 끊기지 않고 부드럽게 계속 움직이면 좋겠다 | "계산하는 부분이랑 화면 그리는 부분을 나눠서 짜줘" | 안 나누면 나중에 기능 하나 고칠 때 다른 것까지 같이 망가짐 |
| 점수를 화면에 보여주고 싶다 | "몇 점 먼저 내면 이기는지도 정해서, 승부 나면 자동으로 멈추게 해줘" | "보여주기"만 말하면 게임이 안 끝나는 무한 루프로 짜일 수 있음 |
| 난이도를 쉬움/보통/어려움 이렇게 나누고 싶다 | "나중에 숫자만 바꿔서 밸런스 조절하기 쉽게 값들을 한군데 모아줘" | 안 그러면 난이도 값이 코드 여기저기 흩어져서 나중에 수정할 때 다 찾아다녀야 함 |
| 게임 시작 전에 선택 화면을 보여주고 싶다 | "선택하기 전엔 게임 로직이 아예 안 돌아가게 해줘" | 안 그러면 선택 화면 뒤에서 공이 이미 움직이고 있는 이상한 상태가 될 수 있음 |
| 게임 하다가 잠깐 멈추고 싶다 | "일시정지 중엔 계산은 멈추고 화면엔 안내 문구만 보이게 해줘" | "멈춰줘"만 말하면 화면만 멈추고 내부 계산은 계속 돌아가는 경우가 있음 |
| AI가 너무 완벽하게 못 받아치게 하고 싶다 | "AI가 공 위치를 정확히 못 맞히고 매번 살짝씩 빗나가게 해줘. 완전 랜덤 말고 조금만" | AI가 100% 완벽하면 절대 못 이기는 게임이 되고, 완전 랜덤이면 반대로 너무 쉬워져서 밸런스가 안 맞음 (실제 aiAimOffset 추가 사례) |
| 점수 난 다음 바로 공이 안 튀어나오면 좋겠다 | "득점하면 바로 시작하지 말고 3초 정도 카운트다운 보여준 다음 공이 나가게 해줘" | 카운트다운이 없으면 준비도 안 됐는데 공이 튀어나와서 매번 억울하게 실점함 |
오늘의 결론
이게 블로그를 작성하다 보니 기록할 게 왜 이리 많은지 모르겠네. 앞으로는 조금 줄여나갈 필요가 있어 보이지만, 이런 기록은 나중에 도움이 될 것 같아서 정리해두기로 했어.