Media Art ProgrammingWeek 07 · Period 03 Handout

p5.js / Media Art Programming

7주차 3교시 — 학생 주도 실습: 클래스를 활용한 다중 오브젝트 작품

Classes and Objects 주제의 학생용 강의 자료입니다.

WEEK 07 PERIOD 03 P5.JS MEDIA ART

7주차 3교시 — 학생 주도 실습: 클래스를 활용한 다중 오브젝트 작품

강의 아웃라인: week-07-outline 이전 교시: week-07-period2-student (객체 배열과 클래스 확장) 다음 주차: 8주차 — 중간고사 (1~7주차)

항목 내용
대상 P5.js 입문자 (테크아트 전공)
소요 시간 45분
사전 준비 1교시 class 기본 문법, 2교시 객체 배열·클래스 확장
결과물 클래스·객체 배열 기반 다중 오브젝트 스케치 1점 (실습과제 3)
실습 목표
  • class 문법으로 독립 객체를 정의하고, 객체 배열로 다수의 객체를 생성·관리하는 작품을 제작합니다
  • 1~6주차 개념(변수·조건문·반복문·함수·배열)이 클래스 안에서 통합되는 것을 체감합니다

완성 기준 안내 + 실습 시작

1-2교시에 배운 클래스와 객체 배열을 합쳐서 직접 작품을 만드는 시간입니다. 세 단계 완성 기준이 있습니다.

완성 기준

단계 이름 완성 기준 핵심
기본 클래스로 움직이는 객체 class 정의(constructor + move + display) + 객체 배열로 10개 이상 + for문 순회 “클래스로 여러 개가 움직인다”
표준 기능 확장 + 인터랙션 기본 + bounce() 메서드 + 랜덤 색상/크기 + mousePressed()로 클릭 추가 “튕기고, 예쁘고, 반응한다”
심화 완성된 작품 표준 + 시각 효과 (잔상, 바운스 색변경, HSB 등) + 키보드 인터랙션 “보기 좋고, 인터랙션도 풍부하다”
완성 기준 팁

만 해도 오늘 목표 완료입니다. 까지 가면 충분히 도전적인 단계입니다. 자기 속도에 맞게 진행하세요!

실습과제 3 안내

이 스케치가 곧 실습과제 3입니다. 수업 중에 기본을 만들고, 중간고사(8주차) 전까지 발전시켜서 P5.js 웹 에디터 링크로 제출합니다. 제출 완료 시 만점입니다.

세 가지 방향

세 방향 중 하나를 골라 시작합니다. 자유롭게 섞어도 됩니다.

방향 설명 핵심 기술 1-2교시 연결
A. 바운싱 볼 월드 Ball 클래스 + 객체 배열 + 클릭으로 추가 class, 배열, 바운싱, mousePressed 2교시 미니 실습 확장
B. 파티클 아트 마우스에서 파티클 생성 + 중력 효과 class, push, speedY += 0.1, 잔상 2교시 사례 1 확장
C. 자유 주제 나만의 클래스 설계 (별, 꽃, 눈, 비 등) class 설계, 창의적 display() 새로운 방향
08 project directions a b c preview
방향 선택

무엇을 골라야 할지 모르겠으면 A(바운싱 볼 월드)부터 시작하세요. 2교시에서 이미 만들어 봤으므로 가장 친숙합니다.

환경 설정

  1. P5.js Web Editor 접속 (로그인 확인)
  2. File → New → 스케치 이름을 week07-class로 변경
  3. 아래 세 방향 중 하나를 골라 스타터 코드를 복사-붙여넣기

스타터 코드

방향 A: 바운싱 볼 월드

class Ball {
  constructor(x, y, speedX, speedY) {
    this.x = x;
    this.y = y;
    this.speedX = speedX;
    this.speedY = speedY;
    this.size = 30;
  }

  move() {
    this.x += this.speedX;
    this.y += this.speedY;
  }

  display() {
    fill(100, 150, 255);
    noStroke();
    ellipse(this.x, this.y, this.size);
  }
}

let balls = [];

function setup() {
  createCanvas(400, 400);
  // 시작할 때 공 5개 생성
  for (let i = 0; i < 5; i++) {
    balls.push(new Ball(
      random(width), random(height),
      random(-3, 3), random(-3, 3)
    ));
  }
}

function draw() {
  background(30);
  for (let i = 0; i < balls.length; i++) {
    balls[i].move();
    // TODO: balls[i].bounce(); ← 이 메서드를 만들어보세요!
    balls[i].display();
  }
}

// TODO: mousePressed()로 클릭하면 공 추가하기
// TODO: keyPressed()로 키보드 이벤트 추가하기

