3차시: 코드에 생명 불어넣기 - while 루프로 애니메이션 만들기¶
🧠 애니메이션 루프¶
while True + rate()가 만드는
무한 프레임의 원리
🧠 rate() 함수¶
프레임 속도를 제어하는
Vpython의 시간 조절기
💻 공 움직이기 실습¶
pos.x를 반복문에서 변경하여
등속 직선 운동 구현
🚀 도전: 나만의 애니메이션¶
속도·방향·여러 객체를
조합한 장면 만들기
⏱️ 수업 흐름¶
1단계: 도입 — 영화의 비밀 (5분)¶
영화·애니메이션이 정지 이미지의 빠른 연속이라는 원리를 떠올리며, 코드에서 이를 어떻게 구현하는지 핵심 질문으로 탐구합니다.
2단계: 핵심 개념 — while 루프와 rate() (10분)¶
while True 무한 루프가 애니메이션 엔진이 되는 원리, rate() 함수가 프레임 속도를 제어하는 역할을 비유와 함께 이해합니다.
3단계: 따라하기 실습 — 공을 움직여보자 (20분)¶
v1(기본 이동) → v2(속도 개념 도입) → v3(바닥과 함께 장면 꾸미기) → 최종(에러 수정 포함) 순서로 점진적으로 코드를 빌드업합니다.
4단계: 연습 문제 & 도전 과제 (10분)¶
기초(방향 변경) → 응용(여러 객체 이동) → 도전(2차시 장면에 애니메이션 추가) 3단계 문제를 풀어봅니다.
5단계: 평가 & 성찰 (5분)¶
퀴즈로 개념을 점검하고, 자기점검 체크리스트를 작성합니다. 다음 차시를 미리 엿봅니다.
1단계: 🎬 도입 — 영화의 비밀¶
여러분, 영화를 볼 때 화면 속 배우가 자연스럽게 움직이는 것처럼 보이죠? 하지만 실제로는 1초에 24장의 정지된 사진이 빠르게 넘어가는 것입니다. 우리 눈이 그 차이를 인식하지 못할 만큼 빠르기 때문에 "움직인다"고 느끼는 거예요.
게임도 마찬가지입니다. 1초에 60장(60fps)의 화면을 그려서 캐릭터가 부드럽게 달리는 것처럼 보이게 만듭니다.
🤔 그렇다면 질문!
Vpython에서 공 하나를 오른쪽으로 움직이려면, 우리는 무엇을 "반복"해야 할까요?
정답의 핵심: "공의 위치를 아주 조금 바꾼다" → "화면을 다시 그린다" → 이것을 수없이 반복한다!
바로 이 "반복"을 담당하는 것이 여러분이 이미 배운 while 반복문입니다. 오늘 우리는 while 루프에 새로운 역할을 부여할 겁니다 — 애니메이션 엔진이라는 역할이요.
▲ 애니메이션의 핵심 원리: 위치 변경 → 화면 그리기 → 대기 → 반복
이 세 가지를 코드로 어떻게 표현하는지, 지금부터 하나씩 알아보겠습니다!
2단계: 📚 핵심 개념 — while 루프와 rate()¶
🧠 핵심 개념 1: while True — 무한 애니메이션 루프¶
일상 비유부터 시작합시다¶
시계의 초침을 생각해보세요. 초침은 "1초 전진 → 1초 전진 → 1초 전진 → ..." 을 영원히 반복합니다. 누가 "멈춰!"라고 하지 않는 한요.
Vpython의 애니메이션도 똑같습니다. "위치 변경 → 위치 변경 → 위치 변경 → ..." 을 영원히 반복해야 공이 계속 움직입니다. 이것이 바로 while True:의 역할입니다.
정확한 정의¶
| 구분 | 일반 while 루프 | 애니메이션 while 루프 |
|---|---|---|
| 조건 | while count < 10: (언젠가 끝남) |
while True: (영원히 반복) |
| 용도 | 정해진 횟수만큼 작업 | 매 프레임마다 화면 갱신 |
| 종료 | 조건이 False가 되면 | 프로그램을 직접 종료할 때 |
| 비유 | 100m 달리기 (결승선 있음) | 러닝머신 (멈출 때까지 계속) |
여러분이 이전에 배운 while count < 10:은 10번 반복하고 멈추는 루프였죠. 하지만 애니메이션은 화면을 계속 갱신해야 하므로, 의도적으로 끝나지 않는 while True:를 사용합니다.
# 여러분이 이미 아는 while 루프
count = 0
while count < 5:
print(count)
count += 1
# → 0, 1, 2, 3, 4 출력 후 끝남
# 오늘 배울 애니메이션 루프 (개념만 미리 보기)
while True: # <- 영원히 반복! (애니메이션 엔진)
rate(60) # <- 1초에 60번만 실행해! (속도 조절기)
ball.pos.x += 0.01 # <- 공 위치를 조금 이동
위 코드의 1번째 줄 while True:가 바로 무한 애니메이션 루프입니다. True는 절대 False가 되지 않으므로, 이 루프는 프로그램을 종료하기 전까지 계속 돌아갑니다.
🧠 핵심 개념 2: rate() — 프레임 속도 조절기¶
일상 비유부터 시작합시다¶
여러분이 플립북(넘기면 그림이 움직이는 수첩) 을 만든다고 상상해보세요.
- 너무 빨리 넘기면? → 그림이 눈에 안 보이고 휙 지나감
- 너무 느리게 넘기면? → 뚝뚝 끊겨서 애니메이션처럼 안 보임
- 적당한 속도로 넘기면? → 부드럽게 움직이는 것처럼 보임! ✨
rate() 함수가 바로 이 "넘기는 속도"를 조절하는 역할입니다.
정확한 정의¶
rate(n)은 "이 루프를 1초에 최대 n번 실행하라"는 명령입니다.
| rate() 값 | 의미 | 체감 |
|---|---|---|
rate(10) |
1초에 10프레임 | 뚝뚝 끊기는 느낌 |
rate(30) |
1초에 30프레임 | 꽤 부드러움 |
rate(60) |
1초에 60프레임 | 매우 부드러움 (게임 수준) |
rate(200) |
1초에 200프레임 | 눈에 차이 거의 없음 |
| rate() 없이 | CPU가 허용하는 최대 속도 | 컴퓨터 과부하 위험! ⚠️ |
⚠️ 중요! rate()를 빼먹으면 컴퓨터가 미친 듯이 루프를 돌려서 브라우저가 멈추거나 프로그램이 응답 불가 상태가 될 수 있습니다. while True 안에는 반드시 rate()를 넣으세요!
rate()가 하는 일을 그림으로 보면¶
▲ rate(60)은 매 반복마다 "1/60초(약 0.017초)가 지났는지" 확인하고, 아직이면 잠깐 기다리게 합니다.
심화: rate()가 없으면 왜 위험할까?¶
rate() 없이 while True:를 실행하면, 컴퓨터는 CPU 능력의 100%를 써서 초당 수만~수십만 번 루프를 돌립니다. 이러면:
- 공이 순식간에 화면 밖으로 사라짐 (너무 빨라서 못 봄)
- 브라우저/프로그램이 응답 불가 상태가 됨
- 컴퓨터 팬이 미친 듯이 돌아감 🔥
rate()는 "쉬엄쉬엄 해!"라고 말해주는 속도 제한기입니다. 이것만 기억하세요!
3단계: 💻 따라하기 실습 — 공을 움직여보자!¶
실행 환경: Vpython 3.2 (Web VPython 또는 GlowScript에서 실행 가능)
자, 이제 직접 코드를 쳐볼 시간입니다! 🎉 한 줄씩 추가하면서 공에 생명을 불어넣어 봅시다.
📌 v1: 가장 기본 — 공 하나를 오른쪽으로 밀기¶
먼저 가장 단순한 코드부터 시작합니다. 딱 5줄이면 됩니다.
from vpython import *
ball = sphere(pos=vector(0, 0, 0), radius=0.5, color=color.red)
while True: # <- 여기가 [무한 애니메이션 루프]
rate(30) # <- 여기가 [프레임 속도 조절기] - 1초에 30번
ball.pos.x += 0.1 # <- 여기가 [위치 변경] - x좌표를 0.1씩 증가
실행 결과: 빨간 공이 오른쪽(+x 방향)으로 천천히 이동합니다.
🔍 개념-코드 매핑
- 3번째 줄
ball = sphere(...): 2차시에서 배운 공 생성입니다.- 5번째 줄
while True:: 이 루프가 애니메이션 엔진입니다. 프로그램이 종료될 때까지 아래 코드를 반복합니다.- 6번째 줄
rate(30): 1초에 30번만 실행하라는 속도 제한기입니다.- 7번째 줄
ball.pos.x += 0.1: 매 프레임마다 공의 x좌표를 0.1만큼 증가시킵니다. 이것이 등속 직선 운동입니다!💡 잠깐!
ball.pos.x += 0.1이 뭔가요?
ball.pos는 공의 위치(vector)이고,.x는 그 중 x좌표만 가리킵니다.+= 0.1은 "현재 값에 0.1을 더해라"라는 뜻이죠. 즉, 매 프레임마다 공이 오른쪽으로 0.1만큼 이동하는 겁니다.
🔬 rate() 값을 바꿔보는 실험¶
v1 코드에서 rate(30)의 숫자만 바꿔서 실행해보세요. 직접 해보는 것이 핵심입니다!
| 실험 | 코드 변경 | 예상 결과 | 왜 그럴까? |
|---|---|---|---|
| 실험 A | rate(5) |
뚝뚝 끊기며 느리게 이동 | 1초에 5번만 위치를 바꾸니까 |
| 실험 B | rate(30) |
적당히 부드럽게 이동 | 1초에 30번 위치를 바꿈 |
| 실험 C | rate(100) |
매우 부드럽고 빠르게 이동 | 1초에 100번 위치를 바꿈 |
| 실험 D | rate(1) |
1초에 한 번 "뚝" 이동 | 1초에 딱 1번만! |
🤔 여기서 질문! rate(5)와 rate(100)은 부드러움도 다르지만, 공의 이동 속도도 다릅니다. 왜 그럴까요?
답: rate(5)는 1초에 5번 × 0.1 = 0.5만큼 이동하고, rate(100)은 1초에 100번 × 0.1 = 10만큼 이동합니다. rate 값이 클수록 같은 시간에 더 많이 이동하게 됩니다!
이 문제를 해결하는 방법은 v2에서 알아봅시다. 👇
📌 v2: 속도(velocity) 개념 도입 — rate와 분리하기¶
v1의 문제점은 rate를 바꾸면 공의 이동 속도까지 바뀐다는 것이었습니다. 실제 애니메이션에서는 프레임 속도와 객체 이동 속도를 분리해야 합니다.
이전 코드에서 뭐가 바뀌었나요?
- ✅ dt 변수 추가 (시간 간격)
- ✅ velocity 변수 추가 (속도)
- ✅ 위치 변경 공식: pos.x += velocity * dt
from vpython import *
ball = sphere(pos=vector(-5, 0, 0), radius=0.5, color=color.red)
# 물리적 속도를 별도 변수로 관리 (rate와 분리!)
velocity = 2 # <- 1초에 2만큼 이동하겠다는 뜻
dt = 0.01 # <- 한 프레임의 시간 간격 (초)
while True:
rate(100) # 1초에 100프레임
ball.pos.x += velocity * dt # <- 여기가 [등속 직선 운동 공식]
실행 결과: 빨간 공이 왼쪽(-5)에서 시작하여 오른쪽으로 부드럽게 이동합니다.
🔍 개념-코드 매핑
- 6번째 줄
velocity = 2: 공의 속도입니다. "1초에 x좌표로 2만큼 이동"을 의미합니다.- 7번째 줄
dt = 0.01: 시간 간격(delta time)입니다. 한 프레임이 0.01초를 나타냅니다.- 11번째 줄
ball.pos.x += velocity * dt: 이것이 등속 직선 운동 공식거리 = 속도 × 시간입니다!- velocity(2) × dt(0.01) = 0.02씩 이동
- 1초에 100프레임 × 0.02 = 2만큼 이동 → velocity와 정확히 일치! ✅
왜 이렇게 하나요? 이제 rate()를 30으로 바꾸든 200으로 바꾸든, 공의 실제 이동 속도는 velocity가 결정합니다. 프레임 속도와 물리적 속도가 깔끔하게 분리된 것이죠!
| 방식 | rate 변경 시 | 속도 제어 |
|---|---|---|
v1: pos.x += 0.1 |
공 속도도 같이 변함 ❌ | 어려움 |
v2: pos.x += velocity * dt |
부드러움만 변함 ✅ | velocity로 쉽게 제어 |
🚨 에러 경험 — rate()를 빼먹으면?¶
자, 이제 일부러 잘못된 코드를 실행해봅시다. 에러를 직접 만나봐야 기억에 남으니까요! 😈
아래 코드에서 이상한 점을 찾아보세요:
from vpython import *
ball = sphere(pos=vector(-5, 0, 0), radius=0.5, color=color.red)
velocity = 2
dt = 0.01
while True:
# rate()를 빼먹었습니다! 🚨
ball.pos.x += velocity * dt
이 코드를 실행하면 어떤 일이 벌어질까요?
🔍 결과 확인하기
**증상**: 1. 공이 눈 깜짝할 사이에 화면 밖으로 사라집니다 2. 브라우저가 먹통이 되거나 극도로 느려집니다 3. "페이지가 응답하지 않습니다" 경고가 뜰 수 있습니다 **원인 분석**: - `rate()`가 없으면 while True 루프가 **CPU 최대 속도**로 돌아갑니다 - 1초에 수만~수십만 번 `pos.x += 0.02`가 실행됩니다 - 공이 순식간에 x = 수천~수만 좌표로 날아가버립니다 - 브라우저가 3D 렌더링을 따라가지 못해 멈춥니다 **수정 코드**: `while True:` 바로 다음 줄에 `rate(100)`을 추가합니다.📌 외워두세요!
while True:다음 줄에는 반드시rate()를 쓴다! 이건 Vpython 애니메이션의 철칙입니다.
🚨 에러 경험 2 — pos를 잘못 수정하면?¶
하나 더 실험해봅시다. 아래 코드를 실행하면 어떻게 될까요?
from vpython import *
ball = sphere(pos=vector(-5, 0, 0), radius=0.5, color=color.red)
velocity = 2
dt = 0.01
while True:
rate(100)
ball.pos.x = velocity * dt # += 가 아니라 = 를 썼습니다!
이 코드를 실행하면 어떤 에러가 날까요?