Media Art ProgrammingWeek 06 · Period 02 Handout

p5.js / Media Art Programming

6주차 2교시 — 배열: 데이터를 한꺼번에 관리하자

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

WEEK 06 PERIOD 02 P5.JS MEDIA ART

6주차 2교시 — 배열: 데이터를 한꺼번에 관리하자

강의 아웃라인: week-06-outline 이전 교시: week-06-period1-student (사용자 정의 함수) 다음 교시: week-06-period3-student (학생 주도 실습: 함수와 배열로 다중 오브젝트)

항목 내용
대상 P5.js 입문자 (테크아트 전공)
소요 시간 45분
사전 준비 1교시 사용자 정의 함수 (매개변수·반환값)
학습 목표
  • 배열을 선언하고 인덱스로 요소에 접근할 수 있습니다
  • .length·.push()로 배열을 조작할 수 있습니다
  • 배열과 for문을 결합해 다수 데이터를 순회할 수 있습니다
  • 배열·반복문·함수를 결합해 다수 오브젝트를 관리할 수 있습니다

1교시 복습

1교시에서 함수를 배웠습니다.

함수가 있으니 공을 함수로 그릴 수 있습니다. 하지만 공 여러 개의 데이터를 관리하는 문제가 남아 있습니다. 이번 시간에 해결합니다.


심화 개념 1 — 배열이 필요한 이유

일상에서 찾는 배열

스마트폰 음악 앱의 플레이리스트를 떠올려보세요. 노래가 순서대로 들어 있죠?

내 플레이리스트:
  1번 트랙: "Blinding Lights"
  2번 트랙: "Dynamite"
  3번 트랙: "Butter"
  4번 트랙: "Levitating"

이게 배열입니다. 같은 종류의 것들(노래)이 순서대로 나열되어 있습니다. 엑셀 시트의 한 열(A1, A2, A3…)도 마찬가지입니다.

왜 배열이 필요한가 — 변수의 한계

공 100개의 x좌표, y좌표, 속도를 저장하려면?

// 이렇게 하나씩 늘리면 곧 관리가 어려워집니다
let x1 = 10, x2 = 50, x3 = 90, x4 = 130, x5 = 170;
// ... x100 = ???

변수 이름을 100개 짓고, 나중에 x47을 눈으로 찾는 방식은 유지보수가 어렵고 실수가 생기기 쉽습니다.

배열 = 번호가 매겨진 서랍장

변수 하나하나 = 이름표가 각각 붙은 상자들 (x1, x2, x3...)
배열 하나     = 번호가 매겨진 서랍장 (칸이 여러 개!)

  [0번 칸] [1번 칸] [2번 칸] [3번 칸] [4번 칸]
  |  10  | |  50  | |  90  | | 130  | | 170  |

서랍장 하나에 이름 하나(xPositions)만 붙이면 되고, 각 칸은 번호(0, 1, 2, …)로 접근합니다. 변수 100개 대신 배열 1개면 충분합니다.


심화 개념 2 — 배열 선언과 인덱스

배열 만들기

배열은 대괄호 []로 만듭니다.

// 빈 배열 — 아직 아무것도 안 넣은 빈 서랍장
let xPositions = [];

// 값을 넣으면서 만들기 — 서랍장에 미리 물건을 채워놓은 것
let scores = [95, 80, 70, 100, 88];

// 문자열, 색상값 등 다른 것도 넣을 수 있어요
let names = ["Alice", "Bob", "Charlie"];

인덱스 — 0부터 시작하는 번호표

배열의 각 칸에는 인덱스(번호)가 붙어 있고, 번호는 0번부터 시작합니다. 유럽 건물의 Ground Floor(0층)처럼요.

let fruits = ["사과", "바나나", "포도", "딸기"];
인덱스:   [0]      [1]       [2]      [3]
값:      "사과"   "바나나"    "포도"   "딸기"

접근할 때는 배열이름[인덱스번호]로 합니다.

