Media Art ProgrammingWeek 06 · Period 01 Handout

p5.js / Media Art Programming

6주차 1교시 — 사용자 정의 함수: 코드를 정리하는 도구

Functions and Arrays 주제의 학생용 강의 자료입니다.

WEEK 06 PERIOD 01 P5.JS MEDIA ART

6주차 1교시 — 사용자 정의 함수: 코드를 정리하는 도구

강의 아웃라인: week-06-outline 다음 교시: week-06-period2-student (배열: 데이터를 한꺼번에 관리하자)

항목 내용
대상 P5.js 입문자 (테크아트 전공)
소요 시간 45분
핵심 도구 P5.js Web Editor
학습 목표
  • 사용자 정의 함수를 선언하고 호출할 수 있습니다
  • 매개변수를 활용하여 재사용 가능한 함수를 만들 수 있습니다
  • 반환값(return)의 개념을 이해하고 활용할 수 있습니다
  • 5주차 바운싱 볼 코드를 함수로 리팩토링할 수 있습니다

도입

5주차 연결 — 코드가 길어지는 문제

5주차에서 만든 바운싱 볼은 원 하나가 화면 안에서 튕기는 코드였습니다. 그런데 공 2개를 만들려면 같은 코드를 복사-붙여넣기 해야 합니다.

let x1, y1, speedX1, speedY1;
let x2, y2, speedX2, speedY2;

function draw() {
  background(220);
  // 공 1
  ellipse(x1, y1, 50, 50);
  x1 += speedX1;
  y1 += speedY1;
  if (x1 > width || x1 < 0) speedX1 *= -1;
  if (y1 > height || y1 < 0) speedY1 *= -1;
  // 공 2 — 같은 코드를 복사-붙여넣기!
  ellipse(x2, y2, 50, 50);
  x2 += speedX2;
  y2 += speedY2;
  if (x2 > width || x2 < 0) speedX2 *= -1;
  if (y2 > height || y2 < 0) speedY2 *= -1;
}

직접 해보기 — 공 색깔을 바꿔보세요

미션
  1. 위 공 2개 코드를 에디터에 넣고 실행하세요.
  2. 공의 크기를 50에서 30으로 바꿔보세요. — ellipse(x1, ...)ellipse(x2, ...) 두 군데를 다 바꿔야 합니다.
  3. 공 3개로 만들어보세요. — 변수 12개, 같은 코드 3번 반복.

공 10개면 변수 40개에 같은 코드 10번 복사. ‘같은 걸 반복하고 있다’ — 이 느낌이 들면, 그게 바로 함수가 필요하다는 신호입니다.

사실 우리는 이미 함수를 쓰고 있다

함수라는 단어가 낯설 수 있지만, 우리는 1주차부터 매주 함수를 쓰고 있었습니다.

우리가 쓰고 있는 함수 하는 일
setup() 초기 설정 (P5.js가 자동 호출)
draw() 매 프레임 실행 (P5.js가 자동 호출)
ellipse(x, y, w, h) 원 그리기
fill(r, g, b) 색상 채우기
random(min, max) 랜덤 숫자 생성

ellipse()라고 부르면 내부적으로 원을 그리는 코드가 수십 줄 실행됩니다. 우리는 그 코드를 몰라도 ellipse()라는 이름만 불러서 원을 그릴 수 있었습니다. 이번 시간에는 내가 만드는 함수를 배웁니다.


핵심 개념 1 — 함수 = 이름 붙인 코드 묶음

비유: 레시피(조리법)

요리 프로그래밍
레시피를 노트에 적어둔다 함수를 만든다 (선언)
“볶음밥 해줘”라고 말한다 함수를 부른다 (호출)
재료를 바꾼다 (김치/새우) 매개변수를 바꾼다
완성된 요리가 나온다 반환값이 돌아온다

레시피를 한 번 적어두면 누가 언제든 그대로 만들 수 있습니다. 함수는 이름 붙인 코드 묶음이에요. 한 번 만들어두면 이름만 불러서 몇 번이든 실행할 수 있습니다.

함수 만드는 문법

function 이름() {
  실행할 코드
}

setup()완전히 같은 모양입니다. 우리는 이미 setup, draw라는 함수를 만들 줄 압니다. 이제 원하는 이름으로 함수를 만들어봅니다.

나만의 함수 만들기

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

function draw() {
  background(220);
  drawSmiley();    // 스마일을 그려줘!
}