실행하면 파란 공 5개가 움직입니다. 바운싱이 아직 없어서 화면 밖으로 나갑니다. 여기서부터 시작합니다.

방향 B: 파티클 아트

class Particle {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.speedX = random(-2, 2);
    this.speedY = random(-5, -1);
    this.size = random(5, 12);
  }

  update() {
    this.x += this.speedX;
    this.y += this.speedY;
    this.speedY += 0.1;  // 중력
  }

  display() {
    fill(255, 200);
    noStroke();
    ellipse(this.x, this.y, this.size);
  }
}

let particles = [];

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(0, 0, 0, 40);  // 잔상 효과

  // 마우스 누르고 있으면 파티클 생성
  if (mouseIsPressed) {
    particles.push(new Particle(mouseX, mouseY));
  }

  for (let i = 0; i < particles.length; i++) {
    particles[i].update();
    particles[i].display();
  }

  // 화면 밖 파티클 제거
  for (let i = particles.length - 1; i >= 0; i--) {
    if (particles[i].y > height) {
      particles.splice(i, 1);
    }
  }
}

// TODO: 파티클에 색상 추가하기
// TODO: 키보드로 중력 방향 바꾸기

마우스를 누르고 있으면 하얀 파티클이 위로 솟아올랐다 떨어집니다. 여기서부터 시작합니다.

방향 C: 자유 주제 (눈 내리기 예시)

class Snowflake {
  constructor() {
    this.x = random(width);
    this.y = random(-50, 0);
    this.size = random(3, 8);
    this.speed = random(1, 3);
    this.drift = random(-0.5, 0.5);  // 좌우 흔들림
  }

  update() {
    this.y += this.speed;
    this.x += this.drift;
  }

  display() {
    fill(255);
    noStroke();
    ellipse(this.x, this.y, this.size);
  }
}

let snowflakes = [];

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(20, 20, 40);

  // 매 프레임 눈 1개 생성
  snowflakes.push(new Snowflake());

  for (let i = 0; i < snowflakes.length; i++) {
    snowflakes[i].update();
    snowflakes[i].display();
  }

  // 화면 밖 눈 제거
  for (let i = snowflakes.length - 1; i >= 0; i--) {
    if (snowflakes[i].y > height) {
      snowflakes.splice(i, 1);
    }
  }
}

// TODO: 눈 색상이나 크기를 바꿔 보세요
// TODO: 마우스 근처에서 눈이 밀려나게 만들어보세요

눈이 위에서 아래로 내립니다. 각 눈송이는 서로 다른 크기, 속도, 좌우 흔들림을 가집니다. 이 코드를 바탕으로 자유롭게 바꿔 보세요.


Step 1 — 스타터 코드 실행 + 숫자 바꿔보기 → 기본 달성

목표: 스타터 코드가 동작하는지 확인하고, 숫자를 바꿔보며 클래스 구조를 체감합니다.

이 단계를 마치면 기본 달성!

방향 A 기준

코드 분석 포인트: 1. class Ball { } — 설계도 전체 구조 2. constructor(x, y, speedX, speedY) — 매개변수로 위치와 속도를 받음 3. this.x, this.y, this.size — 프로퍼티에 저장 4. move(), display() — 메서드로 동작 정의 5. balls.push(new Ball(...)) — 배열에 객체 추가 6. balls[i].move(), balls[i].display() — for문으로 전체 순회

코드 읽기

1-2교시에서 배운 내용이 모두 여기에 있습니다. 하나씩 확인해 보세요.

이 단계에서 할 것: - 공 개수를 5에서 20으로 바꿔보기 (for (let i = 0; i < 20; i++)) - 실행해서 공 20개가 되는지 확인 - this.size = 30this.size = random(20, 50)으로 바꿔보기 - 속도 범위를 random(-3, 3)random(-5, 5)로 바꿔보기

힌트 (막히면 펼쳐보세요)

setup() 안의 for문에서 i < 5i < 20으로 바꾸면 됩니다. balls.length가 자동으로 20이 되므로 draw()는 수정할 필요 없습니다.

this.sizeclass Ballconstructor() 안에서 바꾸면 됩니다. 30 대신 random(20, 50)을 넣으면 공마다 다른 크기가 됩니다.

방향 B 기준

이 단계에서 할 것: - 한 번에 생성하는 파티클 수 바꾸기 (1개 → 3개) - this.sizerandom() 범위를 바꿔보기 - 중력 값 0.10.3으로 바꿔보기 — 더 빨리 떨어짐

방향 C 기준

이 단계에서 할 것: - 눈 크기 범위를 바꿔보기 (random(3, 8)random(2, 15)) - 눈 속도를 바꿔보기 (random(1, 3)random(0.5, 5)) - 배경색을 바꿔보기 — 밤하늘 색, 회색 하늘 등


