๋ดํด์ ์ด๋ ๋ฒ์น
๋ฒกํฐ(vector)์ฒ๋ผ, ํ(force)์ ๋ค์ํ ์๋ฏธ๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ํ์ ์ด๋ค ๊ฐ๋ ฅํ ๋ฌผ๋ฆฌ๋ ฅ, ์ด๋ฅผํ ๋ฉด, ๋ฐ์๋ฅผ ํฐ ํ์ผ๋ก ๋ฏธ๋ ๊ฒ์ ์๋ฏธํ๋ ๊ฐ๋ ์ด ๋ ์ ์๋ค. ์ฌ๊ธฐ์ ๋ค๋ฃฐ ํ ์ ์ ์๋ ๋ฌผ๋ฆฌํ์์ ๋ฐฐ์ฐ๋ ํ์ด๊ณ , ์์ด์ ๋ดํด(Isaac Newton)์ ์ด๋์ ๋ฒ์น์์ ๋น๋กฏ๋ ๊ฐ๋ ์ด๋ค.
ํ์ ์ง๋์ ์ง๋ ๋ฌผ์ฒด๋ฅผ ๊ฐ์ํ๋ ๋ฒกํฐ๋ค.
๋ดํด์ ์ 1๋ฒ์น
๋ดํด์ ์ 1๋ฒ์น์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ๋ค.
์์ง์ด์ง ์๋ ๋ฌผ์ฒด๋ ๊ณ์ ์์ง์ด์ง ์์ผ๋ ค ํ๊ณ ์์ง์ด๋ ๋ฌผ์ฒด๋ ๋ถ๊ท ํ๋ ฅ์ด ๊ฐํด์ง์ง ์๋ ํ ์ผ์ ํ ์๋์ ๋ฐฉํฅ์ผ๋ก ๊ณ์ ์์ง์ด๋ ค ํ๋ค.
์ ์ด์ ํ์ด ์์ ์์ผ๋ฉด ๋ฌผ์ฒด๊ฐ ๊ณ์ ์์ง์ด๊ฒ ํ๋ ๋ฐ ์ด๋ ํ ํ๋ ํ์ํ์ง ์๋ค. ์ง๊ตฌ ๋๊ธฐ๊ถ์ ๋์ ธ์ง (๊ณต๊ณผ ๊ฐ์) ๋ฌผ์ฒด๋ ๊ณต๊ธฐ ์ ํญ(ํ) ๋๋ฌธ์ ์ ์ฐจ ๋๋ ค์ง๋ค.
ํ์ด ์๊ฑฐ๋ ๋ฌผ์ฒด์ ๊ฐํด์ง๋ ํ์ด ์๋ก ์์๋๋ฉด ์ฆ, ์์ง ํ์ด ๊ฒฐ๊ตญ 0์ด ๋๋ฉด ๋ฌผ์ฒด์ ์๋๋ ์ผ์ ํ๊ฒ ์ ์ง๋๋ค. ์ด๊ฒ์ ํํ(equilibrium)์ด๋ผ ํ๋ค. ์ผ๋จ ๊ณต๊ธฐ ์ ํญ๋ ฅ์ด ์ค๋ ฅ๊ณผ ๊ฐ์์ง๋ฉด ๋จ์ด์ง๋ ๊ณต์ (์ผ์ ํ๊ฒ ์ ์ง๋๋) ์ข ๋จ ์๋์ ๋๋ฌํ๊ฒ ๋ ๊ฒ์ด๋ค.
ProcessingJS ์ธ๊ณ์์ ๋ดํด์ ์ 1๋ฒ์น์ ๋ค์๊ณผ ๊ฐ์ด ๋ค์ ๊ธฐ์ ํ ์ ์๋ค.
๊ฐ์ฒด์PVector ์๋๋ ํํ์ ์ํ์ ์๋ ๊ฒฝ์ฐ ์ผ์ ํ๊ฒ ์ ์ง๋๋ค.
๋ดํด์ ์ 3๋ฒ์น
์ด ๋ฒ์น์ ์ข ์ข ๋ค์๊ณผ ๊ฐ์ด ๊ธฐ์ ๋๋ค.
๋ชจ๋ ์์ฉ์ ๋ฐ๋๋ฐฉํฅ์ผ๋ก ๋๊ฐ์ ํ์ ๊ฐ์ง๋ ๋ฐ์์ฉ์ด ์๋ค.
๋ฒฝ์ ๋ฏผ๋ค๊ณ ๊ฐ์ ํด ๋ณด์. ๋ฒฝ์ ์ ๊ทน์ ์ผ๋ก ์ฐ๋ฆฌ๋ฅผ ๋ฐ๋๋ก ๋ฐ์ง๋ ์๋๋ค. ๋ฒฝ์ ์ฐ๋ฆฌ๋ฅผ ๋ฐ๋ง ํ ๊ทผ์์ด ๋๋ ํ์ ๊ฐ๊ณ ์์ง ์๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ์ ๋ฏธ๋ ํ์๋ “์์ฉ/๋ฐ์์ฉ์ด ์”์ด ๋๋ ๋ ๊ฐ์ ํ์ด ํฌํจ๋๋ค.
ํ์ ํญ์ ์์ผ๋ก ๋ฐ์ํ๋ค. ๋ ํ์ ์ธ๊ธฐ๊ฐ ๊ฐ์ง๋ง ๋ฐฉํฅ์ ๋ฐ๋๋ค.
๋ดํด์ ์ 3 ๋ฒ์น์ ProcessingJS์ ๋ง๊ฒ ๋ค์ ๊ธฐ์ ํ๋ฉด ์๋์ ๊ฐ๋ค.
๋ฌผ์ฒด B์ ๋ํ ๋ฌผ์ฒด A์ ํ์ธ PVector f ๋ฅผ ๊ณ์ฐํ๋ค๋ฉด ๋ฐ๋์ ๋ฌผ์ฒด B๊ฐ ๋ฌผ์ฒด A์ ๊ฐํ๋ ํ์ธ PVector.mult(f,-1);๋ ์ ์ฉํด์ผ ํ๋ค.
๋์ค์ ProcessingJS ํ๋ก๊ทธ๋๋ฐ ์ธ๊ณ์์ ํญ์ ์ ๋ฒ์น์ ๋ฐ๋ฅผ ํ์๋ ์๋ค๋ ์ฌ์ค์ ์๊ฒ ๋ ๊ฒ์ด๋ค. ์ ๋ฐํ๊ฒ ๋ชจ๋ ๊ฒ์ ์๋ฒฝํ ์๋ฎฌ๋ ์ด์ ์ ํ๋ ๊ฒ์ด ์๋๋ผ ๋จ์ง ์์ฐ๊ณ์ ๋ฌผ๋ฆฌ ํ์์์ ์๊ฐ์ ์ป๋๋ค๋ ์ฌ์ค์ ๊ธฐ์ตํ์.
๋ดํด์ ์ 2๋ฒ์น
์ ํต์ ์ผ๋ก ์ด ๊ท์น์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ๋ค.
ํ์ ์ง๋ ๊ณฑํ๊ธฐ ๊ฐ์๋์ด๋ค.
์ฆ ๊ฐ์๋๋ ํ๊ณผ ๋น๋กํ๊ณ ์ง๋์ ๋ฐ๋น๋กํ๋ค.
์ฌ๊ธฐ์ ๋ฌผ์ฒด์ ์ง๋์ ๋ฌผ์ฒด์ ํฌํจ๋์ด ์๋ ๋ฌผ์ง์ ์์ด๋ค. ๋ฌด๊ฒ๋ ๋ฌผ์ฒด์ ์์ฉํ๋ ์ค๋ ฅ์ ํ์ ๋งํ๋ค.
๋ดํด์ ์ 2 ๋ฒ์น์ ๋ฐ๋ผ ์ง๋ ๊ณฑํ๊ธฐ ์ค๋ ฅ ๊ฐ์๋ (w = m * g)๋ฅผ ํตํด ๋ฌด๊ฒ๋ฅผ ๊ณ์ฐํ ์ ์๋ค. ๋ฐ๋๋ ์ง๋์ ๋จ์ ๋ถํผ๋ก ๋๋ ๊ฐ์ผ๋ก ์ ์ํ๋ค.
์ง๊ตฌ์์ ์ง๋์ด 1 kg์ธ ๋ฌผ์ฒด๋ ๋ฌ์์๋ ์ง๋์ด 1 kg๋ค. ๊ทธ๋ฌ๋ ๋ฌด๊ฒ๋ 1/6๋ก ์ค์ด๋ ๋ค.
์ด์ ProcessingJS์ ์ธ๊ณ์์ ์ง๋์ ๋ฌด์์ผ๊น? ๊ฐ๋จํ ํ๊ธฐ ์ํด ์์์ ํฝ์ ์ธ๊ณ์์ ๋ชจ๋ ๋ฌผ์ฒด๋ค์ ์ง๋์ 1์ด๋ผ๊ณ ํ์. F/1 = F์ด๋ค. ๋ฐ๋ผ์, ๋ค์์ด ์ฑ๋ฆฝํ๋ค.
๋ฌผ์ฒด์ ๊ฐ์๋๋ ํ๊ณผ ๊ฐ๋ค.
Mover ๊ฐ์ฒด๋ฅผ ๋ง๋ค ๋ ๋ฐฐ์ ๋ ๊ฒ์ฒ๋ผ ํ์ฌ ์์น, ์๋, ๊ฐ์๋๋ฅผ ๊ฐ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋ณด์. ์ง๊ธ ๋ชฉํ๋ ์ด ๊ฐ์ฒด์ ํ์ ๋ถ์ฌํ๋ ๊ฒ์ด๋ค.
mover.applyForce(wind);
// or
mover.applyForce(gravity);
์ด๋, ๋ฐ๋๊ณผ ์ค๋ ฅ์ PVector์ด๋ค. ๋ดํด์ ์ 2๋ฒ์น์ ๋ฐ๋ผ ์ด ํจ์๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ ์ ์๋ค.
Mover.prototype.applyForce = function(force) {
this.acceleration = force;
};
ํ์ ์ถ์
applyForce()๋ ๋ดํด์ ์ 2 ๋ฒ์น์ ์ ์ ๊ทธ๋๋ก ํด์ํ ๊ฒ์ด๋ค. ๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์๋ ๊ฝค ํฐ ๋ฌธ์ ๊ฐ ์๋ค. ์ง๊ธ ์ด๋ฃจ๊ณ ์ ํ๋ ๋ชฉํ๋ ํ๋ฉด์์์ ๋ฐ๋๊ณผ ์ค๋ ฅ์ ์ํด ์์ง์ด๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค.
mover.applyForce(wind);
mover.applyForce(gravity);
์์ ๊ฐ์ด ํธ์ถํ๋ค๋ฉด Mover ๊ฐ์ฒด์ ๊ฐ์๋๋ ์ค๋ ฅ PVector๋ก ์ค์ ๋๋ค. ํ ๋ฒ ์ด์ applyForce()์ ํธ์ถํ๋ฉด ์ด์ ํธ์ถ์ ๋ฌด์ํ๊ณ ๋ฎ์ด์ฐ๊ฒ ๋๋ค. ํ๋ ์ด์์ ํ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํด์ผ ํ ๊น?
๋ดํด์ ์ 2 ๋ฒ์น์ ์ข ๋ ์ ํํ๊ฒ ์ ์ํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
์์ง ํ์ ์ง๋ ๊ณฑํ๊ธฐ ๊ฐ์๋์ ๊ฐ๋ค.
์ด๋ ๊ฐ์๋๊ฐ ํ์ ์ด๋ ์ ์ง๋์ผ๋ก ๋๋ ๊ฐ๊ณผ ๊ฐ๋ค๋ ๋ง๊ณผ ๊ฐ๋ค. ๊ฒฐ๊ตญ ๋ดํด์ ์ 1๋ฒ์น๊ณผ ๊ฐ์ด, ๋ชจ๋ ํ์ ํฉ์ด 0์ด ๋๋ฉด ๋ฌผ์ฒด๋ ํํ ์ํ(๊ฐ์๋๊ฐ ์กด์ฌํ์ง ์๋ ์ํ)๊ฐ ๋๋ค. ํ๋ก๊ทธ๋๋ฐ์์๋ ํ์ ์ถ์ ์ด๋ผ๊ณ ์๋ ค์ง ํ๋ก์ธ์ค๋ฅผ ํตํด ์ด๋ฅผ ๊ตฌํํ ์ ์๋ค. ์ด๋ ์ค์ ๋ก ๋งค์ฐ ๊ฐ๋จํด์, ๋จ์ง ๋ชจ๋ ํ์ ๋ํ๋ฉด ๋๋ค.
์ด์ applyForce() ๋ฉ์๋๋ฅผ ๋ณ๊ฒฝํ์ฌ ํ์ ์ถ์ ํ๋ฉด์ ๊ฐ์๋์ ์๋ก์ด ํ์ ๋ํด๋ณด์.
Mover.prototype.applyForce = function(force) {
this.acceleration.add(force);
};
ํ์ ์ถ์ ์ ๊ตฌํํ๊ธฐ ์ํด ํ ๊ฐ์ง๋ฅผ ๋ ํด์ผ ํ๋ค. ๊ณ์ํด์ ๋ชจ๋ ํ์ ๋ํด์ผ ํ๋ฏ๋ก, ๋งค๋ฒ update()๊ฐ ํธ์ถ๋๊ธฐ ์ ์ ํ์คํ๊ฒ ๊ฐ์๋๋ฅผ ์์ ์ผ (๊ฐ์๋๋ฅผ 0์ผ๋ก ์ค์ )ํ๋ค.
๊ฐ ํ๋ ์์ ๋ํด ๊ฐ์๋๋ฅผ ์์ ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ update()์ ๋ง์ง๋ง PVector์ 0์ ๊ณฑํ๋ ๊ฒ์ด๋ค.
Mover.prototype.update = function() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.acceleration.mult(0);
};
์ง๋
๋ดํด์ ์ 2 ๋ฒ์น์ ์ค์ ๋ก A = F ๊ฐ ์๋ F = MA ๋ค. ์ง๋์ ๋ถ์ฌํ๋ ๊ฒ์ ๊ฐ์ฒด์ ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ๋งํผ ์ฝ๋ค.
์ง๋์ ๋ํด ์๊ฐํ๊ธฐ ์์ํ์ผ๋ ์ธก์ ๋จ์๋ฅผ ์ง๊ณ ๋์ด๊ฐ๋ ๊ฒ์ด ์ค์ํ๋ค. ์ฌ๊ธฐ์๋ ๋จ์๋ก ํฝ์ ๊ณผ ํ๋ ์์ ์ฌ์ฉํ๋ค.
(ํธ์๋ฅผ ์ํด ๋ฌผ์ฒด์ ์ง๋๊ณผ ํฌ๊ธฐ๋ฅผ ๋ฌถ๋๋ก ํ๋ค. ๋ฌผ์ฒด์ ์ง๋์ด 10์ด๋ฉด ๋ฐ์ง๋ฆ์ด 10์ธ ์์ ๊ทธ๋ฆฌ๋ ์์ด๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ฌผ์ฒด์ ์ง๋์ ์๊ฐํํ์ฌ ํ๋ก๊ทธ๋จ์์ ์ง๋์ด ์ผ๊ธฐํ๋ ํจ๊ณผ๋ฅผ ๊ด์ฐฐํ ์ ์๋ค.)
์ง๋์ ๋ฒกํฐ๊ฐ ์๋๋ผ ์ค์นผ๋ผ(๋ถ๋ ์์์ )์ด๋ค. ์ง๋์ ์ด๋ค ๋ฌผ์ฒด๋ฅผ ๊ตฌ์ฑํ๋ ๋ฌผ์ง์ ์์ ๋ํ๋ด๋ ์๋ค. ๋ฌผ์ฒด์ ๋ฉด์ ์ ์ง๋์ผ๋ก ๊ณ์ฐํ ์๋ ์์ง๋ง ๋ฌผ์ฒด์ ์ง๋์ 10์ด๋ผ๊ณ ์ ํ๋ฉด ํ๋ก๊ทธ๋จ์ด ๊ฐ๋จํด์ง๋ค.
const Mover = function() {
this.mass = 10;
this.position = new PVector(random(width), random(height));
this.velocity = new PVector(0, 0);
this.acceleration = new PVector(0, 0);
};
์ง๋์ ๋ดํด์ ์ 2๋ฒ์น์ ๊ฐ์ฒด์ ์ ์ฉํ ๋ ์ด์ฉํ๋ค. ์ฌ๊ธฐ์ ์ฌ๋ฌ ๊ฐ์ Mover ๊ฐ์ฒด๊ฐ ์๋ ์๋๋ฆฌ์ค๋ฅผ ์ํด ์ฃผ์ํ ์ ์ด ์๋ค. JavaScript์์ PVector ๊ฐ์ ๊ฐ์ฒด์ ํ ๋น๋ ๋ณ์๋ ์ฌ์ค ๋ฉ๋ชจ๋ฆฌ์ ์๋ ๊ฐ์ฒด์ ํฌ์ธํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ํจ์์ ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๋ฉด, ๋ณต์ฌ๋ณธ์ ์ ๋ฌํ๋ ๊ฒ์ด ์๋๋ผ ๊ธฐ์กด์ ํฌ์ธํฐ๋ฅผ ์ ๋ฌํ๊ฒ ๋๋ค. ๋ฐ๋ผ์ ํจ์๊ฐ ๊ฐ์ฒด๋ฅผ ์์ ํ๋ฉด(์ง๋์ผ๋ก ๋๋๋ ๊ฒ์ฒ๋ผ) ๊ทธ ๊ฐ์ฒด๋ ์๊ตฌ์ ์ผ๋ก ๋ฐ๋๋ค. ๋ฐ๋ผ์ ์ง๋์ผ๋ก ๋๋๊ธฐ ์ ์ PVector f๋ฅผ ๋ณต์ฌํด ๋์์ผ ํ๋ค.
Mover.prototype.applyForce = function(force) {
const f = force.copy();
force.div(this.mass);
this.acceleration.add(f);
};
๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก๋, ์ด์ ๋จ์์์ ๋ฐฐ์ด ์ ์ ํจ์๋ฅผ ์ด์ฉํ์ฌ ์ ์ div() ํจ์๋ฅผ ์ฌ์ฉํด ๋ฉ์๋๋ฅผ ๋ค์ ์ธ ์ ์๋ค.
Mover.prototype.applyForce = function(force) {
const f = PVector.div(force, this.mass);
this.acceleration.add(f);
};
์ฌ๊ธฐ์์ ์ค์ํ ๊ฒ์, ์ฌ๋ฌ ๊ฐ์ Mover ๊ฐ์ฒด๋ค์ ์ ์ฉํ ์ ์๋๋ก ๊ธฐ์กด ํ ๋ฒกํฐ์ ์ํฅ์ ์ฃผ์ง ์๋ ๋ฐฉ๋ฒ์ ์ฐพ์์ผ ํ๋ค๋ ์ ์ด๋ค.
ํ์ ์์ฑ
ํ์ ๋ง๋๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ๊ทธ๋ฅ ์ซ์๋ฅผ ์ ํํ๋ ๊ฒ์ด๋ค.
const wind = new PVector(0.01, 0);
const gravity = new PVector(0, 0.1);
mover.applyForce(wind);
mover.applyForce(gravity);
์ด์ ์๋ก ๋ค๋ฅธ ํฌ๊ธฐ์ ๋ฐฉํฅ์ ๊ฐ๋ ๋ ๊ฐ์ ํ(๋ฐ๋๊ณผ ์ค๋ ฅ)์ด ์๋ค. ๋ ๊ฐ์ฒด ๋ชจ๋ mover๊ฐ์ฒด์ ์ ์ฉํ๋ค.
๋ชจ๋ ์ฝ๋๋ฅผ ๋ค ๊ฒฐํฉํ ํ๋ก๊ทธ๋จ์ ๋ค์๊ณผ ๊ฐ๋ค.
<canvas id="myCanvas" width="300" height="250" style="border: 1px solid #000;"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');
const PVector = function(x, y) {
this.x = x;
this.y = y;
};
PVector.prototype.add = function(v) {
this.y = this.y + v.y;
this.x = this.x + v.x;
};
PVector.prototype.mult = function(n) {
this.x = this.x * n;
this.y = this.y * n;
};
// ๋ฒกํฐ๋ฅผ ๋ณต์ฌํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ๋ฉ์๋
PVector.prototype.copy = function() {
return new PVector(this.x, this.y);
};
PVector.div = function(v1, n) {
const v3 = new PVector(v1.x / n, v1.y / n);
return v3;
};
const Mover = function() {
// ๋ฌผ์ฒด์ ์ง๋
this.mass = 1;
this.position = new PVector(0, 0);
this.velocity = new PVector(0, 0);
this.acceleration = new PVector(0, 0);
};
Mover.prototype.update = function() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
// ๊ฐ ํ๋ ์๋ง๋ค ๊ฐ์๋ ์ ๊ฑฐ
this.acceleration.mult(0);
};
Mover.prototype.display = function() {
context.beginPath();
// ์ง๋์ ์๊ฐํ (์ง๋์ ๋ฐ๋ผ ํฌ๊ธฐ๋ฅผ ๊ณ์ฐ)
context.ellipse(this.position.x, this.position.y, this.mass * 20, this.mass * 20, 0, 0, Math.PI * 2, false);
context.lineWidth = 5;
context.strokeStyle = '#333333';
context.stroke();
context.fillStyle = '#ffffff';
context.fill();
};
// ๊ฐ์ฅ์๋ฆฌ์์ ๊ฐ์ฒด๋ฅผ ํ๊ฒจ๋ด๋ ๋ฉ์๋
Mover.prototype.checkEdges = function() {
if (this.position.x > canvas.width) {
this.position.x = canvas.width;
this.velocity.x *= -1;
} else if (this.position.x < 0) {
this.velocity.x *= -1;
this.position.x = 0;
}
if (this.position.y > canvas.height) {
this.velocity.y *= -1;
this.position.y = canvas.height;
}
};
// ๋ดํด์ ์ 2๋ฒ์น (ํ์ ๋ฐ๊ณ , ์ง๋์ผ๋ก ๋๋๊ณ , ๊ฐ์๋์ ๋ํจ)
Mover.prototype.applyForce = function(force) {
const f = PVector.div(force, this.mass);
this.acceleration.add(f);
};
const mover = new Mover();
const update = () => {
context.clearRect(0, 0, canvas.width, canvas.height);
// ๋ฐ๋๊ณผ ์ค๋ ฅ ์ ์ฉ
const wind = new PVector(0.01, 0);
const gravity = new PVector(0, 0.1);
mover.applyForce(wind);
mover.applyForce(gravity);
mover.update();
mover.checkEdges();
mover.display();
requestAnimationFrame(update);
};
update();
</script>
์ฌ๋ฌ ๋ฌผ์ฒด์ ์์ง์
์ง๋๊ณผ ์์น๊ฐ ๋ค์ํ, ํ๋ ์ด์์ ๋ฌผ์ฒด์ ์์ง์์ ๊ตฌํํด๋ณด์.
<canvas id="myCanvas" width="300" height="250" style="border: 1px solid #000;"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');
const PVector = function(x, y) {
this.x = x;
this.y = y;
};
PVector.prototype.add = function(v) {
this.y = this.y + v.y;
this.x = this.x + v.x;
};
PVector.prototype.mult = function(n) {
this.x = this.x * n;
this.y = this.y * n;
};
// ๋ฒกํฐ๋ฅผ ๋ณต์ฌํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ ๋ฉ์๋
PVector.prototype.copy = function() {
return new PVector(this.x, this.y);
};
PVector.div = function(v1, n) {
const v3 = new PVector(v1.x / n, v1.y / n);
return v3;
};
// ๋ค์ํ ์ง๋๊ณผ ์์น๋ฅผ ๊ฐ๋ ๊ฐ์ฒด ์์ฑ์
const Mover = function(m, x, y) {
this.mass = m;
this.position = new PVector(x, y);
this.velocity = new PVector(0, 0);
this.acceleration = new PVector(0, 0);
};
Mover.prototype.update = function() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
// ๊ฐ ํ๋ ์๋ง๋ค ๊ฐ์๋ ์ ๊ฑฐ
this.acceleration.mult(0);
};
Mover.prototype.display = function() {
context.beginPath();
// ์ง๋์ ์๊ฐํ (์ง๋์ ๋ฐ๋ผ ํฌ๊ธฐ๋ฅผ ๊ณ์ฐ)
context.ellipse(this.position.x, this.position.y, this.mass * 20, this.mass * 20, 0, 0, Math.PI * 2, false);
context.lineWidth = 5;
context.strokeStyle = '#333333';
context.stroke();
context.fillStyle = '#ffffff';
context.fill();
};
// ๊ฐ์ฅ์๋ฆฌ์์ ๊ฐ์ฒด๋ฅผ ํ๊ฒจ๋ด๋ ๋ฉ์๋
Mover.prototype.checkEdges = function() {
if (this.position.x > canvas.width) {
this.position.x = canvas.width;
this.velocity.x *= -1;
} else if (this.position.x < 0) {
this.velocity.x *= -1;
this.position.x = 0;
}
if (this.position.y > canvas.height) {
this.velocity.y *= -1;
this.position.y = canvas.height;
}
};
// ๋ดํด์ ์ 2๋ฒ์น (ํ์ ๋ฐ๊ณ , ์ง๋์ผ๋ก ๋๋๊ณ , ๊ฐ์๋์ ๋ํจ)
Mover.prototype.applyForce = function(force) {
const f = PVector.div(force, this.mass);
this.acceleration.add(f);
};
const movers = [];
for (let i = 0; i < 20; i++) {
// (0, 0) ์์น์์ ์์ํ๋ ๋ค์ํ ์ง๋์ ๊ฐ์ฒด๋ฅผ 20๊ฐ ์์ฑ
movers[i] = new Mover(Math.random(0.1, 5), 0, 0);
}
const update = () => {
context.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < movers.length; i++) {
// ๋ฐ๋๊ณผ ์ค๋ ฅ ์ ์ฉ
const wind = new PVector(0.01, 0);
const gravity = new PVector(0, 0.1);
movers[i].applyForce(wind);
movers[i].applyForce(gravity);
movers[i].update();
movers[i].checkEdges();
movers[i].display();
}
requestAnimationFrame(update);
};
update();
</script>