My Boundary As Much As I Experienced

Nature of Code 1. 벡터 이해하기 (p5.js) 본문

Interactive(HTML Canvas ・three.js ・game)/CSS・Canvas ・ p5.js ・ Pixi.js

Nature of Code 1. 벡터 이해하기 (p5.js)

Bumang 2024. 5. 21. 21:59

벡터란 무엇일까...? 이번에 공부해봤지만 잘 모르겠다.

(이과들만 배우는 과목이었나, 기하와 벡터가? 교육과정도 다 까묵음)

 

하여튼 이번 Nature of Code에서 벡터를 이해하기 위해 여러가지 영상을 봤는데

그나마 가장 이해 잘 되는 영상은 아래였다. (그나마)

https://www.youtube.com/watch?v=ArgTeYVuJUo&t=297s

 

 

벡터가 뭔가요-? !

벡터는 크기와 방향을 갖는거라고 한다. 사실 이렇게만 말하면 너무 추상적이다.

물리학이나 순수 수학이나 컴퓨터 과학 모두에서 벡터를 되게 각자의 방식으로 정의하는거 같다.

이렇게 방대한 개념을 다 이해하기는 힘들거 같고, 컴퓨터 과학에서 벡터를 어떻게 쓰는지만 알아보았다.

대강 Origin 좌표(대게 0,0)에서 임의의 점(예를 들어 3, 4)까지 화살표를 그어놓은게 벡터라는 의미로 받아들였다.

0,0과 3,4를 각각 말하자면 스칼라(크기만 있음)라고 말할 수 있고,

좌표상에서 0.0에서 3,4로 이동하는 화살표를 그려놓은 꼴이 벡터라고 하는 것이다.

 

하여튼 이렇게 벡터가 뭔지 많이 고민했었는데

p5.js에서 vector를 써보니 조금 구체적으로 어떤 쓰임이 있는지 알거같다.

일단은 이 단원에서 사용한 예제들을 여럿 보여주겠다.

 

예제 모음

 

아래는 벡터 함수를 사용하지 않고 공의 이동을 구현한 코드이다. 좌표값이 벽에 닿으면 -1을 곱해 방향을 바꿔준다.

만약 천장이나 바닥에 부딪히면 y값에 -1을 곱해주고, 왼쪽이나 오른쪽 벽에 부딪히면 x값에 -1을 곱해준다.

// 공의 위치와 속도에 대한 변수
let x = 100;
let y = 100;
let xspeed = 5;
let yspeed = 2;
let radious = 24;

function setup() {
  createCanvas(640, 240);
}

function draw() {
  background(50);

  // 속도에 따라 공을 움직인다.
  x = x + xspeed;
  y = y + yspeed;

  충돌 시 -1을 곱해 방향을 바꿔준다.
  if (x + radious > width || x - radious < 0) {
    xspeed = xspeed * -1;
  }
  if (y + radious > height || y - radious < 0) {
    yspeed = yspeed * -1;
  }

  stroke(0);
  fill(127);
  circle(x, y, radious * 2);
}

 

위 예제는 벡터를 사용하지 않고 물체의 이동을 어떻게 구현하는지에 대한 코드여서

강좌에서도 짧게 보고 넘어가는 코드였지만

나는 여기서 시간이 지남에 따라 마찰력으로 속력이 줄어드는 것을 표현하고 싶었다.

 

그래서 내가 만들어낸 코드는 아래와 같다.

setInterval로 속도가 +방향이든 -방향이든 절대값을 계속 줄어들게 하여 느리게 만들고 결국 정지하게 만들었다.

 

사실 충돌할 시에도 추가적으로 감속을 넣게 만들려고 했는데 이는 실패했다.

충돌하는 순간 내가 원하지 않게 벽을 파고들거나

에러가 난듯 원이 바들바들 떨면서 괴상한 움직임을 내기도 했다ㅠㅠ

 

원인으로 짐작가는 것은 draw함수가 1초에 60번 프레임이 도는데

벽에 닺는 순간이 딱 1프레임이 아니라 여러번 충돌체크가 나서 감속이 계속 되는게 아닐까? 싶기도 하다.

나중에 이 문제원인을 더 찾아봐야겠다.


// 공의 위치와 속도에 대한 변수
let x = 100;
let y = 100;
let xspeed = 5;
let yspeed = 2;
let radious = 24;

// setInterval로 1초마다 감속을 시킴
setInterval(() => {
  // x든 y든 절대값이 0.2 이하면 그냥 멈추게 했다.
  if (Math.abs(xspeed) < 0.2 || Math.abs(yspeed) < 0.2) {
    xspeed = 0;
    yspeed = 0;
    return;
  }
  // +방향으로 속도가 있다면 마이너스를 해주고
  if (xspeed > 0) {
    xspeed = xspeed - 0.1 === 0 ? 0 : xspeed - 0.1;
  // -방향으로 속도가 있다면 플러스를 해준다.
  } else {
    xspeed = xspeed + 0.1 === 0 ? 0 : xspeed + 0.1;
  }
  // y축도 똑같다.
  if (yspeed > 0) {
    yspeed = yspeed - 0.1 === 0 ? 0 : yspeed - 0.1;
  } else {
    yspeed = yspeed + 0.1 === 0 ? 0 : yspeed + 0.1;
  }
}, 1000);

function setup() {
  createCanvas(640, 240);
}

function draw() {
  background(50);

  // 속도에 따라 공을 움직입니다.
  x = x + xspeed;
  y = y + yspeed;

  // 벽에 부딪히면 방향을 바꾸는 코드는 동일하다.
  if (x + radious > width || x - radious < 0) {
    xspeed = xspeed * -1;
    console.log("Xhit!");
  }
  if (y + radious > height || y - radious < 0) {
    yspeed = yspeed * -1;
    console.log("Yhit!");
  }

  stroke(0);
  fill(127);
  circle(x, y, radious * 2);
}

 

 

 

랜덤 워커 예제

이제 실제로 벡터를 사용한 표현해보는 예제이다.

createVector라는 좌표와 origin을 설정하는 p5.js 내장 생성자 함수를 이용하여

positionX와 positionY를 계속 조작하는 예제이다.

생성자 함수의 결과로 반환된 객체의 x, y값을 바꾸고 계속 업데이트해주는 예제이다.

let pos;

function setup() {
  createCanvas(400, 400);
  
  pos = createVector(width/2, height/2);
  background(0);
}

function draw() {
  // 선의 색상을 지정
  stroke(255, 100);
  // 선의 두께를 지정
  strokeWeight(2);
  // (변화하는 x와 y를 이용해) 포인트를 찍음
  point(pos.x, pos.y);
  // 현재 pos.x pos.y값에 난수로 만든 좌표를 더해서 랜덤 발생
  pos.x = pos.x + random(-1, 1);
  pos.y = pos.y + random(-1, 1);
}

 

 

클래스를 이용하여 모듈화한 코드는 아래와 같다. (이건 예제 그대로)

class Walker {
  constructor(x, y) {
    this.pos = createVector(x, y);
  }

  update() {
    this.pos.x = this.pos.x + random(-1, 1);
    this.pos.y = this.pos.y + random(-1, 1);
  }

  show() {
    stroke(255, 100);
    strokeWeight(2);
    point(this.pos.x, this.pos.y);
  }
}

let walker;

function setup() {
  createCanvas(400, 400);
  walker = new Walker(200, 200);
  background(0);
}

function draw() {
  walker.update();
  walker.show();
}