// 스마일 이모지를 그리는 함수
function drawSmiley() {
  fill(255, 255, 0);              // 노란색
  ellipse(200, 200, 100, 100);   // 얼굴
  fill(0);                        // 검은색
  ellipse(185, 190, 10, 10);     // 왼쪽 눈
  ellipse(215, 190, 10, 10);     // 오른쪽 눈
  arc(200, 210, 40, 20, 0, PI);  // 입 (반원)
}

핵심은 두 가지입니다.

  • drawSmiley()만든 부분(아래쪽)과 부르는 부분(draw() 안)이 따로 있습니다.
  • 만들기만 하면 아무 일도 안 일어나요. 불러야 실행됩니다.
  • draw() 안의 drawSmiley() 한 줄이 스마일을 그리는 5줄의 코드를 이름 하나로 대체합니다.
01 declaration vs call
확인 질문

drawSmiley()draw() 안에 두 번 쓰면 어떻게 될까요?

: 같은 위치에 두 번 그려집니다. 겹쳐서 달라 보이진 않지만 코드는 두 번 실행된 것입니다. 위치를 바꿀 수 있게 되면 실제로 유용해집니다.


핵심 개념 2 — 매개변수: 재료를 넘기기

위의 스마일은 항상 (200, 200)에만 그려집니다. 다른 위치에도 그리려면 함수를 부를 때 ‘어디에 그릴지’ 알려주면 됩니다. 이것이 매개변수입니다.

매개변수 1개 — x좌표

function draw() {
  background(220);
  drawSmiley(100);    // x=100 위치에 그려줘
  drawSmiley(300);    // x=300 위치에 그려줘
}

function drawSmiley(x) {
  fill(255, 255, 0);
  ellipse(x, 200, 100, 100);     // x 사용!
  fill(0);
  ellipse(x - 15, 190, 10, 10);  // 왼쪽 눈도 x 기준
  ellipse(x + 15, 190, 10, 10);  // 오른쪽 눈도 x 기준
  arc(x, 210, 40, 20, 0, PI);    // 입도 x 기준
}

drawSmiley(100) — 소괄호 안의 100이 함수 안의 x로 들어갑니다. drawSmiley(300) — 이번엔 300이 x로. 같은 함수인데 넣어주는 값에 따라 다른 위치에 그려집니다.

소괄호 안의 x매개변수(parameter), 호출할 때 넣어주는 값(100, 300)을 인수(argument)라고 합니다.

매개변수 2개 — x, y

function draw() {
  background(220);
  drawSmiley(100, 100);    // 왼쪽 위
  drawSmiley(300, 100);    // 오른쪽 위
  drawSmiley(200, 300);    // 아래 중앙
}

function drawSmiley(x, y) {
  fill(255, 255, 0);
  ellipse(x, y, 100, 100);
  fill(0);
  ellipse(x - 15, y - 10, 10, 10);
  ellipse(x + 15, y - 10, 10, 10);
  arc(x, y + 10, 40, 20, 0, PI);
}

스마일 3개, 위치가 전부 다릅니다. 같은 함수, 다른 재료, 다른 결과.

매개변수 3개 — 크기도 조절

function draw() {
  background(220);
  drawSmiley(100, 100, 120);   // 큰 스마일
  drawSmiley(300, 100, 60);    // 작은 스마일
  drawSmiley(200, 300, 90);    // 중간 스마일
}

function drawSmiley(x, y, size) {
  fill(255, 255, 0);
  ellipse(x, y, size, size);
  fill(0);
  ellipse(x - size * 0.15, y - size * 0.1, size * 0.1, size * 0.1);
  ellipse(x + size * 0.15, y - size * 0.1, size * 0.1, size * 0.1);
  arc(x, y + size * 0.1, size * 0.4, size * 0.2, 0, PI);
}
02 parameter flow
마우스를 따라다니는 스마일

draw() 안에 drawSmiley(mouseX, mouseY, 50); 한 줄을 추가해보세요. 스마일이 마우스를 따라다닙니다. 변수도 매개변수로 넣을 수 있습니다. 함수 하나로 넣어주는 값만 바꿔 다양한 결과를 만들 수 있습니다.


핵심 개념 3 — 반환값: 결과를 돌려주기

drawSmiley()그리기만 하고 끝이었습니다. 그런데 어떤 함수는 값을 돌려주기도 합니다.

이미 반환값을 쓰고 있었다

