Silverback9

#야생으로

Creative Coding 독학 제318일 2025년02월08일(토)

오늘도 참 추운데요…어제 오후에도 공기가 엄청 차서 많이 놀랐어요….

하지만! 찬 공기 속에서도 흰 눈의 흔적 속에서도 오늘의 공부를 시작해 보겠습니다! YEAH~~^^* 우리는 Coding 꿈나무이니까요~~^^* YEAH~~^^*

발레 꿈나무들의 멋진 춤사위를 귀로 들으시며~^^* 아침을 부드럽게 풀고 계시기 바래요~^^*

공부 정리해서 돌아올게요~^^* 쓩우웅~^^*

먼저, 아주아주 옛날부터 지금까지 vehicle의 조상님들의 약초와 독초에 대한 경험의 기억을 유전자에 담아보겠습니다~^^* 네~^^* 이제 슬슬 DNA를 준비해 볼까요~~^^*

네^^*

food에 대한 유전적 기억을 dna[0]에 담고요~^^*

poison에 대한 유전적 기억을 dna[1]에 담아 볼게요~^^*

왠지 모르게 약초에게 끌리고 왠지 모르게 독초에서 멀어지고픈 마음이 자연스럽게 생기는 안전한 미래가, 이 프로그램을 최종적으로 완성하면, 펼쳐질 것 같아요.

그 미래를 준비하는 첫 날인 오늘!!!

일단 오늘은~^^* 끌림과 멀어지고픔의 강도의 최소/최대 값을 food와 poison에 대해 동일하게 갖도록 해볼게요. 그리고 그 구체적인 값은 최소/최대 범위 안에서 무작위로 설정해 볼게요.

네~^^* 우리의 귀엽고 총명한 vehicle의 태초의 조상이 맞이했던 상황이라고 여겨질 수도 있겠네요.

class Vehicle {
  constructor(x, y) {
    this.acceleration = createVector(0, 0);
    this.velocity = createVector(0, -2);
    this.position = createVector(x, y);

    this.health = 1;

    this.r = 6;
    this.maxspeed = 8;
    this.maxforce = 0.2;

    this.dna = [];
    this.dna[0] = random(-5, 5);
    //food에 대한 멀어지고픔 최대치 -5 끌림 최대치 +5 사이 무작위 값
    this.dna[1] = random(-5, 5);
    //poison에 대한 멀어지고픔 최대치 -5 끌림 최대치 +5 사이 무작위 값
    
  }
   .
   .
   .
}

이번에는 vehicle의 DNA에 심어진 이 기억에 따라 vehicle이 자신도 모르게 본능적으로 food와 poison에 반응하는 행동을 표현해야 할 것 같네요~~^^*

네~^^* 내장함수 behaviors()를 준비해 보겠습니다~^^*

먹거리를 몸에 좋은 것 그리고 나쁜 것으로 구분해 볼게요~^^* 그리고 몸에 좋은 것을 먹을 때의 행동 그리고 몸에 나쁜 것을 먹을 때의 행동을 표현해 보겠습니다.

class Vehicle {
   .
   .
   .
  behaviors(good, bad) {
     const steerG = this.eat(good);
     //몸에 좋은 음식에 대한 반응행동 벡터 steerG입니다.
     const steerB = this.eat(bad);
     //몸에 나쁜 음식에 대한 반응행동 벡터 steerB입니다. 

     steerG.mult(this.dna[0]);
     //몸에 좋은 것에 대한 기억인 dna[0]에 저장된 값을 좋은 음식에 대한 반응행동 벡터 steerG의 크기에 곱하겠습니다.  
     steerB.mult(this.dna[1]);
     //몸에 나쁜 것에 대한 기억인 dna[1]에 저장된 값을 나쁜 음식에 대한 반응행동 벡터 steerB의 크기에 곱하겠습니다. 

     this.applyForce(steerG);
     this.applyForce(steerB);
      //vehicle의 행동에 이 반응벡터 steerG와 steerB가 영향을 끼칩니다.     
  }
   .
   .
   .
}

음…그런데요…

행동을 묘사하는 함수 behaviors()를 마련하고 보니, 함수 eat()를 또 개선할 필요가 있을 것 같네요.

steerG와 steerB가 함수 eat()가 return 반환하는 값을 저장하니까요~^^*

어제 우리가 만들어 보았던 eat()함수를 다시 살펴 볼까요~^^*

<<어제의 함수 eat() 버전>> 

