6차시: 중력을 눈으로 보다 - 가속도와 포물선 운동 시뮬레이션¶
🧠 가속도와 중력 벡터¶
속도를 매 순간 바꾸는 힘, gravity = vector(0, -9.8, 0) 한 줄의 마법
💻 포물선 운동 시뮬레이션¶
등속 운동 코드에 딱 한 줄을 추가해서 공이 곡선을 그리게 만들기
🔬 발사 각도 실험¶
초기 속도의 방향과 크기를 바꾸며 궤적 변화를 탐구하기
🎯 바닥 충돌 & 궤적¶
make_trail로 아름다운 포물선을 남기고, 바닥에 닿으면 멈추기
🔥 도입: 등속 vs 가속, 한 줄의 차이 (5분)¶
5차시 등속 운동 코드를 떠올리며, "속도가 변한다"는 것이 무엇인지 체감합니다. 농구공을 위로 던졌을 때의 경험을 떠올려봅니다.
📚 개념: 가속도 벡터와 velocity 갱신 패턴 (10분)¶
가속도의 정의를 일상 비유로 이해하고, velocity += gravity * dt 패턴이 왜 작동하는지 코드-개념 매핑으로 학습합니다.
💻 실습: 포물선 운동 시뮬레이션 만들기 (20분)¶
v1(자유낙하) → v2(포물선 운동) → v3(궤적 + 바닥 충돌)으로 점진적으로 코드를 완성합니다. 에러 경험도 포함됩니다.
🔬 탐구: 발사 각도와 속력 실험 (10분)¶
초기 속도의 각도와 크기를 바꿔가며 궤적이 어떻게 달라지는지 실험하고 결과를 정리합니다.
📝 정리 & 평가 (5분)¶
핵심 개념을 복습하고, 형성 평가와 자기점검으로 학습을 마무리합니다.
🔥 도입: 등속 운동에서 빠진 한 가지¶
여러분, 5차시에서 공이 일직선으로 쭉 날아가는 등속 운동을 만들었습니다. 기억나시나요?
이 코드에서 velocity는 절대 변하지 않았습니다. 공은 마치 우주 공간에서 날아가듯, 한 방향으로 영원히 직진했습니다.
그런데 현실에서 농구공을 던지면 어떻게 되나요?
- 처음에는 위로 올라가다가...
- 점점 느려지면서...
- 꼭대기에서 잠깐 멈췄다가...
- 아래로 점점 빨라지면서 떨어집니다
이 모든 현상의 원인은 딱 하나, 중력이 속도를 매 순간 바꾸고 있기 때문입니다.
놀라운 사실을 알려드릴게요. 이 복잡해 보이는 현상을 코드 딱 한 줄을 추가하는 것만으로 재현할 수 있습니다!
📚 핵심 개념 1: 가속도(Acceleration)란?¶
🎢 일상 비유: 자동차의 가속 페달¶
자동차를 생각해보세요.
| 상황 | 속도 변화 | 가속도 |
|---|---|---|
| 가속 페달을 밟는다 | 속도가 점점 빨라진다 | 양(+)의 가속도 |
| 브레이크를 밟는다 | 속도가 점점 느려진다 | 음(-)의 가속도 |
| 크루즈 컨트롤 (일정 속도) | 속도가 변하지 않는다 | 가속도 = 0 |
가속도는 "속도가 얼마나 빠르게 변하는지"를 나타내는 값입니다.
- 속도(velocity): 위치가 시간에 따라 변하는 비율 →
위치 변화량 / 시간 - 가속도(acceleration): 속도가 시간에 따라 변하는 비율 →
속도 변화량 / 시간
🍎 중력 가속도: 지구가 당기는 힘¶
지구 위의 모든 물체는 아래 방향으로 초당 9.8 m/s씩 속도가 증가합니다. 이것이 바로 중력 가속도 g = 9.8 m/s²입니다.
| 시간 (초) | 속도 (m/s) | 설명 |
|---|---|---|
| 0 | 0 | 가만히 놓은 순간 |
| 1 | 9.8 | 1초 후 |
| 2 | 19.6 | 2초 후 |
| 3 | 29.4 | 3초 후 |
매 초마다 속도가 9.8씩 증가합니다! 이것이 "가속"입니다.
🖥️ 코드로 표현하면?¶
5차시의 등속 운동 패턴을 기억해보세요:
여기에 가속도를 추가하면:
순서가 중요합니다! 먼저 속도를 갱신하고, 갱신된 속도로 위치를 갱신합니다.
아래 다이어그램은 등속 운동과 가속 운동의 루프 차이를 보여줍니다:
위 다이어그램에서 주황색 ① 속도 갱신 단계가 5차시에는 없었던 새로운 한 줄입니다. 이 한 줄이 등속 운동을 가속 운동으로 바꿔줍니다!
📚 핵심 개념 2: VPython에서 중력 벡터 정의하기¶
중력은 아래 방향으로 작용합니다. VPython에서 y축이 위아래이므로:
| 성분 | 값 | 의미 |
|---|---|---|
| x | 0 | 좌우로는 힘이 없음 |
| y | -9.8 | 아래 방향으로 9.8 m/s² |
| z | 0 | 앞뒤로는 힘이 없음 |
마이너스(-) 인 이유는 VPython에서 y축 위쪽이 +, 아래쪽이 -이기 때문입니다. 중력은 아래로 당기니까 -9.8이 됩니다.
💻 실습: 포물선 운동 시뮬레이션 만들기¶
실행 환경: VPython 3.2 (GlowScript 또는 로컬 vpython 패키지)
🏗️ v1: 자유낙하 — 공을 높은 곳에서 놓아보기¶
가장 간단한 가속 운동부터 시작합시다. 공을 높은 곳에 놓으면 중력에 의해 아래로 떨어지는 자유낙하입니다.
from vpython import *
# 장면 설정
scene = canvas(title="v1: 자유낙하", width=600, height=400)
# 바닥
ground = box(pos=vector(0, -0.05, 0), size=vector(20, 0.1, 5), color=color.green)
# 공: 높은 곳(y=10)에서 시작
ball = sphere(pos=vector(0, 10, 0), radius=0.5, color=color.red)
# 초기 속도: 정지 상태에서 출발
velocity = vector(0, 0, 0)
# 중력 가속도 벡터 # <- 여기가 [가속도 벡터 정의]
gravity = vector(0, -9.8, 0)
dt = 0.01 # 시간 간격
while ball.pos.y >= ball.radius: # 바닥에 닿을 때까지
rate(100) # 초당 100프레임
velocity = velocity + gravity * dt # <- 여기가 [속도 갱신]
ball.pos = ball.pos + velocity * dt # <- 여기가 [위치 갱신]
실행 결과: 빨간 공이 높이 10m에서 시작해 점점 빨라지면서 아래로 떨어집니다. 바닥(y=0 근처)에 닿으면 멈춥니다.
🔍 코드-개념 매핑¶
- 7번째 줄
gravity = vector(0, -9.8, 0)— 이것이 바로 중력 가속도 벡터입니다. y 방향으로 -9.8을 넣어 "아래로 당기는 힘"을 표현합니다. - 12번째 줄
velocity = velocity + gravity * dt— 이것이 바로 속도 갱신 패턴입니다. 매 프레임마다 중력이 속도를 조금씩 바꿉니다.gravity * dt는 아주 짧은 시간(0.01초) 동안 속도가 변하는 양입니다. - 13번째 줄
ball.pos = ball.pos + velocity * dt— 5차시에서 배운 위치 갱신 패턴과 동일합니다. 다만 이제velocity가 매번 바뀌므로 공이 가속됩니다! - 10번째 줄
while ball.pos.y >= ball.radius— 공의 중심이 반지름만큼 내려오면 바닥에 닿은 것으로 판단합니다. 이것이 바닥 충돌 조건입니다.
💡 핵심 포인트: 5차시 등속 운동 코드와 비교하면, 정말로 한 줄(
velocity = velocity + gravity * dt)만 추가되었습니다. 이 한 줄이 직선 운동을 가속 운동으로 바꿉니다!
🏗️ v2: 포물선 운동 — 비스듬히 던지기¶
자유낙하는 직선이었습니다. 이제 공에 비스듬한 초기 속도를 주어서 포물선을 만들어봅시다!
v1에서 바뀐 부분: 초기 속도를 vector(0, 0, 0) → vector(5, 15, 0)으로 변경했습니다. 오른쪽으로 5 m/s, 위쪽으로 15 m/s의 속도로 던지는 것입니다.
from vpython import *
# 장면 설정
scene = canvas(title="v2: 포물선 운동", width=700, height=400)
scene.camera.pos = vector(8, 5, 15) # 카메라 위치 조정
# 바닥
ground = box(pos=vector(8, -0.05, 0), size=vector(25, 0.1, 5), color=color.green)
# 공: 왼쪽 아래에서 시작
ball = sphere(pos=vector(0, 0.5, 0), radius=0.3, color=color.red)
# ✨ 비스듬한 초기 속도: 오른쪽(+x) + 위쪽(+y) # <- 여기가 [초기 속도]
velocity = vector(5, 15, 0)
# 중력 가속도
gravity = vector(0, -9.8, 0)
dt = 0.01
while ball.pos.y >= ball.radius:
rate(100)
velocity = velocity + gravity * dt # 속도 갱신: 중력이 매 프레임 속도를 바꿈
ball.pos = ball.pos + velocity * dt # 위치 갱신: 바뀐 속도로 이동
실행 결과: 공이 왼쪽 아래에서 출발하여 오른쪽 위로 올라갔다가, 꼭대기에서 잠시 느려지고, 다시 아래로 떨어지며 아름다운 포물선을 그립니다! 🎉
왜 포물선이 될까요?¶
| 방향 | 속도 변화 | 이유 |
|---|---|---|
| x(가로) | 변하지 않음 (계속 5 m/s) | 중력의 x 성분이 0이므로 |
| y(세로) | 계속 줄어듦 (15 → 0 → -15...) | 중력이 y 방향으로 -9.8씩 감소시킴 |
가로는 등속, 세로는 가속 → 이 두 운동이 합쳐져서 포물선이 됩니다!
🐛 에러 경험: 순서를 바꾸면 어떻게 될까?¶
여기서 잠깐! 다음 코드를 한번 살펴보세요. 뭔가 이상한 점이 있습니다.
from vpython import *
scene = canvas(title="에러 체험: 순서 실수", width=700, height=400)
ground = box(pos=vector(8, -0.05, 0), size=vector(25, 0.1, 5), color=color.green)
ball = sphere(pos=vector(0, 0.5, 0), radius=0.3, color=color.red)
velocity = vector(5, 15, 0)
gravity = vector(0, -9.8, 0)
dt = 0.01
while ball.pos.y >= ball.radius:
rate(100)
# ⚠️ 위치를 먼저 갱신하고, 속도를 나중에 갱신했습니다!
ball.pos = ball.pos + velocity * dt # 위치 먼저!
velocity = velocity + gravity * dt # 속도 나중에!
🤔 질문: 이 코드를 실행하면 에러가 날까요?
답: 에러는 나지 않습니다! 하지만 결과가 미묘하게 달라집니다.
| 정상 순서 (v2) | 잘못된 순서 (위 코드) |
|---|---|
| 속도 먼저 갱신 → 위치 갱신 | 위치 먼저 갱신 → 속도 갱신 |
| 이번 프레임의 새 속도로 이동 | 이전 프레임의 옛 속도로 이동 |
| 더 정확한 시뮬레이션 | 약간의 오차가 누적됨 |
dt가 0.01처럼 작으면 눈으로는 차이를 거의 못 느끼지만, dt를 0.1이나 0.5로 크게 하면 궤적 차이가 눈에 보입니다. 물리 시뮬레이션에서는 순서가 중요합니다!
✅ 기억하세요: 항상 속도 먼저, 위치 나중에!
🏗️ v3: 궤적 남기기 + 바닥 충돌 완성¶
포물선이 만들어지지만, 공이 지나간 자리가 보이지 않으니 아쉽습니다. 궤적(trail) 을 남겨서 포물선을 눈으로 확인해봅시다!
v2에서 바뀐 부분:
1. make_trail=True 옵션 추가 → 공이 지나간 경로를 선으로 표시
2. trail_color, trail_radius 추가 → 궤적을 예쁘게 꾸미기
3. while 조건 개선 → 바닥 충돌 후 공을 정확히 멈추기
4. 시작/착지 표시 추가
from vpython import *
# 장면 설정
scene = canvas(title="v3: 포물선 궤적 시각화", width=700, height=450)
scene.camera.pos = vector(8, 6, 18)
# 바닥
ground = box(pos=vector(8, -0.05, 0), size=vector(25, 0.1, 5), color=color.green)
# 공: make_trail로 궤적을 남김 # <- 여기가 [궤적 시각화]
ball = sphere(
pos=vector(0, 0.5, 0),
radius=0.3,
color=color.red,
make_trail=True, # 궤적 남기기 ON
trail_color=color.yellow, # 궤적 색상
trail_radius=0.05 # 궤적 선 두께
)
# 시작점 표시
sphere(pos=vector(0, 0.5, 0), radius=0.15, color=color.cyan)
# 초기 속도와 중력
velocity = vector(5, 15, 0)
gravity = vector(0, -9.8, 0)
dt = 0.01
# 시뮬레이션 루프
while ball.pos.y >= ball.radius: # <- 여기가 [바닥 충돌 조건]
rate(100)
velocity = velocity + gravity * dt # ① 속도 갱신
ball.pos = ball.pos + velocity * dt # ② 위치 갱신
# 바닥에 닿으면 정확한 위치에 멈추기
ball.pos.y = ball.radius # 공이 바닥에 살짝 얹힌 상태
# 착지점 표시
sphere(pos=ball.pos, radius=0.15, color=color.orange)
# 비행 거리 출력
print("착지 x 좌표:", round(ball.pos.x, 2), "m")
실행 결과: 빨간 공이 날아가면서 노란색 포물선 궤적이 화면에 남습니다. 시작점(하늘색)과 착지점(주황색)이 표시되어 비행 거리를 한눈에 볼 수 있습니다!
🔍 v3 코드-개념 매핑¶
- 11~17번째 줄
make_trail=True—sphere를 만들 때 이 옵션을 켜면, 공이 이동한 경로를 자동으로 선으로 그려줍니다. 이것이 궤적 시각화 기능입니다. - 29번째 줄
while ball.pos.y >= ball.radius— 공의 중심 y좌표가 반지름 이하가 되면 반복을 멈춥니다. 이것이 바닥 충돌 판정입니다. - 35번째 줄
ball.pos.y = ball.radius— 루프가 끝난 후 공의 y좌표를 정확히 반지름 높이로 맞춰서, 공이 바닥을 뚫고 내려가지 않게 합니다.
🎉 여기까지가 포물선 시뮬레이션의 핵심입니다! 5차시 등속 운동 코드에서 실질적으로 추가된 것은
gravity정의와velocity += gravity * dt한 줄뿐입니다.
🏗️ 최종 완성: 발사 각도 입력 + 다중 궤적 비교¶
마지막으로, 발사 각도와 속력을 입력받아 여러 궤적을 한 화면에 비교하는 완성 버전입니다.
v3에서 바뀐 부분:
1. math.cos, math.sin으로 각도 → 속도 벡터 변환
2. 함수(launch_ball)로 분리하여 재사용 가능
3. 여러 각도를 반복문