console.log(fruits[0]);  // "사과"   ← 0번째
console.log(fruits[1]);  // "바나나" ← 1번째
console.log(fruits[3]);  // "딸기"   ← 3번째

요소가 4개면 마지막 인덱스는 3입니다 (4가 아니라). 0부터 시작하니까 0, 1, 2, 3.

없는 인덱스에 접근하면?

console.log(fruits[10]);  // undefined ← 10번 칸은 없으니까!

에러는 아니고 undefined(정의되지 않음)가 나옵니다. 코드가 예상과 다르게 동작할 때 undefined가 보이면 배열 인덱스 접근을 먼저 확인하세요.

인덱스 퀴즈

let animals = ["고양이", "강아지", "토끼", "앵무새", "햄스터"];

  • animals[0]은? → “고양이”
  • animals[3]은? → “앵무새”
  • animals[5]는? → undefined (5번 칸 없음!)
  • 마지막 요소의 인덱스는? → 4 (5개니까 0~4)
06 zero index

값 바꾸기

let fruits = ["사과", "바나나", "포도", "딸기"];
fruits[1] = "수박";  // 1번 칸의 "바나나"를 "수박"으로 교체!
console.log(fruits); // ["사과", "수박", "포도", "딸기"]

마이크로 실습 A — 내 배열 만들어보기

좋아하는 것 3가지를 배열로 만들고, 콘솔에 출력해보세요.

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

  // 예: 좋아하는 음식, 영화, 색상 등
  let favorites = ["피자", "파스타", "떡볶이"];

  console.log("전체:", favorites);
  console.log("첫 번째:", favorites[0]);
  console.log("마지막:", favorites[2]);
}

실행해서 콘솔에 값이 제대로 나오면 성공입니다.


심화 개념 3 — 배열 조작: length와 push

배열 길이: .length

배열에 몇 개의 요소가 있는지 알려줍니다.

let fruits = ["사과", "바나나", "포도", "딸기"];
console.log(fruits.length);  // 4

.length는 개수(4)이고, 마지막 인덱스(3)와는 다릅니다. 항상 length = 마지막 인덱스 + 1.

요소 추가: .push()

배열 맨 뒤에 새 요소를 추가합니다.

let fruits = ["사과", "바나나"];
console.log(fruits.length);  // 2

fruits.push("포도");
console.log(fruits);         // ["사과", "바나나", "포도"]
console.log(fruits.length);  // 3 ← 하나 늘었다!

push()는 나중에 “클릭할 때마다 공 추가하기”에서 유용하게 쓰입니다.

라이브 코딩 — 배열 만들고 조작해보기

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

  let numbers = [10, 20, 30, 40, 50];

  console.log("배열 전체:", numbers);
  console.log("첫 번째:", numbers[0]);
  console.log("길이:", numbers.length);

  // 60을 추가해보자
  numbers.push(60);
  console.log("추가 후:", numbers);

  // 값을 바꿔보자
  numbers[0] = 999;
  console.log("변경 후:", numbers);
}
확인 질문

numbers[5]는 push 하기 전에는 뭘까요?

: undefined — 아직 그 칸이 없으니까.


심화 개념 4 — 배열 + 반복문: 수동에서 자동으로

배열은 반복문과 결합할 때 가장 유용합니다. 3주차 for문을 다시 가져옵니다.

Step A — 수동으로 하나씩 그리기

let xPositions = [50, 150, 250, 350];

function draw() {
  background(220);

  // 하나씩 수동으로 그리기
  ellipse(xPositions[0], 200, 40, 40);
  ellipse(xPositions[1], 200, 40, 40);
  ellipse(xPositions[2], 200, 40, 40);
  ellipse(xPositions[3], 200, 40, 40);
}

원이 100개면 ellipse()를 100번 써야 할까요? 여기서 패턴이 보입니다 — 대괄호 안의 숫자만 0, 1, 2, 3으로 바뀝니다.

Step B — 패턴 발견: 숫자만 바뀐다!

