Silverback9

#야생으로

Creative Coding 독학 제181일 2024년09월24일(화)

오늘은 동그라미들이 서로의 거리를 일정하게 그리고 유연하게 유지하여 멋진 대형을 만드는 프로그램에 도전!해 보겠습니다~~~^^* 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();
    }
}

와~~^^* 이렇게 차근히 생각하면서 단계별로 나아가니, 전체 코드가 완성되는군요~~^^* 우리들의 이 동그라미들이 유연하게 정렬하며 사슬 대형을 유지하는 보람찬 광경을 보러 갈까요~~^^*

손에 손 잡고 예쁜 대형을 유연하게 만들어 나가는 광경은 언제나 멋진 것 같아요!

오늘도 저와 함께 동그라미들이 멋진 대형을 유연하면서도 튼튼하게 표현하는 프로그램을 만들어 주셔서 감사합니다!

오늘도 멋진 아침! 즐거운 하루! 보내셔요!

내일도 우리 함께 도전! 계속해 나가면 좋겠어요~~^^*

네~!!! 꿈은 이루어 집니다~!!!

댓글 남기기