Silverback9

#야생으로

Creative Coding 독학 제095일 2024년06월30일(일)

오늘은 노트르담 대성당의 종을 울려 보도록 하겠습니다~^^*

일요일 동네 교회의 첨탑에서 뎅~뎅~ 울리던 종소리를 떠올리며,

콰지모토가 매일 긴 줄을 붙잡고 정성으로 울렸던 노트르담 대성당 종을 프로그램으로 표현해 보겠습니다~^^*

아래 동영상 강의를 클릭하시면, 오늘 공부 내용을 바로 시작(27:10)하실 수 있어요~^^* 29:00까지 보시면 오늘 공부 끝~~^^*

음… 우리가 줄을 잡아당겨도, 첨탑 지지대에 매달려 있는 종은 지지대에서 떨어지면 안되는데요….음….떨어지면 머리가 “아야”해요….떨어지면 안돼요….!!!

어쩌면 좋을까요?

아하!!!

캔버스 화면 제일 위에 위치하는 입자 즉 입자 배열 첫 번째 요소, particles[0]는 꼼짝하지 않도록 만들면 될 것 같아요~~!!!

입자가 particles[0]이면 움직이지 않도록 하고, 입자가 partcicles[0]가 아니면 움직이도록 하면 어떨까요~~!!

입자 클래스에, 잠김상태를 알려주는 Boolean Logic을 사용해 보겠습니다.

particles[0]는 잠김 상태가 True이다라고 설정을 하고, 다른 입자들은 잠김 상태가 False이다라고 설정을 해 볼게요.

그리고, 잠김 상태가 True가 아니라면 움직이도록 하겠습니다.

즉, particle[0]을 제외한 다른 입자들이 움직이게 되겠지요~^^*?

아래의 알고리즘을 살펴 보셔도 좋겠지요~^^*?