ellipse(xPositions[0], 200, 40, 40);  ← 0
ellipse(xPositions[1], 200, 40, 40);  ← 1
ellipse(xPositions[2], 200, 40, 40);  ← 2
ellipse(xPositions[3], 200, 40, 40);  ← 3

0, 1, 2, 3을 i로 바꾸면 ellipse(xPositions[i], 200, 40, 40).

Step C — for문으로 자동화!

let xPositions = [50, 150, 250, 350];

function draw() {
  background(220);

  for (let i = 0; i < xPositions.length; i++) {
    ellipse(xPositions[i], 200, 40, 40);
  }
}

4줄이 2줄로 줄었고, 배열에 값을 100개 넣어도 이 for문 코드는 그대로입니다.

실행 흐름 트레이싱:

반복 i의 값 xPositions[i]의 값 실행되는 코드
1번째 0 50 ellipse(50, 200, 40, 40)
2번째 1 150 ellipse(150, 200, 40, 40)
3번째 2 250 ellipse(250, 200, 40, 40)
4번째 3 350 ellipse(350, 200, 40, 40)
종료 4 4 < 4는 false → 반복 끝!
07 array for loop

이 패턴은 통째로 외워두세요.

for (let i = 0; i < 배열이름.length; i++) {
  // 배열이름[i]로 각 요소에 접근
}

마이크로 실습 B — for문으로 원 여러 개 그리기

배열에 x좌표 5개를 넣고, for문으로 원을 그려보세요.

let xPos = [40, 120, 200, 280, 360];

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

function draw() {
  background(30);
  noStroke();

  for (let i = 0; i < xPos.length; i++) {
    fill(100 + i * 30, 150, 255);  // 색상도 i에 따라 변화
    ellipse(xPos[i], 200, 40, 40);
  }
}

원 5개가 가로로 나란히, 색이 조금씩 다르게 나오면 성공입니다.

도전: xPos 배열에 값을 3개 더 추가해보세요. for문 코드를 수정할 필요가 있나요? (없어요! .length가 자동으로 바뀌니까!)


심화 개념 5 — 배열 여러 개로 다양한 원 그리기

x좌표만이 아니라 y좌표, 크기도 배열로 만들면 각각 다른 위치와 크기의 원을 그릴 수 있습니다.

let xPos = [50, 120, 200, 280, 350];
let yPos = [100, 250, 180, 320, 150];
let sizes = [30, 50, 40, 60, 35];

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

function draw() {
  background(30);
  noStroke();

  for (let i = 0; i < xPos.length; i++) {
    fill(100 + i * 30, 150, 255);
    ellipse(xPos[i], yPos[i], sizes[i], sizes[i]);
  }
}

같은 인덱스 i로 여러 배열에 동시에 접근합니다. i번째 공의 x좌표, y좌표, 크기를 한꺼번에 꺼내는 것입니다 — 학생부에서 ’3번 학생’을 찾으면 이름·학번·전화번호를 한 줄에서 다 볼 수 있는 것처럼.

08 parallel arrays

심화 개념 6 — 배열 + 함수: 다수의 오브젝트 관리

1교시의 함수와 방금 배운 배열을 결합합니다. 이게 오늘 수업의 핵심 패턴입니다. random()push()로 배열을 자동으로 채울 수 있습니다.

let xPos = [];
let yPos = [];
let sizes = [];
let ballCount = 5;

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

  // 빈 배열에 랜덤 데이터를 push()로 채우기
  for (let i = 0; i < ballCount; i++) {
    xPos.push(random(width));
    yPos.push(random(height));
    sizes.push(random(20, 60));
  }
}

// 1교시에서 배운 함수!
function drawBall(x, y, size) {
  fill(255, 100, 100);
  noStroke();
  ellipse(x, y, size, size);
}

function draw() {
  background(30);

  // 배열 + 반복문 + 함수 = 한 번에 여러 개 그리기
  for (let i = 0; i < ballCount; i++) {
    drawBall(xPos[i], yPos[i], sizes[i]);
  }
}
오늘의 핵심 패턴

