오늘은 동그라미들이 서로의 거리를 일정하게 그리고 유연하게 유지하여 멋진 대형을 만드는 프로그램에 도전!해 보겠습니다~~~^^* YEAH~~~^^*
두 개의 동그라미 사이의 거리를 일정하면서도 유연하게 유지하는 코드를 어제 만들어 보았는데요~^^*
여러 개의 동그라미들이 순서에 따라 두 개씩 짝지어서, 이 Constraint의 작용이 이루어 지면 하나의 사슬 형태가 될 것 같아요~!
음…근데…이 사슬은….위쪽 끝자락이 고정이 되어 있네요…
어떻게 하면 좋을 까요…..?
음…
아…!
어머!!!
그렇네요!!!
네, 정말 그렇네요!!!
첫 번째 동그라미는 <고정> 되고,
다음 번째 동그리미부터는 <안고정> 되면 되겠네요…
아…네…또 하나 생각해 볼 것이 있다고요?
네…아….와…!!! 그렇네요!!!
동그라미의 연결 방법!
<앞과 뒤> 관계성!!
중요하겠어요!!
넵! 정리해 보면~~~^^*
첫 번째 동그라미는 <고정>되고, <앞의 동그라미가 없음> 상태이며
두 번째 동그라미부터는 <안고정>되고, <앞의 동그라미가 있음> 상태가 되겠네요!
중요 포인트 2 가지 <고정여부> <앞의 동그라미 유무>를 상정해 놓았으니, 이제 이 포인트들을 코드로 한 단계 한 단계 표현해 볼까요~~^^*
하나. 앞의 동그라미를 표현할 변수를 만들고, 정보는 비워 놓도록 할게요.
let prev = null;
둘. 고정 여부를 표현할 변수를 만들고, false 값을 부여해 놓도록 할게요. ( 대부분의 동그라미는 고정되지 않을 것이니까, false 값을 Default로 잡아놓도록 할게요~^^*)
let fixed = false;
셋. 첫 번째 동그라미는 고정시키도록 할게요.
Q: 첫 번째 동그라미는 어떻게 알 수 있지요?
A: 앞의 동그라미가 없으니,
prev 값이 null이라서,
prev의 진리값은 false가 되어서,
그 반대인 !prev의 진리값은 true가 되겠지요?
!prev가 true이면 바로 첫 번째 동그라미~~!
(여기서, “!”는 “not”의 의미를 표현하는 부호예요~^^*)
if (!prev) {
fixed = true;
}
넷. 고정 여부를 표현하는 fixed를 이제 동그라미 생성에 중요한 옵션 중 하나인 isStatic의 상태를 지정하는 매개변수 parameter로 삼습니다~^^*
class Particle{
constructor(x, y, r, fixed) {
this.x = x;
this.y = y;
this.r = r;
let options = {
friction: 0,
restitution: 0.95,
isStatic: fixed
}
}
}
//매개변수 fixed로 true 값이 넘겨져 오면,
//"isStatic : fixed" 는 "isStatic : true"의 의미가 되어
//동그라미가 고정됩니다.
//첫 번째 동그라미는 true 값을 넘겨 받을 것이라, 고정될 것이고
//두 번째 동그라미부터는 Default인 false 값을 넘겨 받아서, 고정되지 않게 될것 같네요~~!!!
다섯. 첫 번째 동그라미를 생성합니다.
let particles = [];
let p = new Particle(x, 100, 10, fixed);
particles.push(p);
여섯. 첫 번쨰 동그라미가 생성되었으니, 변수 prev에 이 동그라미를 저장합니다.
prev = p;
일곱. 두 번째 동그라미부터는
변수 prev의 값이 null이 아니니까 (앞의 동그라미가 있으니까) ,
prev의 진리값이 true가 되어,
!prev의 진리값은 false가 되어,
if (!prev) 구문이 작동되지 않아서,
fixed의 진리값은 false로 유지가 되어,
고정되지 않는 동그라미들이 생성되겠네요~~^^*
let fixed = false;
if (!prev) {
fixed = true;
}
let p = new Particle(x, 100, 10, fixed);
particles.push(p);
여덟. 두번째 동그라미부터는, 앞의 동그라미가 존재하기 떄문에, <앞뒤 관계성>을 표현하겠습니다. 클래스 동그라미의 구성함수에 옵션을 추가하는 작업을 메인함수에서 해 보겠습니다.
if (prev) {
let options = {
bodyA: p.body,
bodyB: prev.body,
length: 20,
stiffness: 0.4
}
let constraint = Constraint.create(options);
World.add(world, constraint);
}
//두 번째 동그라미는 첫 번째 동그라미와 앞뒤 관계성을 가지고 있으며, 옵션 사항에 따른 Constraint의 작용을 받게 되었습니다
아홉. 두 번째 동그라미를 변수 prev에 저장하여, 세 번쨰 동그라미의 앞 동그라미가 되도록 미리 설정해 놓습니다.
prev = p;
열. 이렇게 동그라미를 여러 개 생성하기 위해서 for 구문을 사용합니다.
for (let x = 200; x < 400; x += 20)
// x축 좌표 200 부터 400 까지, 20 pixel 간격으로 동그라미들을 만들어 봅시다. 생성이 되면, 중력에 의해 수평선에서 수직선으로 정렬 모습이 바뀌게 될 것 같습니다.
열하나. 이 모든 10단계를 정리해 보겠습니다.
class Particle{
constructor(x, y, r, fixed) {
this.x = x;
this.y = y;
this.r = r;
let options = {
friction: 0,
restitution: 0.95,
isStatic: fixed //넷
}
}
}
let engine;
let world;
let particles = [];
engine = Engine.create();
world = engine.world;
let prev = null; //하나
for (let x = 200; x < 400; x += 20) { //열
let fixed = false; //둘 //일곱
if (!prev) {
fixed = true; //셋
}
let p = new Particle(x, 100, 10, fixed); //다섯 //일곱
particles.push(p);
if (prev) { //여덟
let options = {
bodyA: p.body,
bodyB: prev.body,
length: 20,
stiffness: 0.4
}
let constraint = Constraint.create(options);
World.add(world, constraint);
}
prev = p; //여섯 //아홉
}
<고정 여부> <앞뒤 관계성 유무> 이 두 가지 포인트를 중심으로 한 전체 코드를 이제 우리 함께 살펴 볼까요~^^* 주요 내용을 충분히 짚어 보았으니, 주석은 넣지 않도록 할게요~^^*
<!DOCTYPE html>
<html lang="en">
<head>
https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js
https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/addons/p5.sound.min.js
https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
</main>
http://sketch.js
http://circle.js
http://boundary.js
</body>
</html>
class Boundary {
constructor(x, y, w, h, a) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
let options = {
friction: 0,
restitution: 0.6,
angle: a,
isStatic: true
}
this.body = Bodies.rectangle(this.x, this.y, this.w, this.h, options);
Composite.add(world, this.body);
}
show() {
let pos = this.body.position;
let angle = this.body.angle;
push();
translate(pos.x, pos.y);
rotate(angle);
rectMode(CENTER);
fill(0);
rect(0, 0, this.w, this.h);
pop();
}
}
class Particle{
constructor(x, y, r, fixed) {
this.x = x;
this.y = y;
this.r = r;
let options = {
friction: 0,
restitution: 0.95,
isStatic: fixed
}
this.body = Bodies.circle(this.x, this.y, this.r, options);
Composite.add(world, this.body);
}
show() {
let pos = this.body.position;
let angle = this.body.angle;
push();
translate(pos.x, pos.y);
rotate(angle);
rectMode(CENTER);
strokeWeight(1);
stroke(255)
fill(127);
ellipse(0, 0, this.r*2);
pop();
}
}
const {
Engine,
World,
Bodies,
Composite,
Constraint
} = Matter;
let engine;
let world;
let particles = [];
let boundaries = [];
function setup() {
createCanvas(400, 400);
engine = Engine.create();
world = engine.world;
let prev = null;
for (let x = 200; x < 400; x += 20) {
let fixed = false;
if (!prev) {
fixed = true;
}
let p = new Particle(x, 100, 10, fixed);
particles.push(p);
if (prev) {
let options = {
bodyA: p.body,
bodyB: prev.body,
length: 20,
stiffness: 0.4
}
let constraint = Constraint.create(options);
World.add(world, constraint);
}
prev = p;
}
boundaries.push(new Boundary(width / 2, 400, width, 20, 0));
}
function draw() {
background(51);
Engine.update(engine);
for (let i = 0; i < boundaries.length; i++) {
boundaries[i].show();
}
for (i = 0; i < particles.length; i++) {
particles[i].show();
}
}
손에 손 잡고 예쁜 대형을 유연하게 만들어 나가는 광경은 언제나 멋진 것 같아요!
오늘도 저와 함께 동그라미들이 멋진 대형을 유연하면서도 튼튼하게 표현하는 프로그램을 만들어 주셔서 감사합니다!
오늘도 멋진 아침! 즐거운 하루! 보내셔요!
내일도 우리 함께 도전! 계속해 나가면 좋겠어요~~^^*
네~!!! 꿈은 이루어 집니다~!!!
댓글 남기기