Step 2 — 기능 확장 + 인터랙션 추가 → 표준 달성

목표: 클래스에 메서드를 추가하고, 마우스 인터랙션을 넣습니다.

이 단계를 마치면 표준 달성!

방향 A 기준: bounce() 추가 + 색상 + 클릭 인터랙션

공이 화면 밖으로 나가는 문제를 해결하기 위해 bounce() 메서드를 추가합니다. 이 메서드가 공을 벽에서 튕기게 만듭니다.

할 일 1 — bounce() 메서드 추가:

// class Ball { } 안에 추가
bounce() {
  if (this.x > width || this.x < 0) {
    this.speedX *= -1;
  }
  if (this.y > height || this.y < 0) {
    this.speedY *= -1;
  }
}

draw()에서 balls[i].bounce();를 호출합니다. 주석 처리된 TODO 부분입니다.

할 일 2 — 랜덤 색상 추가:

constructor에서 this.c = color(random(255), random(255), random(255));를 추가하고, display()에서 fill(100, 150, 255)fill(this.c)로 바꿉니다.

할 일 3 — 클릭으로 공 추가:

function mousePressed() {
  balls.push(new Ball(
    mouseX, mouseY,
    random(-3, 3), random(-3, 3)
  ));
}

마우스를 클릭한 위치에서 랜덤 속도의 공이 추가됩니다.

힌트 (막히면 펼쳐보세요)
  1. bounce() 메서드는 display() 아래에, class의 중괄호 } 안에 넣으세요
  2. draw()에서 balls[i].move(); 다음 줄에 balls[i].bounce();를 추가
  3. this.c를 constructor에 추가할 때, this.size 다음 줄에 넣으면 됩니다
  4. mousePressed() 함수는 draw() 밖에 독립적으로 선언해야 합니다

에러가 나면 확인할 것: - bounce() 안에 function을 쓰지 않았는지 (클래스 안에서는 function 안 씀!) - this.c에서 this를 빠뜨리지 않았는지

방향 B 기준: 색상 추가 + 클릭 폭발

할 일 1 — constructor에 색상 추가:

this.c = color(random(255), random(100, 255), random(100));

할 일 2 — display()에서 색상 사용:

fill(this.c);

할 일 3 — 클릭하면 한 번에 많은 파티클 폭발:

function mousePressed() {
  for (let i = 0; i < 20; i++) {
    particles.push(new Particle(mouseX, mouseY));
  }
}

방향 C 기준: 투명도 + 클릭 인터랙션

할 일 1 — constructor에 투명도 추가:

this.alpha = random(100, 255);

할 일 2 — display()에서 사용:

fill(255, this.alpha);

할 일 3 — 클릭하면 눈 폭풍 (한번에 30개):

function mousePressed() {
  for (let i = 0; i < 30; i++) {
    snowflakes.push(new Snowflake());
  }
}

Step 3 — 시각 효과 + 키보드 → 심화 달성

목표: 잔상, 색상 변경, HSB, 키보드 인터랙션 등으로 작품을 발전시킵니다.

이 단계를 마치면 심화 달성!

09 finished examples gallery

잔상 효과 (전 방향 공통)

// background(30); 을 아래로 교체
background(30, 30, 30, 50);  // 반투명 배경 → 잔상 효과

배경의 투명도를 낮추면 이전 프레임이 살짝 남아서 궤적이 보입니다.

바운스 시 색 변경 (방향 A)

bounce() {
  if (this.x > width || this.x < 0) {
    this.speedX *= -1;
    this.c = color(random(255), random(255), random(255));  // 색 변경!
  }
  if (this.y > height || this.y < 0) {
    this.speedY *= -1;
    this.c = color(random(255), random(255), random(255));
  }
}

HSB 색상 모드 (전 방향 공통)

function setup() {
  createCanvas(400, 400);
  colorMode(HSB, 360, 100, 100);  // HSB 모드!
  // ...
}

// constructor에서 색상 생성 시:
this.c = color(random(360), 80, 100);  // 선명한 랜덤 색상

키보드 인터랙션 (방향 A)

function keyPressed() {
  if (key === 'c') {
    balls = [];  // 모든 공 삭제
  }
  if (key === 'r') {
    // 공 10개 다시 생성
    for (let i = 0; i < 10; i++) {
      balls.push(new Ball(
        random(width), random(height),
        random(-3, 3), random(-3, 3)
      ));
    }
  }
}

정보 표시 (전 방향 공통)

// draw() 맨 마지막에 추가
fill(255);
noStroke();
textSize(14);
text("objects: " + balls.length, 10, 20);

파티클 크기 줄이기 (방향 B — 수명 효과)