배열에 데이터를 넣고, 반복문으로 돌며, 함수로 그린다. 이 패턴만 익히면 공 5개든 100개든 1000개든 만들 수 있습니다. ballCount만 바꾸면 됩니다.


실전 사례 — 움직이는 공 여러 개

5주차에서 배운 바운싱을 배열에 적용해서 움직이는 공 여러 개를 만듭니다. 공 10개를 움직이려면 x좌표·y좌표·x속도·y속도가 각각 10개씩 — 배열 4개면 됩니다.

let xPos = [], yPos = [];
let speedX = [], speedY = [];
let sizes = [];
let numBalls = 10;

function setup() {
  createCanvas(400, 400);
  for (let i = 0; i < numBalls; i++) {
    xPos.push(random(width));
    yPos.push(random(height));
    speedX.push(random(-3, 3));
    speedY.push(random(-3, 3));
    sizes.push(random(15, 45));
  }
}

function drawBall(x, y, size, index) {
  colorMode(HSB, 360, 100, 100);
  fill(index * 36, 80, 90);  // 인덱스마다 다른 색상!
  noStroke();
  ellipse(x, y, size, size);
  colorMode(RGB);
}

function moveBall(index) {
  // 5주차의 x += speedX 를 배열 버전으로!
  xPos[index] += speedX[index];
  yPos[index] += speedY[index];

  // 벽 바운싱도 배열 버전으로
  let r = sizes[index] / 2;
  if (xPos[index] > width - r || xPos[index] < r) {
    speedX[index] *= -1;
  }
  if (yPos[index] > height - r || yPos[index] < r) {
    speedY[index] *= -1;
  }
}

function draw() {
  background(20);
  for (let i = 0; i < numBalls; i++) {
    moveBall(i);
    drawBall(xPos[i], yPos[i], sizes[i], i);
  }
}

이 코드에서 numBalls를 10에서 100으로 바꿔보세요. 코드 다른 곳은 하나도 안 바꿔도 공 100개가 돌아다닙니다.

마우스 클릭으로 공 추가하기 — push() 활용

function mousePressed() {
  xPos.push(mouseX);          // 클릭한 x좌표
  yPos.push(mouseY);          // 클릭한 y좌표
  speedX.push(random(-3, 3)); // 랜덤 속도
  speedY.push(random(-3, 3));
  sizes.push(random(15, 50)); // 랜덤 크기
  numBalls++;                 // 공 개수 1 증가
}

모든 배열에 push()로 새 데이터를 추가하면, 다음 draw()에서 for문이 새 공까지 자동으로 그려줍니다. .length가 자동으로 바뀌니까요.


정리

2교시 핵심 요약
  1. 배열은 같은 종류의 데이터를 번호(인덱스)로 관리하는 서랍장 — 0번부터 시작!
  2. 배열 + for문으로 데이터 100개든 1000개든 반복 처리할 수 있다
  3. 배열 + for문 + 함수 = 다수의 오브젝트를 한 번에 관리하는 핵심 패턴

3교시 실습 안내

3교시에는 함수와 배열을 결합해서 움직이는 공 여러 개 스케치를 만듭니다.

기대 결과물 - 최소 10개의 공이 화면 안에서 각각 독립적으로 움직인다 - 각 공은 벽에 부딪히면 튕긴다 - 공마다 크기와 색상이 다르다 - (선택) 마우스 클릭으로 새 공을 추가할 수 있다

먼저 drawBall() 함수부터 만들고, 배열을 선언하고, setup()에서 데이터를 채우고, draw()에서 반복문으로 돌리면 됩니다.

7주차 예고

실습하면서 느끼겠지만, 공 하나의 데이터가 x배열, y배열, speedX배열처럼 여러 배열에 흩어져 있습니다. 이 불편함이 다음 주에 배울 class의 출발점입니다. class를 쓰면 공 하나의 모든 데이터를 하나로 묶을 수 있습니다.