WEEK 05 · 2026
미사일이 날아가고
적이 쏟아진다
지난주에 키보드로 비행기를 움직였다. 이번 주는 진짜 슈팅 게임 — 스페이스바 누르면 미사일이 발사되고, 하늘에서 적이 무한히 내려옵니다. 배열·setInterval·메모리 관리까지 한 번에.
Duration90 minutes
ToolClaude Code
Output발사 + 적 스폰
Phase비행기 게임 (2/4)
02 / Learning Goals⏱ 5분
오늘의 학습 목표
1
발사 시스템 (쿨다운)
스페이스바 한 번에 미사일 한 발. 0.3초 안에 또 누르면 안 나간다 — 연사 제한이 왜 필요한지.
2
적 무한 스폰 (setInterval)
setInterval로 1초마다 적 하나씩. 화면 위에서 시작해서 아래로 내려오게.
3
배열에 객체 저장
미사일 100개·적 100개 → 어떻게 관리? 배열 하나에 다 담고 매 프레임 forEach.
4
메모리 청소 (filter)
화면 밖 나간 미사일·적은 배열에서 빼야 한다. 안 빼면 1분 후 게임이 멈춤.
03 / Concept⏱ 10분
배열 = 물건 담는 상자
미사일이 10발 나가면? 적이 50마리 있으면? 변수 하나씩 만들면 미친다. 그래서 "배열"이라는 상자 하나에 다 담고, 한꺼번에 처리한다.
📦
미사일 배열
[ ◆, ◆, ◆, ... ]
발사할 때마다 +1
발사할 때마다 +1
+
📦
적 배열
[ ▼, ▼, ▼, ... ]
1초마다 +1
1초마다 +1
→
🔄
매 프레임
forEach로 전부
이동 · 그리기
이동 · 그리기
핵심: "많은 걸 한꺼번에 다루려면 배열". 게임은 99% 이 패턴이다.
04 / Cooldown⏱ 10분
왜 쿨다운이 필요할까?
❌ 쿨다운 없으면
스페이스바 꾹 누르면
1초에 60발 발사
→ 미사일 한 줄로 붙어서
그냥 막대기처럼 보임
1초에 60발 발사
→ 미사일 한 줄로 붙어서
그냥 막대기처럼 보임
왜 망함? 60fps 게임 루프는 1초에 60번 코드를 실행. 키 누르고 있으면 매 프레임 발사 = 미사일이 끊김없이 나옴.
메모리도 0.5초만에 1000발 쌓임 → 컴퓨터 멈춤.
✓ 쿨다운 있으면
한 발 쏘면 0.3초 대기
그 사이 스페이스 눌러도 무시
0.3초 지나야 다음 발 가능
→ 진짜 슈팅 게임 느낌
그 사이 스페이스 눌러도 무시
0.3초 지나야 다음 발 가능
→ 진짜 슈팅 게임 느낌
왜 좋음? 마지막 발사 시각을 변수에 저장 → 지금 시각이 그것보다 0.3초 이상 지났을 때만 발사.
이게 모든 슈팅·격투·MMO 게임 공식.
💡 오늘의 공식:
if (지금 - 마지막발사 > 300ms) { 발사하기; 마지막발사 = 지금; } — 한 줄에 다 들어있어.
05 / Live Build · Step 1⏱ 8분
Step 1 — 미사일 한 발 발사
먼저 한 발만 만든다. 스페이스바 한 번에 미사일 하나가 비행기 위치에서 위로 슉.
1
Claude에게 보낼 프롬프트
// 지난주 비행기 코드에 이어서
"지난주에 만든 비행기 게임에 미사일을 추가해줘.
- 스페이스바를 누르면 비행기 머리 위에서 미사일이 생긴다
- 미사일은 노란색 작은 사각형(8x16px)
- 매 프레임마다 위로 8px씩 이동
- 일단 한 발만. 여러 발은 다음 단계에서."
✓
AI가 만들 코드 미리보기
let missile = null; // 미사일 객체
document.addEventListener('keydown', e => {
if (e.code === 'Space' && !missile) {
missile = { x: plane.x + 21, y: plane.y, w: 8, h: 16 };
}
});
function update() {
if (missile) missile.y -= 8; // 위로 이동
}
🎙
멘토 멘트
"missile = null 이라는 게 '아직 미사일 없음'이라는 뜻이에요. 한 발 쏘면 missile 안에 좌표가 들어가요. 다음 단계에서 이걸 배열로 바꾸면 100발도 가능."
✋
학생 액션
한 발 발사 작동하는지 확인 → 발사된 미사일이 화면 밖으로 나가면 어떻게 되는지 관찰. (다음 단계에서 풀 문제)
05 / Live Build · Step 2⏱ 12분
Step 2 — 발사 쿨다운 · 여러 발
이제 배열로 바꿔서 여러 발 발사. 쿨다운 0.3초 적용. 진짜 슈팅 게임 시작.
2
Claude에게 보낼 프롬프트
"미사일을 한 번에 여러 발 발사 가능하게 바꿔줘.
- missile 변수 → missiles 배열로 변경
- 스페이스바 누를 때마다 새 미사일 추가
- 단, 쿨다운 0.3초 — 너무 빨리 누르면 무시
- 매 프레임 모든 미사일이 위로 이동
- 모든 미사일을 그려줘"
✓
핵심 코드 — 쿨다운 + 배열
const missiles = []; // 빈 배열
let lastShot = 0; // 마지막 발사 시각
document.addEventListener('keydown', e => {
if (e.code === 'Space') {
const now = Date.now();
if (now - lastShot > 300) { // 0.3초 지났나?
missiles.push({ x: plane.x + 21, y: plane.y, w: 8, h: 16 });
lastShot = now;
}
}
});
missiles.forEach(m => m.y -= 8); // 다 같이 위로
🎙
핵심 강조
"forEach는 '배열의 모든 것에 똑같은 짓 하기'예요. 미사일이 10개든 100개든 한 줄로 다 처리. 이거 이해하면 게임 만드는 게 진짜 쉬워져요."
05 / Live Build · Step 3⏱ 15분
Step 3 — 적 무한 스폰
화면 위에서 적이 1초마다 한 마리씩 무작위 위치에 나타나고, 아래로 떨어진다. setInterval의 첫 등장.
3
Claude에게 보낼 프롬프트
"적을 추가해줘.
- setInterval로 1초마다 적 한 마리 생성
- 적은 빨간 사각형(30x30px)
- 시작 위치: 화면 맨 위, x는 0~화면너비 사이 랜덤
- 매 프레임 아래로 2px씩 이동
- enemies 배열에 저장하고 forEach로 처리"
✓
핵심 코드 — setInterval로 무한 스폰
const enemies = [];
// 1초마다 자동 실행 — 게임 끝까지 계속
setInterval(() => {
enemies.push({
x: Math.random() * (canvas.width - 30), // 랜덤 x
y: -30, // 화면 위에서 시작
w: 30, h: 30
});
}, 1000); // 1000ms = 1초
// 매 프레임
enemies.forEach(en => en.y += 2); // 다 같이 아래로
🎙
setInterval 한 줄 설명
"setInterval은 '몇 ms마다 이 함수 자동 실행' 명령이에요. 1000은 1초. 500으로 바꾸면 0.5초마다 적 나옴 → 더 어려운 게임. 숫자만 바꾸면 난이도 조절돼요."
🎮
학생 자유 실험
setInterval의 1000을 500·2000·100으로 바꿔보기 → 어떤 게 가장 재밌는지 한 줄로 메모.
05 / Live Build · Step 4⏱ 5분
Step 4 — 적이 아래로 떨어진다
사실 Step 3에서 이미 해결됐어. 여기선 속도 다양화로 게임 느낌을 살린다.
4
Claude에게 보낼 프롬프트
"지금 적이 모두 같은 속도로 떨어지는데, 각 적마다 속도를 다르게 해줘.
- 스폰될 때 speed 값에 1~4 사이 랜덤 숫자 넣어줘
- 빠른 적은 4, 느린 적은 1로 떨어짐
- 색깔도 속도에 따라 다르게:
· 빠를수록 진한 빨강, 느릴수록 연한 분홍"
✓
핵심 코드 — 각 적이 자기 속도 가짐
setInterval(() => {
const speed = 1 + Math.random() * 3; // 1~4 사이
enemies.push({
x: Math.random() * canvas.width,
y: -30, w: 30, h: 30,
speed: speed, // 각자 자기 속도 보유
color: `hsl(0, 80%, ${70 - speed * 12}%)` // 속도→밝기
});
}, 1000);
enemies.forEach(en => en.y += en.speed); // 각자 자기 속도로
🎙
객체 속에 속성
"each 적이 자기 x, y만 가지는 게 아니라 speed, color까지 가지고 있다는 게 포인트. 이게 객체지향의 시작이에요. 다음 주엔 HP, 점수도 객체 안에 넣을 거예요."
05 / Live Build · Step 5⏱ 10분
Step 5 — 화면 밖 청소 (메모리)
미사일이 화면 위로 나갔는데도 배열에 계속 남아 있다. 1분 뒤 게임이 버벅대기 시작. 이걸 해결한다.
5
Claude에게 보낼 프롬프트
"화면 밖으로 나간 미사일·적을 배열에서 자동 삭제해줘.
- 미사일이 y < 0 (화면 위로 나감) → 배열에서 빼기
- 적이 y > canvas.height (화면 아래로 나감) → 배열에서 빼기
- filter로 처리해줘 (남길 것만 남기기)
그리고 콘솔에 missiles.length, enemies.length 매초 출력해줘 — 진짜로 줄어드는지 확인용."
✓
핵심 코드 — filter로 청소
// 매 프레임 실행
// "y가 0보다 큰 것만 남겨라" = 화면 위로 나간 미사일 제거
missiles = missiles.filter(m => m.y > 0);
// "y가 화면높이보다 작은 것만 남겨라" = 화면 밑으로 나간 적 제거
enemies = enemies.filter(en => en.y < canvas.height);
// 디버그용 — 5초 뒤 비교해봐
setInterval(() => {
console.log('미사일:', missiles.length, '적:', enemies.length);
}, 1000);
🎙
왜 중요한가
"filter 안 쓰면 5분 후엔 미사일 9000개가 배열에 남아 있어요. 매 프레임 forEach가 9000번 돌면? 게임이 슬로우모션 돼요. 진짜 게임 회사도 이 문제로 고생해요."
🔍
학생 액션
F12로 콘솔 열고 5분 동안 게임 → missiles.length가 30 넘게 안 가는지 확인. 넘으면 filter 코드 빠진 것.
10 / Checkpoint⏱ 5분
여기까지 됐나? 확인하기
✅잘 됐다면
- 스페이스바로 미사일 발사 (꾹 눌러도 연사 안 됨)
- 1초마다 적이 위에서 떨어짐
- 적마다 속도가 다름 (빠른놈·느린놈 섞임)
- 5분 플레이해도 버벅임 없음 (filter 작동)
- F12 콘솔에 missiles, enemies 숫자 일정 범위 유지
⚠️자주 막히는 부분
- 스페이스 꾹 누르면 무지막지 발사 → 쿨다운 lastShot 코드 빠짐
- 적이 안 나옴 → setInterval이 game.start() 안에 있나 확인
- 1분 뒤 게임 느려짐 → filter 코드 빠짐 (메모리 누수)
- 미사일이 비행기에서 안 나옴 → plane.x 좌표 잘못
- 적이 한 줄로 줄지어 옴 → Math.random 빠짐
11 / Challenge⏱ 10분
더 해보고 싶다면 도전
💥
미사일을 한 번에 3발 발사하게 — 가운데·왼쪽 사선·오른쪽 사선. (트리플 샷)
난이도 ★
🌊
적이 좌우로 흔들면서 내려오게. Math.sin(y * 0.05) * 50 으로 x 변형.
난이도 ★★
⏱
시간이 지날수록 점점 빨라지게 — 10초마다 setInterval 간격을 100ms씩 줄여서 난이도 상승.
난이도 ★★★
12 / Student Gallery⏱ 7분
작년 친구들 작품
🚀
결과물 1
💥
결과물 2
👾
결과물 3
⚡
결과물 4
🎯
결과물 5
✨
결과물 6
📌 첫 학기 종료 후 학생 결과물 사진을 여기에 채울 예정입니다.
13 / Next Week⏱ 3분
다음 시간 예고
WEEK 06 · COMING UP
적 패턴과 점수 시스템 —
맞으면 죽고, 점수가 쌓인다
이번 주는 적과 미사일이 따로따로 움직였다. 다음 주는 둘이 만나는 순간 — 충돌 감지. 미사일이 적을 맞히면 적이 죽고 점수 +. 비행기도 적과 부딪히면 HP가 깎입니다.
PREPARE · 준비물
- 이번 주 코드 (미사일·적·쿨다운까지 다 들어있는 버전)
- 좋아하는 슈팅 게임에서 점수 UI 스크린샷 한 장
- "HP 바를 어떻게 보이게 할지" 1줄 아이디어