8차시: 객체가 많아지면? - 리스트로 여러 3D 객체 한꺼번에 다루기¶
🎯 핵심 주제 카드¶
🧠 리스트로 객체 관리¶
for 루프 한 번이면 3D 객체 100개도 뚝딱! 리스트에 담아서 한꺼번에 다루는 패턴을 익힙니다.
💻 사용자 정의 속성¶
ball.velocity = vector(...) — 각 객체에 나만의 데이터를 붙이는 테크닉으로 개별 움직임을 구현합니다.
💬 for-in-리스트 업데이트¶
for ball in balls: 패턴으로 while 루프 안에서 모든 객체를 동시에 움직이는 핵심 구조를 완성합니다.
🚀 랜덤 색상 · 속도¶
random 모듈과 결합해 각 객체를 개성 있게 만들어 시각적으로 풍성한 장면을 연출합니다.
⏱️ 수업 흐름¶
1단계: 문제 인식 — 변수 10개의 고통 (5분)¶
변수를 하나하나 만들어 공 10개를 생성하는 "나쁜 코드"를 직접 보고, 왜 리스트가 필요한지 체감합니다.
2단계: 핵심 개념 — 리스트 + for 루프로 객체 생성 (10분)¶
리스트에 VPython 객체를 담는 방법과 사용자 정의 속성(.velocity) 개념을 배웁니다.
3단계: 따라하기 실습 — 공 10개 동시에 움직이기 (20분)¶
v1(리스트 생성) → v2(속성 추가) → v3(while 루프에서 업데이트) → v4(벽 반사) 순서로 코드를 점진적으로 완성합니다.
4단계: 에러 경험 & 연습 문제 (10분)¶
흔히 발생하는 에러를 직접 만나보고, 3단계 연습 문제로 응용력을 키웁니다.
5단계: 성찰 & 평가 (5분)¶
오늘 배운 패턴을 정리하고, 다음 차시 충돌 감지와의 연결 고리를 확인합니다.
📚 1단계: 문제 인식 — 변수 10개의 고통 😫¶
변수를 하나하나 만들면 어떻게 될까요?¶
여러분이 학교 운동장에서 축구공 10개를 동시에 굴린다고 상상해 보세요. 공마다 이름표를 붙여야 한다면 — "공1", "공2", "공3" … "공10" — 이름 붙이는 것만으로도 지칩니다. 그런데 공이 100개라면요? 😱
프로그래밍에서도 똑같습니다. 아래 코드를 한번 보세요.
from vpython import *
# 공 10개를 각각 변수에 담는 "나쁜 코드" 😰
ball0 = sphere(pos=vector(-4, 0, 0), radius=0.3, color=color.red)
ball1 = sphere(pos=vector(-3, 0, 0), radius=0.3, color=color.blue)
ball2 = sphere(pos=vector(-2, 0, 0), radius=0.3, color=color.green)
ball3 = sphere(pos=vector(-1, 0, 0), radius=0.3, color=color.yellow)
ball4 = sphere(pos=vector(0, 0, 0), radius=0.3, color=color.orange)
ball5 = sphere(pos=vector(1, 0, 0), radius=0.3, color=color.cyan)
ball6 = sphere(pos=vector(2, 0, 0), radius=0.3, color=color.magenta)
ball7 = sphere(pos=vector(3, 0, 0), radius=0.3, color=color.white)
ball8 = sphere(pos=vector(4, 0, 0), radius=0.3, color=color.red)
ball9 = sphere(pos=vector(5, 0, 0), radius=0.3, color=color.blue)
# 이제 각 공을 움직이려면...
ball0.pos.x += 0.01
ball1.pos.x += 0.01
ball2.pos.x += 0.01
# ... 이것을 10번 반복? 100개면 100번?! 😵
💡 실행 결과: 공 10개가 일렬로 나타나지만, 움직이는 코드를 작성하려면 같은 줄을 10번씩 복사해야 합니다.
이 방식의 문제를 정리하면:
| 문제점 | 설명 |
|---|---|
| 코드 중복 | 거의 같은 줄을 계속 복사-붙여넣기 |
| 수정 어려움 | 색상을 바꾸려면 10줄을 다 고쳐야 함 |
| 확장 불가 | 100개로 늘리려면 90줄을 추가해야 함 |
| 실수 위험 | ball7을 ball8로 오타 내면 찾기 어려움 |
🎯 핵심 깨달음: "같은 종류의 것이 여러 개"일 때는 리스트에 담고 반복문으로 다루는 것이 정답입니다!
📚 2단계: 핵심 개념 — 리스트 + 객체 + 사용자 정의 속성¶
🧠 개념 1: 리스트에 3D 객체 담기¶
여러분은 이미 파이썬에서 리스트를 배웠습니다:
리스트에는 숫자뿐 아니라 뭐든지 담을 수 있습니다. VPython의 sphere 객체도 마찬가지입니다!
마치 축구팀 감독이 선수 명단(리스트)을 가지고 있으면, "전원 앞으로 이동!" 한마디로 모든 선수를 움직일 수 있는 것과 같습니다. 변수를 하나하나 부르는 대신, 리스트 이름 하나로 전체를 제어하는 것이죠.
리스트로 객체를 관리하는 핵심 구조:
리스트 기반 객체 관리 흐름도
🧠 개념 2: 사용자 정의 속성 — 객체에 나만의 데이터 붙이기¶
VPython의 sphere 객체에는 기본적으로 pos, radius, color 같은 속성이 있습니다. 그런데 놀라운 점은 — 원하는 속성을 마음대로 추가할 수 있다는 것입니다!
ball = sphere(pos=vector(0,0,0), radius=0.3, color=color.red)
ball.velocity = vector(1, 2, 0) # 내가 만든 속성!
ball.mass = 5.0 # 이것도 내가 만든 속성!
이것은 마치 학생증에 기본 정보(이름, 학번)가 있는데, 뒷면에 메모를 적어 붙이는 것과 같습니다. "이 학생은 달리기가 빠르다"라고 메모를 붙이면 나중에 참고할 수 있는 것처럼, 객체에 .velocity를 붙이면 나중에 ball.velocity로 꺼내 쓸 수 있습니다.
⚠️ 주의:
.velocity는 VPython이 원래 알고 있는 속성이 아닙니다! 파이썬이 동적으로 속성을 추가할 수 있기 때문에 가능한 것입니다. 이름은 자유롭게 정할 수 있어요 (.vel,.speed,.my_data등).
기본 속성 vs 사용자 정의 속성 비교:
| 구분 | 기본 속성 | 사용자 정의 속성 |
|---|---|---|
| 예시 | ball.pos, ball.radius, ball.color |
ball.velocity, ball.mass, ball.score |
| 누가 만듦? | VPython이 자동 생성 | 프로그래머가 직접 추가 |
| 화면 반영 | pos 변경 시 객체가 이동 | 화면에 직접 영향 없음 (코드로 연결해야 함) |
| 용도 | 객체의 시각적 상태 | 객체의 물리적/논리적 데이터 저장 |
📚 3단계: 따라하기 실습 — 공 10개 동시에 움직이기 🏀¶
실행 환경: VPython 3.2 (GlowScript 또는 로컬 설치)
✅ v1: 리스트로 공 10개 한 번에 생성하기¶
먼저 가장 기본적인 것부터 — for 루프로 공 10개를 만들어 봅시다!
from vpython import *
# 빈 리스트 준비 — 여기에 공들을 담을 것입니다
balls = [] # <- 여기가 [리스트 초기화]
# for 루프로 공 10개 생성
for i in range(10): # <- 여기가 [반복 생성 패턴]
ball = sphere(
pos=vector(-4 + i, 0, 0), # i를 활용해 위치를 다르게!
radius=0.3,
color=color.red
)
balls.append(ball) # <- 여기가 [리스트에 객체 추가]
# 확인: 리스트에 몇 개가 담겼는지 출력
print("공의 개수:", len(balls))
🖥️ 화면 결과: 빨간 공 10개가 x = -4부터 x = 5까지 일렬로 나타납니다.
개념-코드 매핑:
- 1번째 줄의
balls = []가 바로 빈 리스트 초기화입니다. 공을 담을 빈 바구니를 준비한 것이죠. - 4번째 줄의
for i in range(10):이 바로 반복 생성 패턴입니다. i가 0, 1, 2, ..., 9로 변하면서 10번 반복합니다. - 5번째 줄의
pos=vector(-4 + i, 0, 0)에서 i를 좌표에 활용하여 공마다 서로 다른 위치를 만듭니다. - 9번째 줄의
balls.append(ball)이 바로 리스트에 객체 추가입니다. 공을 만들 때마다 바구니에 넣는 동작이에요.
✅ v2: 각 공에 랜덤 색상과 속도 부여하기¶
v1에서는 공이 전부 빨간색이고 움직이지도 않았습니다. 이제 사용자 정의 속성과 random 모듈을 추가합니다!
v1에서 바뀐 점: import random 추가, 색상을 랜덤으로, .velocity 사용자 정의 속성 추가
from vpython import *
import random # <- 새로 추가! 랜덤 값 생성을 위해
balls = []
for i in range(10):
ball = sphere(
pos=vector(-4 + i, 0, 0),
radius=0.3,
# 랜덤 색상: RGB 각각 0~1 사이 랜덤 값
color=vector(random.random(), random.random(), random.random()) # <- 변경!
)
# 사용자 정의 속성으로 속도 부여 — 각 공이 자기만의 속도를 가짐
ball.velocity = vector(
random.uniform(-3, 3), # x 방향: -3 ~ 3 사이 랜덤
random.uniform(-3, 3), # y 방향: -3 ~ 3 사이 랜덤
0 # z 방향: 0 (2D 평면에서 움직이게)
) # <- 여기가 [사용자 정의 속성]
balls.append(ball)
# 첫 번째 공의 속도를 확인해 봅시다
print("첫 번째 공의 속도:", balls[0].velocity)
print("세 번째 공의 속도:", balls[2].velocity)
🖥️ 화면 결과: 알록달록한 공 10개가 일렬로 나타납니다. 아직 움직이진 않습니다.
개념-코드 매핑:
- 10번째 줄
color=vector(random.random(), ...)— VPython에서 색상은vector(R, G, B)로 표현합니다. 각 값이 0~1 사이이므로random.random()이 딱 맞습니다. - 14~18번째 줄
ball.velocity = vector(...)— 이것이 바로 사용자 정의 속성입니다! VPython의 sphere에는 원래.velocity가 없지만, 파이썬이 동적으로 추가해 줍니다.
🚨 에러 경험: 흔한 실수를 만나봅시다!¶
아래 코드를 실행하면 어떤 에러가 날까요? 🤔
from vpython import *
import random
balls = []
for i in range(10):
ball = sphere(
pos=vector(-4 + i, 0, 0),
radius=0.3,
color=vector(random.random(), random.random(), random.random())
)
ball.velocity = vector(random.uniform(-3, 3), random.uniform(-3, 3), 0)
balls.append(ball)
# 실수! 리스트 전체에 .velocity를 호출하려고 함
print(balls.velocity)
에러 메시지:
원인 분석:
balls는 리스트입니다. 리스트 자체에는 .velocity라는 속성이 없어요! .velocity는 리스트 안에 들어있는 각각의 sphere 객체에 붙어 있습니다.
비유하자면: 축구팀 선수 명단(리스트)에게 "네 등번호 뭐야?"라고 물어본 것과 같습니다. 명단 자체는 등번호가 없고, 명단 안의 각 선수에게 물어봐야 합니다!
수정 코드:
# 잘못된 코드:
# print(balls.velocity) # ❌ 리스트 자체에는 velocity가 없다!
# 올바른 코드 — 리스트 안의 각 객체에 접근
print(balls[0].velocity) # ✅ 첫 번째 공의 속도
# 또는 for 루프로 전체 순회
for ball in balls: # ✅ 각 공에 하나씩 접근
print(ball.velocity)
💡 핵심 정리:
balls(리스트) ≠ball(개별 객체). 리스트는 컨테이너이고, 속성은 안에 든 객체에 있습니다!
✅ v3: while 루프에서 모든 공 동시에 움직이기¶
이제 진짜 핵심입니다! while 루프 + for 루프 조합으로 모든 공을 동시에 업데이트합니다.
v2에서 바뀐 점: while True: 루프 안에 for ball in balls: 패턴 추가
from vpython import *
import random
balls = []
for i in range(10):
ball = sphere(
pos=vector(-4 + i, 0, 0),
radius=0.3,
color=vector(random.random(), random.random(), random.random())
)
ball.velocity = vector(
random.uniform(-3, 3),
random.uniform(-3, 3),
0
)
balls.append(ball)
dt = 0.01 # 시간 간격
# 애니메이션 루프
while True:
rate(100) # 초당 100프레임
# 핵심 패턴: for ball in balls — 모든 공을 순회하며 업데이트
for ball in balls: # <- 여기가 [리스트 순회 업데이트 패턴]
ball.pos = ball.pos + ball.velocity * dt # <- 여기가 [위치 업데이트]
🖥️ 화면 결과: 10개의 알록달록한 공이 각자의 속도로 사방으로 흩어지며 움직입니다! 🎉
개념-코드 매핑:
- 25번째 줄
for ball in balls:— 이것이 바로 오늘의 핵심 패턴입니다. 리스트balls에서 공을 하나씩 꺼내ball이라는 변수에 넣고 아래 코드를 실행합니다. - 26번째 줄
ball.pos = ball.pos + ball.velocity * dt— 각 공의 현재 위치에 속도 × 시간을 더해 새 위치를 계산합니다. 모든 공에 대해 이 계산이 반복됩니다!
아래 다이어그램으로 while-for 이중 루프 구조를 확인해 봅시다:
while-for 이중 루프 구조: while이 매 프레임을 만들고, for가 매 프레임마다 모든 공을 처리합니다
하지만 아직 문제가 있습니다 — 공이 화면 밖으로 날아가 버립니다! 😅