// update() 안에 추가
this.size -= 0.1;  // 점점 작아짐

// display() 수정 — 크기가 0 이하면 안 그림
display() {
  if (this.size > 0) {
    fill(this.c);
    noStroke();
    ellipse(this.x, this.y, this.size);
  }
}

완성 예시 — 방향 A 바운싱 볼 월드 ( 심화)

class Ball {
  constructor(x, y, speedX, speedY) {
    this.x = x;
    this.y = y;
    this.speedX = speedX;
    this.speedY = speedY;
    this.size = random(15, 45);
    this.c = color(random(360), 80, 100);
  }

  move() {
    this.x += this.speedX;
    this.y += this.speedY;
  }

  bounce() {
    if (this.x > width || this.x < 0) {
      this.speedX *= -1;
      this.c = color(random(360), 80, 100);
    }
    if (this.y > height || this.y < 0) {
      this.speedY *= -1;
      this.c = color(random(360), 80, 100);
    }
  }

  display() {
    fill(this.c);
    noStroke();
    ellipse(this.x, this.y, this.size);
  }
}

let balls = [];

function setup() {
  createCanvas(400, 400);
  colorMode(HSB, 360, 100, 100);
  for (let i = 0; i < 20; i++) {
    balls.push(new Ball(
      random(width), random(height),
      random(-4, 4), random(-4, 4)
    ));
  }
}

function draw() {
  background(0, 0, 10, 50);  // 잔상 효과
  for (let i = 0; i < balls.length; i++) {
    balls[i].move();
    balls[i].bounce();
    balls[i].display();
  }
  // 정보 표시
  fill(0, 0, 100);
  noStroke();
  textSize(14);
  text("Bouncing Ball World", 10, 20);
  text("balls: " + balls.length + " | click to add | 'c' to clear", 10, 38);
}

function mousePressed() {
  balls.push(new Ball(
    mouseX, mouseY,
    random(-4, 4), random(-4, 4)
  ));
}

function keyPressed() {
  if (key === 'c') {
    balls = [];
  }
  if (key === 'r') {
    for (let i = 0; i < 10; i++) {
      balls.push(new Ball(
        random(width), random(height),
        random(-4, 4), random(-4, 4)
      ));
    }
  }
}

실행 결과: - 어두운 배경에 선명한 HSB 색상의 공들이 잔상을 남기며 바운싱 - 벽에 닿으면 색상 변경 - 클릭하면 공 추가 - c 키로 전부 삭제, r 키로 10개 재생성 - 좌상단에 공 개수 표시


마무리

스케치 저장

저장

Ctrl+S (Mac: Cmd+S)로 스케치를 저장하세요. P5.js Web Editor에서 저장하면 자동으로 계정에 연결됩니다.

오늘 한 것 돌아보기

완성 기준 핵심 기술 확인
기본 class 정의 + 객체 배열 + for문 순회 “내 스케치에 클래스로 만든 객체가 여러 개 움직이고 있나?”
표준 bounce() + 랜덤 색상/크기 + mousePressed() “벽에서 튕기고, 색상이 다양하고, 클릭하면 추가되나?”
심화 잔상 + 바운스 색변경 + HSB + 키보드 “시각적으로 완성도 있고, 인터랙션도 풍부한가?”
핵심

어디까지 갔든 괜찮습니다. 중요한 것은 클래스와 객체 배열을 직접 써본 경험입니다.

실습과제 3 제출 안내

항목 내용
과제명 클래스를 활용한 다중 오브젝트 작품
제출 기한 8주차(중간고사) 수업 전까지
제출 방식 P5.js Web Editor 링크 공유
평가 제출 완료 시 만점
# 필수 요구사항
1 class 1개 이상 정의 (constructor + 메서드 2개 이상)
2 객체 배열로 10개 이상 관리
3 각 객체가 독립적으로 움직이거나 변화
4 인터랙션 1개 이상 (마우스 클릭, 키보드 등)
제출 팁

까지 도달했다면 이미 요구사항 4개를 모두 충족합니다. 수업 중에 만든 것을 다듬어서 제출하면 됩니다.

중간고사(8주차) 예고

다음 주는 중간고사입니다. 범위는 1~7주차입니다.

핵심 줄거리를 기억하고 있나요?

도형을 그리고(1-2주) → 색을 칠하고 반복하고(3주) → 클릭/키보드에 반응하고(4주) → 움직이고 튕기고(5주) → 함수와 배열로 정리하고(6주) → 클래스로 하나로 묶는다(7주)

시험 준비

오늘 만든 Ball 클래스 코드를 다시 한 번 읽어보세요. 1~7주차의 모든 개념이 이 클래스 안에 다 들어 있습니다.