eat(list) {
    var record = Infinity;
    var closest = -1;
    for (var i = 0; i < list.length; i++) {
      var d = this.position.dist(list[i]);
      if(d < record) {
        record = d;
        closest = i;
      }
    }
    
   if(record < 5) {
      list.splice(closest, 1);
    } else if(closest > -1) {
      this.seek(list[closest]);  
    }
  }

아직 가장 가까운 먹거리가 5 pixel보다는 떨어져 있지만, 먹거리의 배열에 아직 구성요소가 남아있을 경우( closest > -1 ), 먹지는 않고( 먹거리 배열에서 삭제하지는 않고) 그 먹거리를 향해서 몸을 틀게 되는데요.

이 seek 함수 호출 부분을 return하도록 개선해 보겠습니다~^^*

<<오늘의 함수 eat() 버전>> 

eat(list) {
    var record = Infinity;
    var closest = -1;
    for (var i = 0; i < list.length; i++) {
      var d = this.position.dist(list[i]);
      if(d < record) {
        record = d;
        closest = i;
      }
    }
    
    if(record < 5) {
      list.splice(closest, 1);
    } else if(closest > -1) {
      return this.seek(list[closest]);  
    }
    return createVector(0,0);
  }

//먹거리가 5 pixel 거리 안에 없지만, 먹거리 배열에 구성요소가 남아있을 경우, 가장 가까운 구성요소를 향해서 몸을 트는 행동 벡터 this.seek(list[closest]);를 반환합니다. 
//먹거리가 5 pixel 거리 안에 있으면, 먹거리 배열에서 그 먹거리를 삭제한 후 아무 움직임도 없는(0,0) 행동벡터를 반환합니다. 
//먹거리 배열에 아무 구성요소가 없는 경우에도 아무 행동이 없는 (0,0) 행동벡터를 반환합니다.  

음…그러면….이제는 또….

네…내장함수 seek()를 수정해서 벡터값을 반환하도록 개선해야 할 것 같아요…!!

이전 버전 먼저 함께 살펴 볼까요~~^^*

 seek(target) {
   const desired = p5.Vector.sub(target, this.position); 
   desired.setMag(this.maxspeed);
   let steer = p5.Vector.sub(desired, this.velocity);
   steer.limit(this.maxforce); 
   this.applyForce(steer); 
  }  

target으로 몸을 트는 벡터 steer를 생성하여 maxforce 값 안으로 힘이 크기를 조정하여 vehicle에게 이 벡터를 적용시켰는데요.

이제는 vehicle의 행동에 벡터의 적용을 하지 않고, 벡터 steer를 반환하는 것으로 수정해 보겠습니다.

 seek(target) {
   const desired = p5.Vector.sub(target, this.position); 
   desired.setMag(this.maxspeed);
   let steer = p5.Vector.sub(desired, this.velocity);
   steer.limit(this.maxforce); 
   return steer;
  }  

네~^^* 그럼 이제~~^^*

새로운 내장 변수 배열 dna[], 새로운 내장 함수 behavior()와 이에 맞게 개선된 내장 함수 eat()와 steer()를 함께 모아 한 눈에 같이 살펴 볼까요~~^^*

class Vehicle {
  constructor(x, y) {
     .
     .
     .

    this.dna = [];
    this.dna[0] = random(-5, 5);
    //food에 대한 멀어지고픔 최대치 -5 끌림 최대치 +5 사이 무작위 값
    this.dna[1] = random(-5, 5);
    //poison에 대한 멀어지고픔 최대치 -5 끌림 최대치 +5 사이 무작위 값
  }
    .
    .
    .
  behaviors(good, bad) {
     const steerG = this.eat(good);
     //몸에 좋은 음식에 대한 반응행동 벡터 steerG입니다.
     const steerB = this.eat(bad);
     //몸에 나쁜 음식에 대한 반응행동 벡터 steerB입니다. 

     steerG.mult(this.dna[0]);
     //몸에 좋은 것에 대한 기억인 dna[0]에 저장된 값을 좋은 음식에 대한 반응행동 벡터 steerG의 크기에 곱하겠습니다.  
     steerB.mult(this.dna[1]);
     //몸에 나쁜 것에 대한 기억인 dna[1]에 저장된 값을 나쁜 음식에 대한 반응행동 벡터 steerB의 크기에 곱하겠습니다. 

     this.applyForce(steerG);
     this.applyForce(steerB);
      //vehicle의 행동에 이 반응벡터 steerG와 steerB가 영향을 끼칩니다.     
  }

