10차시: 나만의 3D 시뮬레이션 완성 - 미니 프로젝트 설계·코딩·공유¶
🎯 핵심 주제 카드¶
🧠 프로젝트 설계 방법론¶
큰 프로그램을 작은 단계로 쪼개어 하나씩 완성하는 전략
💻 기능 통합 코딩¶
객체·애니메이션·벡터·입력·리스트·충돌을 하나의 프로그램으로 결합
💬 피어 리뷰¶
짝의 작품을 실행하고 건설적 피드백을 주고받는 활동
🚀 확장 방향 탐색¶
나만의 다음 프로젝트를 구체화하는 자기 가이드 질문
⏱️ 수업 흐름¶
1단계: 🗺️ 프로젝트 선택 & 설계 (8분)¶
3가지 프로젝트 옵션을 살펴보고, 자신의 수준과 관심에 맞는 것을 선택합니다. 기능 목록과 설계 체크리스트를 작성합니다.
2단계: 🦴 뼈대 코드 작성 (7분)¶
선택한 프로젝트의 v1 — 화면에 기본 객체만 나타나는 가장 단순한 버전을 완성합니다.
3단계: 🔧 기능 추가 & 디버깅 (20분)¶
v2(움직임) → v3(상호작용) → v4(꾸미기) 순서로 기능을 하나씩 붙여 나갑니다. 막힐 때는 분기 흐름도를 참고합니다.
4단계: 🤝 짝 공유 & 피어 리뷰 (10분)¶
옆 친구와 코드를 교환하여 실행해 보고, 피드백 카드를 작성합니다.
5단계: 💭 성찰 & 다음 방향 탐색 (5분)¶
자기점검 체크리스트를 완성하고, 이후 개인 프로젝트의 주제와 방향을 가이드 질문으로 탐색합니다.
📚 핵심 개념 1: 프로젝트 설계 방법론 — 큰 것을 작게 쪼개기¶
🏗️ 비유: 레고 조립 설명서¶
여러분이 레고 세트를 살 때, 설명서에는 한 번에 완성된 모습이 아니라 단계별 조립 순서가 나와 있습니다. 1단계에서 바닥판을 만들고, 2단계에서 벽을 세우고, 3단계에서 지붕을 올리죠. 프로그래밍 프로젝트도 똑같습니다!
프로젝트 설계 방법론이란?
완성하고 싶은 프로그램을 작은 기능 단위로 나누고, 가장 기본적인 것부터 하나씩 완성해 가는 전략입니다.
왜 한 번에 다 쓰면 안 될까요?¶
| 한 번에 전체 코드 작성 | 단계별 빌드업 |
|---|---|
| 에러가 나면 어디가 문제인지 모름 😵 | 에러가 나면 방금 추가한 부분이 문제! 🎯 |
| 50줄 코드를 디버깅 → 30분 낭비 | 5줄 코드를 디버깅 → 2분 해결 |
| 완성까지 아무것도 안 보임 | 매 단계마다 뭔가 돌아감 → 동기 부여 💪 |
오늘 사용할 4단계 빌드업 프로세스¶
프로젝트 완성까지의 단계별 흐름입니다:
각 단계를 완성할 때마다 반드시 실행해서 확인합니다. "돌아가는 코드"를 유지하면서 기능을 추가하는 것이 핵심입니다!
📚 핵심 개념 2: 기능 통합 — 1~9차시 지식 총정리¶
지금까지 배운 VPython 기능을 한 장의 표로 정리해 봅시다. 이 표가 오늘 프로젝트의 재료 목록이 됩니다.
| 차시 | 배운 기능 | 핵심 코드 예시 | 오늘 프로젝트에서의 역할 |
|---|---|---|---|
| 1~2 | 3D 객체 생성 | sphere(pos=..., color=...) |
캐릭터·장애물 만들기 |
| 3 | 애니메이션 루프 | while True: rate(60) |
프레임마다 위치 업데이트 |
| 4 | 벡터와 물리 | vel = vector(...), pos += vel*dt |
속도·가속도 계산 |
| 5 | 키보드 입력 | scene.waitfor('keydown') / keysdown() |
사용자 조작 |
| 6 | 리스트 관리 | obstacles = [box(...) for i in range(5)] |
여러 객체 일괄 관리 |
| 7 | 충돌 감지 | mag(a.pos - b.pos) < r |
게임오버·점수 판정 |
| 8 | 궤적·라벨 | attach_trail(...), label(...) |
시각적 효과·정보 표시 |
| 9 | 함수 분리 | def create_enemy(): ... |
코드 정리·재사용 |
💡 핵심 포인트: 오늘은 새로운 문법을 배우는 것이 아닙니다! 이미 알고 있는 재료들을 조합하는 능력을 기르는 것이 목표입니다.
🗺️ 1단계: 프로젝트 선택 & 설계 (8분)¶
3가지 프로젝트 옵션¶
자신의 수준과 관심에 맞는 프로젝트를 하나 선택하세요!
| 옵션 A 🎯 | 옵션 B 🎮 | 옵션 C 🌟 | |
|---|---|---|---|
| 제목 | 포물선 궤적 시뮬레이션 | 키보드 피하기 게임 | 자유 주제 |
| 설명 | 공을 발사하면 포물선을 그리며 날아가고, 궤적이 남으며, 바닥에 닿으면 튕기는 시뮬레이션 | 키보드로 캐릭터를 조종하여 위에서 떨어지는 장애물을 피하는 게임 | 나만의 아이디어로 시뮬레이션 또는 게임 제작 |
| 추천 대상 | 물리에 관심 있는 학생 | 게임 만들기에 관심 있는 학생 | 도전 정신이 강한 학생 |
| 핵심 기능 | 벡터, 중력, 궤적, 라벨 | 키보드 입력, 리스트, 충돌, 점수 | 최소 3가지 이상 기능 조합 |
| 난이도 | ●●●○○ | ●●●●○ | ●●●●● |
📋 설계 체크리스트 — 코딩 전에 먼저 작성하세요!¶
종이나 메모장에 아래 항목을 채워 보세요 (2분이면 됩니다):
- 내가 선택한 옵션: A / B / C
- 필요한 3D 객체 목록: (예: 공 1개, 바닥 1개, 장애물 5개)
- 움직임 규칙: (예: 공은 중력으로 떨어지고, 장애물은 위에서 내려옴)
- 사용자 조작: (예: 좌우 화살표로 이동, 스페이스바로 발사)
- 종료 조건: (예: 바닥에 닿으면 멈춤, 장애물에 맞으면 게임오버)
🎯 이 체크리스트가 바로 여러분의 설계도입니다! 건물 짓기 전에 설계도를 그리듯, 코딩 전에 이것부터 정리하는 습관이 중요합니다.
🦴 2단계: 뼈대 코드 작성 (7분)¶
선택한 옵션에 따라 v1 코드를 작성합니다. 가장 기본적인 것 — 화면에 객체가 보이기만 하면 성공입니다!
옵션 A: 포물선 궤적 시뮬레이션 — v1 (뼈대)¶
실행 환경: VPython 3.2 (GlowScript 또는 로컬 설치)
from vpython import *
# v1: 기본 객체만 표시 — 아직 아무것도 움직이지 않습니다
scene.title = "포물선 궤적 시뮬레이션"
scene.background = color.white
# 바닥
ground = box(
pos=vector(0, -0.5, 0),
size=vector(20, 0.1, 5),
color=color.green
)
# 발사할 공
ball = sphere(
pos=vector(-8, 0, 0), # 왼쪽에서 시작
radius=0.3,
color=color.red,
make_trail=True # <- 여기가 궤적 기능입니다
)
# 발사 속도 (아직 사용 안 함 — v2에서 사용)
velocity = vector(5, 8, 0)
실행하면 초록색 바닥 위에 빨간 공이 보입니다. 아직 움직이지 않지만, 이것만으로도 v1 완성입니다! 🎉
위 코드의 5번째 줄 scene.background = color.white가 바로 장면 설정입니다. 16번째 줄 make_trail=True가 바로 8차시에서 배운 궤적 기능입니다.
옵션 B: 키보드 피하기 게임 — v1 (뼈대)¶
from vpython import *
# v1: 기본 객체만 표시 — 아직 움직이지 않습니다
scene.title = "피하기 게임"
scene.width = 600
scene.height = 400
# 플레이어 (키보드로 조종할 캐릭터)
player = sphere(
pos=vector(0, -4, 0), # 화면 아래쪽에 위치
radius=0.4,
color=color.cyan
)
# 장애물 리스트 — 6차시에서 배운 리스트 컴프리헨션!
from random import uniform
obstacles = []
for i in range(5):
obs = box(
pos=vector(uniform(-5, 5), 6 + i * 2, 0), # 화면 위쪽에 랜덤 배치
size=vector(0.8, 0.8, 0.8),
color=color.red
)
obstacles.append(obs)
# 바닥 라인 (시각적 경계)
floor_line = box(
pos=vector(0, -5, 0),
size=vector(12, 0.1, 0.5),
color=color.white
)
실행하면 아래쪽에 파란 공(플레이어), 위쪽에 빨간 박스 5개(장애물)가 보입니다. v1 완성! 🎮
위 코드의 17~24번째 줄이 바로 6차시에서 배운 리스트로 여러 객체 관리하기입니다.
옵션 C: 자유 주제 — v1 가이드¶
자유 주제를 선택한 학생은 아래 템플릿에서 시작하세요:
from vpython import *
# v1: 자유 주제 뼈대
scene.title = "나의 시뮬레이션 제목"
scene.background = vector(0.1, 0.1, 0.2) # 어두운 배경
# TODO: 여기에 최소 2개의 3D 객체를 만드세요
# 예: 주인공, 배경, 목표물 등
⚠️ 자유 주제 학생 주의사항: 50분 안에 완성해야 하므로, 아이디어를 최대한 단순하게 시작하세요. "태양계 시뮬레이션을 완벽하게!" 보다 "공 2개가 서로 끌어당기는 것"이 현실적입니다.
🔧 3단계: 기능 추가 & 디버깅 (20분)¶
이제 본격적으로 기능을 붙여 나갑니다! 한 가지 기능을 추가할 때마다 실행해서 확인하는 것, 잊지 마세요.
옵션 A 계속: 포물선 시뮬레이션 — v2 (움직임 추가)¶
v1 코드에서 아래쪽에 애니메이션 루프를 추가합니다:
from vpython import *
scene.title = "포물선 궤적 시뮬레이션"
scene.background = color.white
ground = box(pos=vector(0, -0.5, 0), size=vector(20, 0.1, 5), color=color.green)
ball = sphere(pos=vector(-8, 0, 0), radius=0.3, color=color.red, make_trail=True)
# === v2에서 추가된 부분 시작 ===
velocity = vector(5, 8, 0) # 초기 발사 속도
gravity = vector(0, -9.8, 0) # 중력 가속도 <- 여기가 물리 법칙!
dt = 0.01 # 시간 간격
while True:
rate(100) # 초당 100프레임
# 속도에 중력을 더함 (가속도 -> 속도 변화)
velocity = velocity + gravity * dt # <- 여기가 뉴턴 제2법칙!
# 위치에 속도를 더함 (속도 -> 위치 변화)
ball.pos = ball.pos + velocity * dt # <- 여기가 운동 방정식!
# 바닥에 닿으면 멈춤
if ball.pos.y < 0:
velocity = vector(0, 0, 0) # 정지
# === v2에서 추가된 부분 끝 ===
v1에서 뭐가 바뀌었나요?
- 10~11번째 줄: velocity와 gravity 벡터를 정의했습니다
- 14~25번째 줄: while True 애니메이션 루프가 추가되었습니다
- 18번째 줄 velocity = velocity + gravity * dt가 바로 4차시에서 배운 벡터 연산으로 물리 법칙 구현하기입니다
실행하면 공이 포물선을 그리며 날아가다가 바닥에서 멈춥니다. 빨간 궤적이 남아 있는 것도 확인해 보세요!
🐛 에러 경험: 이 코드를 실행하면?¶
잠깐! 한 학생이 v2를 작성하다가 이렇게 썼습니다. 어떤 에러가 날까요?
from vpython import *
scene.title = "포물선 궤적 시뮬레이션"
ground = box(pos=vector(0, -0.5, 0), size=vector(20, 0.1, 5), color=color.green)
ball = sphere(pos=vector(-8, 0, 0), radius=0.3, color=color.red, make_trail=True)
velocity = vector(5, 8, 0)
gravity = vector(0, -9.8, 0)
dt = 0.01
while True:
rate(100)
velocity = velocity + gravity * dt
ball.pos = ball.pos + velocity * dt
if ball.y < 0: # <- 여기가 문제!
velocity = vector(0, 0, 0)
원인 분석: VPython에서 객체의 y좌표에 접근할 때는 ball.y가 아니라 ball.pos.y라고 써야 합니다. ball.pos가 벡터이고, 그 벡터의 .y 성분을 가져와야 하기 때문입니다.
수정 코드: 16번째 줄을 이렇게 고치면 됩니다:
💡 이 에러는 VPython을 처음 쓰는 사람이 가장 많이 만나는 실수입니다. 기억하세요: 위치는 항상
.pos.x,.pos.y,.pos.z로 접근합니다!
옵션 A 계속: v3 (바운스 & 라벨 추가)¶
v2에서 바닥에 닿으면 그냥 멈췄는데, 이제 튕기게 만들고 최대 높이를 표시합니다:
from vpython import *
scene.title = "포물선 궤적 시뮬레이션 v3"
scene.background = color.white
ground = box(pos=vector(0, -0.5, 0), size=vector(20, 0.1, 5), color=color.green)
ball = sphere(pos=vector(-8, 0, 0), radius=0.3, color=color.red, make_trail=True)
velocity = vector(5, 8, 0)
gravity = vector(0, -9.8, 0)
dt = 0.01
# === v3에서 추가: 최대 높이 추적 & 라벨 ===
max_height = 0
info_label = label(
pos=vector(0, 6, 0),
text="최대 높이: 0.0 m",
height=16,
color=color.black,
box=False
)
bounce_count = 0 # 튕긴 횟수
while True:
rate(100)
velocity = velocity + gravity * dt
ball.pos = ball.pos + velocity * dt
# 최대 높이 갱신 <- 여기가 리스트 없이 최댓값 추적하는 패턴
if ball.pos.y > max_height:
max_height = ball.pos.y
info_label.text = f"최대 높이: {max_height:.1f} m | 바운스: {bounce_count}회"
# === v3에서 변경: 멈춤 → 바운스 ===
if ball.pos.y < 0 and velocity.y < 0: # 바닥 아래 + 내려가는 중일 때만
velocity.y = -velocity.y * 0.7 # y속도 반전 + 에너지 손실(0.7배)
bounce_count += 1
# 거의 멈추면 종료
if bounce_count > 5 and mag(velocity) < 0.5:
info_label.text += " [완료!]"
break
v2에서 뭐가 바뀌었나요?
- 14~22번째 줄: max_height 변수와 info_label(라벨)이 추가되었습니다 — 8차시에서 배운 기능!
- 36번째 줄: velocity.y = -velocity.y * 0.7 — 바닥에서 튕기면서 에너지를 잃는 물리 현상을 표현합니다
- 35번째 줄의 velocity.y < 0 조건이 중요합니다: 이미 올라가는 중인데 또 반전하면 바닥을 뚫고 내려가는 버그가 생기거든요!