๐ŸŽ“ 4์ฃผ์ฐจ: ๋ฒกํ„ฐ์™€ ํž˜ (Vector & Force)

BamgasiJMยท2025๋…„ 11์›” 4์ผ

p5.js Art

๋ชฉ๋ก ๋ณด๊ธฐ
15/67
post-thumbnail

๋ฒกํ„ฐ ์‹œ๊ฐํ™” (Vector Visualization)

let center, mouse;

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

function draw() {
  background(25);
  center = createVector(width / 2, height / 2);
  mouse = createVector(mouseX, mouseY);
  let dir = p5.Vector.sub(mouse, center);

  // ๋ฒกํ„ฐ ๊ทธ๋ฆฌ๊ธฐ
  stroke(10, 180, 170);
  fill(0);
  translate(center.x, center.y);
  line(0, 0, dir.x, dir.y);

  // ๋์— ํ™”์‚ดํ‘œ
  push();
  translate(dir.x, dir.y);
  rotate(dir.heading());
  let arrowSize = 20;
  translate(-arrowSize, 0);
  triangle(0, 2, 0, -2, arrowSize, 0);
  pop();

  noStroke();
  fill(255, 255, 255);
  text("๋ฒกํ„ฐ ๊ธธ์ด: " + nf(dir.mag(), 1, 2), -50, -20);
}

๐Ÿ“˜ ๊ฐœ๋…: ๋‘ ์  ๊ฐ„์˜ ๋ฒกํ„ฐ, ๋ฐฉํ–ฅ(heading()), ํฌ๊ธฐ(mag()).

๋ฒกํ„ฐ ์ •๊ทœํ™”์™€ ์†๋„ ๋ฒกํ„ฐ (Normalization and velocity)

let pos, vel;

function setup() {
  createCanvas(800, 200);
  pos = createVector(100, 200);
  vel = createVector(2, -1);
}

function draw() {
  background(25);
  pos.add(vel);
  
  // ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด ๋ฐ˜์ „
  if (pos.x > width || pos.x < 0) vel.x *= -1;
  if (pos.y > height || pos.y < 0) vel.y *= -1;

  fill(10, 190, 180, 255);
  ellipse(pos.x, pos.y, 20, 20);

  // ์†๋„ ๋ฒกํ„ฐ ๊ทธ๋ฆฌ๊ธฐ
  stroke(10, 190, 180, 255);
  strokeWeight(3);
  line(pos.x, pos.y, pos.x + vel.x * 10, pos.y + vel.y * 10);
}

๐Ÿ“˜ ๊ฐœ๋…: p5.Vector.add(), ์†๋„ ๋ฒกํ„ฐ, ํ™”๋ฉด ๋ฐ˜์‚ฌ.

ํž˜ ์ ์šฉ: ์ค‘๋ ฅ๊ณผ ๋งˆ์ฐฐ (Force: Gravity and Friction)

let mover;

function setup() {
  createCanvas(800, 400);
  mover = new Mover();
}

function draw() {
  background(25);

  let gravity = createVector(0, 0.1);
  mover.applyForce(gravity);

  // ๋ฐ”๋‹ฅ ๊ทผ์ฒ˜์ผ ๋•Œ ๋งˆ์ฐฐ๋ ฅ
  if (mover.pos.y > height - 20) {
    let friction = mover.vel.copy();
    friction.normalize();
    friction.mult(-0.1);
    mover.applyForce(friction);
  }

  mover.update();
  mover.edges();
  mover.display();
}

class Mover {
  constructor() {
    this.pos = createVector(width / 2, 0);
    this.vel = createVector(0, 0);
    this.acc = createVector(0, 0);
    this.mass = 1;
  }

  applyForce(force) {
    let f = p5.Vector.div(force, this.mass);
    this.acc.add(f);
  }

  update() {
    this.vel.add(this.acc);
    this.pos.add(this.vel);
    this.acc.mult(0);
  }

  edges() {
    if (this.pos.y > height - 25) {
      this.pos.y = height - 25;
      this.vel.y *= -0.7; // ๋ฐ˜๋™
    }
  }

  display() {
    fill(10, 190, 180);
    ellipse(this.pos.x, this.pos.y, 50, 50);
  }
}

๐Ÿ“˜ ๊ฐœ๋…: ๋‰ดํ„ด์˜ ์ œ2๋ฒ•์น™ F = ma, ์ค‘๋ ฅ๊ณผ ๋งˆ์ฐฐ๋ ฅ์˜ ํ•ฉ์‚ฐ, ๋ฐ˜๋™ ์‹œ๋ฎฌ๋ ˆ์ด์…˜.

