레슨 5 / 8·20분
물리와 움직임
벡터와 물리 시뮬레이션
p5.js의 createVector()를 사용하면 위치, 속도, 가속도를 벡터로 표현하여 자연스러운 물리 시뮬레이션을 구현할 수 있습니다. 뉴턴의 운동 법칙(F=ma)을 코드로 옮기면 중력, 바람, 마찰 등 현실적인 움직임을 만들 수 있습니다.
javascript
// 물리 기반 공 튀기기
let position, velocity, acceleration;
let gravity;
function setup() {
createCanvas(800, 600);
position = createVector(width / 2, 100);
velocity = createVector(2, 0);
gravity = createVector(0, 0.3); // 중력
}
function draw() {
background(20);
// 물리 업데이트: 가속도 -> 속도 -> 위치
velocity.add(gravity); // 속도에 중력 적용
position.add(velocity); // 위치에 속도 적용
// 바닥 충돌
if (position.y > height - 20) {
position.y = height - 20;
velocity.y *= -0.8; // 반발 (에너지 손실 20%)
}
// 벽 충돌
if (position.x > width - 20 || position.x < 20) {
velocity.x *= -1;
}
// 공 그리기
fill(255, 100, 150);
noStroke();
ellipse(position.x, position.y, 40, 40);
}파티클 시스템
javascript
let particles = [];
function setup() {
createCanvas(800, 600);
}
function draw() {
background(10, 20, 30);
// 마우스 위치에서 파티클 생성
if (mouseIsPressed) {
for (let i = 0; i < 3; i++) {
particles.push({
pos: createVector(mouseX, mouseY),
vel: p5.Vector.random2D().mult(random(1, 4)),
life: 255,
size: random(4, 12),
hue: random(360),
});
}
}
// 파티클 업데이트 및 렌더링
colorMode(HSB, 360, 100, 100, 255);
noStroke();
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.vel.y += 0.05; // 중력
p.pos.add(p.vel);
p.life -= 3;
fill(p.hue, 80, 100, p.life);
ellipse(p.pos.x, p.pos.y, p.size);
if (p.life <= 0) particles.splice(i, 1);
}
}javascript
// 인력/척력 시뮬레이션
let attractor;
let movers = [];
function setup() {
createCanvas(800, 600);
attractor = createVector(width / 2, height / 2);
for (let i = 0; i < 50; i++) {
movers.push({
pos: createVector(random(width), random(height)),
vel: createVector(0, 0),
mass: random(1, 5),
});
}
}
function draw() {
background(10, 25);
attractor.set(mouseX, mouseY);
// 인력 중심 표시
fill(255, 50, 50);
noStroke();
ellipse(attractor.x, attractor.y, 20);
for (let m of movers) {
// 인력 계산 (뉴턴 만유인력)
let force = p5.Vector.sub(attractor, m.pos);
let dist = constrain(force.mag(), 5, 50);
force.normalize();
let strength = (10 * m.mass) / (dist * dist);
force.mult(strength);
// F = ma -> a = F/m
let acc = p5.Vector.div(force, m.mass);
m.vel.add(acc);
m.vel.mult(0.99); // 마찰
m.pos.add(m.vel);
fill(100, 200, 255, 200);
ellipse(m.pos.x, m.pos.y, m.mass * 6);
}
}- •createVector(x, y) — 2D 벡터 생성 (위치, 속도, 힘 표현)
- •vec.add(other) — 벡터 덧셈 (속도를 위치에 더하기 등)
- •vec.mult(scalar) — 벡터 스칼라 곱 (힘의 크기 조절)
- •p5.Vector.sub(a, b) — 새 벡터 반환 (방향 계산)
- •p5.Vector.random2D() — 무작위 방향의 단위 벡터
- •constrain(val, min, max) — 값의 범위 제한
💡
물리 시뮬레이션에서 마찰을 적용하려면 velocity.mult(0.99)처럼 속도에 1보다 작은 값을 곱합니다. 이 값이 1에 가까울수록 마찰이 적고, 0에 가까울수록 빠르게 멈춥니다.