class Particle{
   constructor(x,y){
   (1) this.locked = false;
   ...
   }
   update(){
   (3) if(!this.locked){
   움직인다;
   } 
}
....

function setup(){
  ...
 (2) particles[0].locked = true;
  ...
}

//(1) 모든 입자들은 기본적으로 locked의 Boolean 값을 false로 설정해 놓습니다.
//(2) 입자 배열[0], 즉 캔버스 화면 맨 위에 있는 매듭은 locked의 Boolean 값을 true로 설정합니다. 
//(3) locked의 Boolean 값이 false인 입자만 움직입니다.
// "!"는 Not의 의미를 가지고 있습니다. (Not + locked) 가 True 일 때, 움직입니다. 다시 말해서, (Not + False) = True 일 때 움직입니다. 그러므로, locked의 Boolean 값이 false일 때 움직입니다.    
// particles[0]는 Boolean 값이 true이므로, (!locked) = (Not True) = (False)가 되어, 조건을 만족시키지 않기 때문에, 움직이지 못합니다. 

이제 전체 코드를 살펴 볼까요~~^^*?

자세한 내용은 주석을 참고해 주시면 감사하겠습니다~^^*

class Particle{
  constructor(x,y){
    this.locked = false;
    //Boolean Logic을 사용해 보겠습니다.
    //입자들은 기본적으로 locked되지 않은 상태로 생성하겠습니다.
    //this.locked 상태는 false로 기본설정하겠습니다. 
    this.acceleration = createVector(0,0);
    this.velocity = createVector(0,0);
    this.position = createVector(x,y);
    this.mass = 1;
  }
  applyForce(force){
    let f = force.copy();
    f.div(this.mass);
    this.acceleration.add(f);
    // F = M * A를 적용하여, A = F / M 관계를 사용합니다.
    // f = F / M 하여, f를 가속도에 더합니다.  
  }
  update() {
    if(!this.locked) 
    //this.locked가 false이면, !this.locked는 true가 되어요.
    //그러면 아래의 움직임 명령어들을 수행해요. 움직여요.    
    //this.locked가 true이면, !this.locked는 false가 되어요.
    //그러면, 아래의 움직임 명령어들을 수행하지 않아요. 가만히 있어요.   
    {
    this.velocity.mult(0.99);
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    this.acceleration.mult(0);
    // 공기저항을 반영하여 속도를 점차 줄여요. 
    // 가속도가 속도에 영향을 주고
    // 속도가 위치에 영향을 준 뒤
    // 가속도는 0로 재세팅합니다. 
    // 함수 draw()는 무한반복하기 때문에, 가속도가 force의 변화가 없는데도 중첩증가하지 않는 장치가 필요합니다: 가속도 재세팅!  
    }  
     
  }
  show(){
    stroke(255);
    strokeWeight(4);
    fill(127, 255, 127);
    ellipse(this.position.x, this.position.y, 12);
    //종에 연결된 줄의 매듭을 표현하기 위해 동그라미는 작게 그리겠습니다. 
  }
}
class Spring {
  constructor(k, restLength, a, b){
    this.k = k;
    this.restLength = restLength;
    this.a = a;
    this.b = b;  
  }
  update(){
    
    let force = p5.Vector.sub(this.b.position, this.a.position);
    // 벡터 b 입자에서 벡터 a 입자를 뺍니다.
    // 벡터 force의 방향은 입자 a에서 입자 b으로 향합니다. 
    
    let x = force.mag() - this.restLength;
    force.normalize();
    
    force.mult(this.k*x);
    this.a.applyForce(force);
    // 벡터 force의 방향이 이미 입자 a에서 입자 b로 향하고 있으므로, 탄성계수 k * 거리 x를 그대로 씁니다. 
    // 입자 a가 입자 b로 향하는 힘입니다. 
    
    force.mult(-1);
    this.b.applyForce(force);
    //입자 b가 입자 a로 향하는 힘을 표현하기 위해서, 벡터 force에 -1을 곱하여, 힘의 방향을 바꿉니다.
    
    // 두 입자 a, b가 스프링으로 연결되어 서로를 향한 힘을 가지고 있습니다. 
    
  }
  show(){
    strokeWeight(4);
    stroke(255);
    line(this.a.position.x, this.a.position.y, this.b.position.x, this.b.position.y);
  }
}
let particles = [];
let springs = [];
let k = 0.01;
let gravity;

let spacing = 10;
//처음 시작할 때, 입자들 사이의 수직 거리가 될 것입니다~^^* 
//입자들 사이의 스프링의 원래 길이(restLength)로 사용하겠습니다~^^*

function setup() {
  
  createCanvas(400, 400);
  
  for( let i = 0; i <10; i++){
    // [0] ~ [9] 총 10개의 입자를 만들어 보겠습니다~^^*
    
    particles[i] = new Particle(200, i*spacing);
    // 화면 가운데, 맨 위에서 아래로 spacing = 10 간격으로 수직으로 나란히 위치시켜 볼게요~^^*
    
    if( i != 0){
      // particles[0] 즉 (200, 0)에 있는 입자에 대해서는 아래의 일을 하지 않습니다. 왜냐하면, 이 입자 앞에는 그 어떤 입자도 없기 때문입니다. 
      // parcicles[0]는 배열 맨 처음의 요소라서, 자신 앞에 다른 요소를 가지고 있지 않아 연결 작업이 무의미 합니다~
      
      let a = particles[i];
      let b = particles[i - 1];
      let spring = new Spring(k, spacing, a, b);
      //요소 particles[i]는 자신 바로 앞에 있는 요소 particles[i-1]과 스프링으로 연결됩니다.~^^*
      
      springs.push(spring);
      //생성된 spring을 배열 springs[]에 저장합니다. 
      //배열 springs[]는 배열 particles[]보다 요소가 1개 적게 되겠네요? (1->0), (2->1), (3->2), (4->3) ...,(9->8) 총 9개의 spring이 생성되어 배열 springs[]에 저장됩니다~^^*
    }
  }
   particles[0].locked = true;
   //캔버스 화면 제일 위에 있는 입자, 즉 입자 배열 첫번째 요소인 particles[0]의 클래스 구성요소인 locked 의 Boolean 상태를 기본값 false 에서 true 로 바꾸겠습니다~^^* 
  
  gravity = createVector(0, 0.01);
  //줄의 매듭들이 중력의 영향을 받아 차르르 예쁘게 자리잡도록 해보겠습니다~^^*
}  
  
  
function draw() {

  background(220);
  
  for( let s of springs){
    s.update();
    s.show();
  }
  //모든 스프링의 움직임을 보여주고
  
  for ( let p of particles){
    p.applyForce(gravity);
    p.update();
    p.show();
  }
  //모든 줄 매듭의 움직임을 보여줍니다.
  
  let tail = particles[particles.length - 1];
  //배열 맨마지막 요소를 변수 tail에 저장하겠습니다~

  if (mouseIsPressed) {
   tail.position.set(mouseX, mouseY);
   tail.velocity.set(0,0);
  }
  //마우스/손가락을 클릭/눌러서 노트르담 대성당의 종을 울려보세요.
  //줄이 부드럽게 움직이나요~^^*
}

이제 콰지모토가 되어 노트르담 대성당의 종을 정성을 담아 울려 볼까요~~^^* 뎅~뎅~뎅~^^*

오늘은 비가 온 뒤라 제법 햇살도 부드럽고 해서 걸어다니기 좋았어요~^^*

콰지모토가 평생을 종탑 안에 살면서, 종탑 아래 바깥 세상을 참 많이 걸어보고 싶었을 것 같은데요…. 자유롭게 걸어 다닐 수 있음이 새삼 감사했어요~^^*

콰지모토가 종탑 아래 바깥 세상을 꿈꾸며 노래 부르는 심정을 다양한 방식으로 절절하게 표현해 볼 수 있을 것 같은데요. 친근한 애니메이션으로, 수화를 곁들여 두 명의 배우가 함께, 또는 한 명의 배우가 간결하면서도 상징적인 분장을 하고서, 콰지모토의 심경을 표현할 수도 있네요…

우리도, COVID-19 시절 바깥 세상에 자유롭게 나가 사람들과 무언가를 함께 할 수 있기를 많이 바라기도 했었지요. 그 시절, 물리적으로 함께 할 수 없지만, 온라인으로 함께 만나 아름다운 공연을 해 낸 배우들도 계셨네요~^^*

COVID-19으로 인해, 콰지모토의 심정을 함께 느껴보았던 우리라서, 콰지모토가 지금은 천국의 친구들과 자유롭게 바깥 나들이를 하며 함께 어울리고 있기를 바라게 되는 것 같아요. 이제 콰지모토는 천국에서 친구들과 함께 즐겁게 종을 울리고 있겠지요~^^*

콰지모토의 이야기를 다양한 방식으로 표현할 수 있듯이, 어떤 이야기를 코딩을 통해서도 다양하게 표현할 수 있는 역량을 기르고 싶다는 소망을 가지게 되는 오늘입니다.

콰지모토는 천국에서 지금 행복하고, 우리는 여기에서 날마다 성장하기를 바라게 되네요.

오늘도 저와 함께 코딩 공부를 해주셔서 감사합니다~^^*

내일은 우리 음악 함께 들어요~~^^*

넵!!! 꿈은 이루어 집니다!!!

댓글 남기기