let r = random(0, 255);  // random()이 랜덤 숫자를 돌려줌 → r에 저장
let d = dist(100, 100, mouseX, mouseY);  // dist()가 거리를 돌려줌 → d에 저장

random(0, 255)가 실행되면 랜덤 숫자가 하나 나옵니다. 그걸 r에 담는 것입니다. 반면 ellipse()는 원을 그리기만 하고 뭔가를 돌려주지 않습니다.

종류 하는 일 예시
값을 돌려주는 함수 계산/처리 후 결과를 반환 random(), dist(), map()
동작을 수행하는 함수 동작만 하고 끝 ellipse(), fill(), background()

return 키워드

function add(a, b) {
  return a + b;
}

let result = add(3, 5);   // result = 8
console.log(result);       // 콘솔에 8 출력

return a + b — ’a + b의 결과를 돌려줘라’는 뜻입니다. add(3, 5)를 호출하면 8이 돌아와서 result에 들어갑니다.

P5.js 활용: 랜덤 색상 만드는 함수

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

function draw() {
  background(220);

  let c = randomWarmColor();      // 따뜻한 랜덤 색상을 돌려줘!
  fill(c);
  ellipse(200, 200, 150, 150);
}

// 따뜻한 계열 랜덤 색상을 돌려주는 함수
function randomWarmColor() {
  let r = random(180, 255);   // 빨강 많이
  let g = random(50, 150);    // 초록 적당히
  let b = random(0, 80);      // 파랑 조금
  return color(r, g, b);       // 색상을 만들어서 돌려줌!
}

randomWarmColor()를 부르면 따뜻한 계열의 랜덤 색상이 하나 돌아옵니다. 이런 식으로 randomCoolColor(), randomPastelColor() 같은 나만의 색상 팔레트 함수를 만들 수 있습니다.

03 return flow

예제 — 바운싱 볼 리팩토링

도입에서 본 바운싱 볼 코드를 함수로 리팩토링합니다. 리팩토링이란 ’동작은 그대로인데 코드 구조를 개선하는 것’입니다.

리팩토링 전: 5주차 원본

draw() 안에 그리기·이동·바운싱이 한 덩어리로 들어가 있습니다. 코드가 길어지면 읽기 어려워집니다.

리팩토링 후: 한 함수씩 분리

let x, y;
let speedX, speedY;

function setup() {
  createCanvas(400, 400);
  x = width / 2;
  y = height / 2;
  speedX = 3;
  speedY = 2;
}

function draw() {
  background(220);
  drawBall();       // 그리기
  moveBall();       // 이동
  bounceBall();     // 바운싱
}

function drawBall() {
  fill(100, 150, 255);
  ellipse(x, y, 50, 50);
}

function moveBall() {
  x += speedX;
  y += speedY;
}

function bounceBall() {
  if (x > width || x < 0) speedX *= -1;
  if (y > height || y < 0) speedY *= -1;
}

실행하면 5주차와 완전히 동일하게 동작합니다. 바뀐 건 코드의 구조뿐입니다. draw() 안이 세 줄로, 무엇을 하는지 한눈에 보입니다. 바운싱 로직을 수정하려면 bounceBall() 함수만 찾으면 됩니다.

04 refactoring comparison
함수 이름 짓는 팁

동사로 시작하세요. drawBall(공을 그리다), moveBall(공을 움직이다), checkBounce(바운싱을 체크하다). 이름만 봐도 뭘 하는 함수인지 알 수 있도록.


정리

1교시 핵심 요약
개념 한 줄 설명 코드
함수 이름 붙인 코드 묶음. 몇 번이든 호출 가능 function drawSmiley() { ... }
매개변수 함수에 값을 넘겨서 다른 결과를 만듦 drawSmiley(x, y, size)
반환값 return으로 결과를 돌려줌 return color(r, g, b);

함수의 3가지 쓸모 — 반복 제거(복사-붙여넣기 대신 호출), 코드 정리(긴 코드를 함수로 분리), 재사용(한 번 만든 함수를 어디서나).

2교시 예고

함수로 코드를 정리하는 건 배웠지만, 공 여러 개의 데이터는 어떻게 관리할까요? 2교시에서 배열(Array)을 배우면 같은 종류의 데이터를 하나의 변수에 묶어서 관리할 수 있습니다. 함수 + 배열을 합치면 공 100개도 코드 몇 줄이면 충분합니다.