  eat(list) {
    var record = Infinity;
    var closest = -1;
    for (var i = 0; i < list.length; i++) {
      var d = this.position.dist(list[i]);
      if(d < record) {
        record = d;
        closest = i;
      }
    }
    
    if(record < 5) {
      list.splice(closest, 1);
    } else if(closest > -1) {
      return this.seek(list[closest]);  
    }
    return createVector(0,0);
  }

//먹거리가 5 pixel 거리 안에 없지만, 먹거리 배열에 구성요소가 남아있을 경우, 가장 가까운 구성요소를 향해서 몸을 트는 행동 벡터 this.seek(list[closest]);를 반환합니다. 
//먹거리가 5 pixel 거리 안에 있으면, 먹거리 배열에서 그 먹거리를 삭제한 후 아무 움직임도 없는(0,0) 행동벡터를 반환합니다. 
//먹거리 배열에 아무 구성요소가 없는 경우에도 아무 행동이 없는 (0,0) 행동벡터를 반환합니다.  

 seek(target) {
    const desired = p5.Vector.sub(target, this.position); 
    desired.setMag(this.maxspeed);
    let steer = p5.Vector.sub(desired, this.velocity);
    steer.limit(this.maxforce); 
    return steer;
  }  
//target으로 몸을 트는 벡터를 생성하여 변수 steer에 저장한 후 maxforce 값 안으로 힘의 크기를 조정하여 steer를 반환합니다. 
   .
   .
   .
}

이제 메인 함수이며 무한 반복 함수인 draw()에서는 vehicle의 내장함수 beaviors()를 호출하면서 food를 좋은 음식 poison을 나쁜 음식 argument로 넘겨주면 될 것 같아요~~^^*

function draw() {
   .
   .
   .
  vehicle.behavior(food, poison);
  vehicle.update();
  vehicle.display();
}

그럼 이제 새롭게 개선된 vehicle이 잘 작동하는 지 확인해 볼까요~^^* food와 poison에 대해 구별 없이 무작위적인 기억을 가진 태초의 vehicle 조상의 모습을 우리가 보게 되는 것인가요? food와 poison에 대한 기억이 무작위 값으로 세팅되다 보니 플레이 할 때마다 vehicle이 떄로는 food를 좀더 잘 찾아내고 때로는 poison을 더 잘 찾아내곤 하는 것 같아요…여러 번 플레이 해 보면 매번 다른 행동 패턴을 보여주는 vehicle 태초 조상님이 많이 귀여우신데요~~^^* 어떨 땐 캔버스 밖을 나가 한참 동안 헤메시고 계시기도 하네요…역시…어떤 종이든…그 시조새의 고군분투 우당탕탕 좌충우돌은 많이 감동적인 것 같아요…시조새의 그런 힘겨운 생존의 경험이 후세에게 지혜로 전해져서 후세는 좀더 편안하게 좀더 효율적으로 자신의 역량을 펼칠 수 있는 것 같아요…

시조새님들 존경합니다!!!

네~^^* 처음의 길을 닦는 존재에 대한 감사함을 느끼며, 오늘 vehicle에 몸에 좋은 음식과 위험한 음식에 대한 유전적 기억을 저와 함께 준비해 주셔서 감사합니다~^^*

내일은 이 dna와 이에 대한 반응행동에 대해 우리 함께 좀 더 공부해 나가 볼까요~^^*

네~^^* 좋아요~^^* 고마워요~^^*

새로운 세상으로의 첫 진입은 신기함과 놀라움과 무지함에서 오는 무작위적인 반응행동과 그에 대한 결과에 영향을 받아가며 조금씩 지식도 지헤도 몸 안에 쌓아나가는 것 같아요…

그리고 어느새 그 새로운 세상을 편안하게 누리며 즐겁게 탐험하게 되는 것 같아요~^^*

우리의 vehicle도 이제 점점 새로운 세상에 대한 자신만의 경험 축적으로 지혜를 쌓아나가며 점점 귀엽고 총명해 질 것 같은데요~^^*!!

인내심을 가지고 프로그램 개선에 저와 함께 해 주셔서 감사합니다~^^*

오늘도!

멋진 하루 보내시며~^^*

반가운 만남 기쁨 나누는 보람 만끽하시고요~^^*

뿌듯한 가슴 통통 두드리며 따뜻하게 코~^^* 하셔요~^^*

네~^^* 꿈은 이루어 집니다~^^*

댓글 남기기