ํž˜ ์ ์šฉ : ๋ฐ”๋žŒ + ์ค‘๋ ฅ (Force: Wind + Gravity)

let movers = [];

function setup() {
  createCanvas(800, 400);
  for (let i = 0; i < 40; i++) {
    movers.push(new Mover(random(width), random(height)));
  }
}

function draw() {
  background(25, 25, 25, 50);

  let wind = createVector(0.02, 0.02);
  let gravity = createVector(0, 0.01);

  for (let m of movers) {
    if (mouseIsPressed) m.applyForce(wind);
    m.applyForce(gravity);
    m.update();
    m.edges();
    m.display();
  }

  fill(255);
  noStroke();
  text("Click to blow the wind โ†’", 10, 20);
}

class Mover {
  constructor(x, y) {
    this.pos = createVector(x, y);
    this.vel = createVector(0, 0);
    this.acc = createVector(0, 0);
    this.mass = random(0.5, 2);
  }

  applyForce(force) {
    let f = p5.Vector.div(force, this.mass);
    this.acc.add(f);
  }

  update() {
    this.vel.add(this.acc);
    this.pos.add(this.vel);
    this.acc.mult(0);
  }

  edges() {
    if (this.pos.y > height - 10) {
      this.pos.y = height - 10;
      this.vel.y *= -0.8;
    }
  }

  display() {
    fill(10, 190, 180, 200);
    ellipse(this.pos.x, this.pos.y, this.mass * 16, this.mass * 16);
  }
}

๐Ÿ“˜ ๊ฐœ๋…: ์—ฌ๋Ÿฌ ๊ฐ์ฒด์— ํž˜ ์ ์šฉ, ์งˆ๋Ÿ‰์— ๋”ฐ๋ฅธ ๊ฐ€์†๋„ ์ฐจ์ด, ๋ฐ”๋žŒ๊ณผ ์ค‘๋ ฅ์˜ ์ƒํ˜ธ์ž‘์šฉ.

๋Œ์–ด๋‹น๊ธฐ๊ธฐ (Attraction Force)

๋งˆ์šฐ์Šค๊ฐ€ ์บ”๋ฒ„์Šค ์˜์—ญ์„ ๋ฒ—์–ด๋‚˜๋ฉด ํŒŒํ‹ฐํด๋“ค์ด ์ž์œ ๋กญ๊ฒŒ ์›€์ง์ด๊ณ , ๋‹ค์‹œ ๋“ค์–ด์˜ค๋ฉด ๋งˆ์šฐ์Šค ์œ„์น˜๋กœ ๋Œ๋ ค๊ฐ‘๋‹ˆ๋‹ค. ๋งˆ์šฐ์Šค ํด๋ฆญ ์—†์ด ์œ„์น˜๋งŒ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

    let movers = [];
    const numMovers = 20;

    function setup() {
      createCanvas(800, 400);
      
      for (let i = 0; i < numMovers; i++) {
        movers.push(new Mover(random(width), random(height)));
      }
    }

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

      let isMouseInside = mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height;
      
      for (let mover of movers) {
        if (isMouseInside) {
          let mouse = createVector(mouseX, mouseY);
          let dir = p5.Vector.sub(mouse, mover.pos);
          let d = constrain(dir.mag(), 5, 25);
          dir.normalize();
          let strength = (200 * mover.mass) / (d * d);
          dir.mult(strength);
          mover.applyForce(dir);
        }
        
        mover.update();
        mover.edges();
        mover.display();
      }

      noStroke();
      fill(255);
      text("Move mouse to attract particles", 10, 20);
    }

    class Mover {
      constructor(x, y) {
        this.pos = createVector(x, y);
        this.vel = createVector(0, 0);
        this.acc = createVector(0, 0);
        this.size = random(5, 15);
        this.mass = this.size / 10;
      }

      applyForce(f) {
        let force = p5.Vector.div(f, this.mass);
        this.acc.add(force);
      }

      update() {
        this.vel.add(this.acc);
        this.vel.mult(0.85);
        this.pos.add(this.vel);
        this.acc.mult(0);
      }

      edges() {
        if (this.pos.x > width) this.pos.x = 0;
        if (this.pos.x < 0) this.pos.x = width;
        if (this.pos.y > height) this.pos.y = 0;
        if (this.pos.y < 0) this.pos.y = height;
      }

      display() {
        fill(10, 180, 170);
        ellipse(this.pos.x, this.pos.y, this.size, this.size);
      }
    }

๐Ÿ“˜ ๊ฐœ๋…: ๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ˜ ํž˜ (Gravitational Attraction), 1 / dยฒ ๋ฒ•์น™, ๋งˆ์šฐ์Šค ์ธํ„ฐ๋ž™์…˜.


profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€