본문 바로가기
♣ 강좌/플래시

제15강 1차원 충돌의 액션 구현

by 칠칠너래 2006. 3. 25.

1. 학습목표

    직선 상에서의 운동량 보존의 법칙을 액션으로 구현할 수 있다.

 

지난 강좌에서 배운 내용 복습하기(사전 지식)

 
운동량 보존 법칙 :
 
반발 계수 :

 

 

2. 운동량 보존 법칙의 액션 구현

 

깜짝 수학: 구의 부피

 

  보통 수박 한 덩이리가 4,000원 합니다. 보통 수박에 비해 지름이 정확히 2배 더 큰 수박이 20,000원 한다고 합니다. 20,000원어치 수박을 산다고 할 때 4,000원짜리 5덩이를 사겠습니까? 20,000원짜리 1덩이를 사겠습니까?

 

  아주 쉬운 수학문제입니다. 얼핏 보통 수박 5덩이를 사는 것이 수박을 더 많이 먹을 것 같은데요, 20,000원짜리 하나를 사는 것이 훨씬 이득입니다.

 

  언제 배우는지는 잘 모르겠지만 구의 부피는 따라 반지름의 세제곱에 비례합니다. 그러니까 반지름이 2배가 되면 부피는 배가 되는 것입니다. 결론적으로 20,000원짜리 하나를 사면 4,000원짜리 8개를 산 것과 같다는 것입니다.

 

  실제로는 4,000원짜리 8개보다 더 많이 먹습니다. 왜냐하면 4,000원짜리 8개의 껍데기가 더 많거든요. 구의 표면적은 에 따라 반지름의 제곱에 비례합니다. 반지름을 1이라고 할 때 4,000원짜리 8개의 표면적은 가 됩니다. 반면 반지름이 2배인 20,000원짜리의 표면적은 가 되는 거죠. 결국 4,000원짜리 8개를 사는 것보다 20,000원짜리 하나를 사는 것이 더 많은 수박을 먹을 수 있다는 거죠. ^^

 

  여기서 딴지를 걸고 싶은 사람이 있을 지도 모르겠네요, 4,000원짜리가 더 맛있다고... 뭐 어쩔 수 없죠. 개인적인 성향이니... -.-;

 

  그런데 왜 반지름이 2배가 될 때 가격은 8배가 안되는 걸까요? 파는 사람이 수학을 잘 몰라서 그래요. 그렇다고 그렇게 팔면 또 잘 안팔리겠죠? 사는 사람도 수학을 잘 모르니까요. ^^

 

1. 공 그림의 무비클립을 만들어 식별자를 써 넣는다. (여기선 ball이라고 합시다.)

2. 첫번째 프레임에 다음과 같이 써서 무비클립을 삽입하고 왼쪽과 오른쪽에 각각 위치 시킨다.

   그리고 질량 값을 랜덤하게 갖도록 하여 크기를 결정한다.

   

mA=10+random(20);   //10~30사이의 값

mB=10+random(20);

_root.attachMovie("ball","ballA",1); 

_root["ballA"]._x = 100;              
_root["ballA"]._y = 100;

_root["ballA"]._width=_root["ballA"]._height=10*Math.pow(mA, 1/3); 

//질량(부피에 비례)은 반지름의 세제곱에 비례하므로

//반지름은 질량의 세제곱근에 비례합니다. ( )

//Math.pow(x,y) 형태는 x의 값을 y만큼 거듭제곱한다는 뜻입니다.

//세제곱근은 y값으로 1/3을 넣으면 됩니다.

 

_root.attachMovie("ball","ballB",2); 

_root["ballB"]._x = 400;              
_root["ballB"]._y = 100;

_root["ballB"]._width=_root["ballB"]._height=10*Math.pow(mB, 1/3);

 

3. 각각의 속도를 랜덤하게 정하고 onEnterFrame을 이용하여 공이 움직이도록 한다. 이 때 좌 우

   벽에 부딪치면 튕겨나게 한다. (이 강좌부터는 setInterval 대신에 onEnterFrame으로 바꿀 생각

   입니다. onEnterFrame이 더 부드러운 듯 하여... ^^)

   

mA=10+random(20);  

mB=10+random(20);

vA = 10-random(20); //-10~10 사이의 값. 좌우로 움직이게 하기 위합입니다.
vB = 10-random(20);

_root.attachMovie("ball","ballA",1); 

_root["ballA"]._x = 100;              
_root["ballA"]._y = 100;

_root["ballA"]._width=_root["ballA"]._height=10*Math.pow(mA, 1/3); 

_root.attachMovie("ball","ballB",2); 

_root["ballB"]._x = 400;              
_root["ballB"]._y = 100;

_root["ballB"]._width=_root["ballB"]._height=10*Math.pow(mB, 1/3);

//박스의 왼쪽, 오른쪽 여백이 각각 10입니다.

this.onEnterFrame = function() {
  if (ballA._x-ballA._width/2+vA<10 || ballA._x+ballA._width/2+vA>490){
    vA *= -1;
  }

  //볼 A의 중심좌표(_x)에서 볼의 폭의 반을 뺀 좌표(볼의 맨 왼쪽의 좌표)에

  //볼의 속력을 적용시킬 때 10보다 작으면 속도의 방향이 반대로 되라는 뜻

  //또한 볼A의 중심좌표에서 볼의 폭의 반을 더한 좌표(볼의 맨 오른쪽 좌표)에

  //볼의 속력을 적용시킬 때 490보다 크면 속도의 방향이 반대가 되라는 뜻

  //같은 원리를 공 B에도 적용시킵니다.
  if (ballB._x-ballB._width/2+vB<10 || ballB._x+ballB._width/2+vB>490){
    vB *= -1;
  }
  ballA._x += vA;  //속력을 적용합니다. 왜 이렇게 하는지 잘 이해가 안되면
  ballB._x += vB;  //7강의 속도와 가속도 개념을 공부하세요...
};


   

4. 충돌을 감지하여 충돌하면 완전탄성충돌하여 공이 튕기게 한다. (물론 당연히 운동량이 보존되게

   해야겠죠? ^^)

사전 계산 :  충돌 후 공 A와 B의 속도는 어떻게 될까?

 
# 우리가 알고 싶은 미지수는 2개입니다. 충돌 후 공 A의 속도와 공 B의 속도죠. 2개의 미지수를 알려면 몇 개의 식이 필요할까요? ^^
 
학교 다닐 때 수학시간에 졸지 않고 열심히 들은 사람은 알꺼예요... 2개라고. 그렇습니다. 2개의 식이 필요하죠. 어떤 식일까요? 바로 전 강좌에서 배웠던 운동량 보존법칙과 반발 계수와 관련된 식이죠.
 
운동량 보존 법칙은 입니다. 이 식을 위에서 사용한 공 A와 B의 질량과 속도 변수를 사용해서 기술해 봅시다. 충돌 후 A의 속도를 vAp(브이 에이 프라임), 충돌 후 B의 속도를 vBp이라고 하면 운동량 보존 법칙에 의해 다음과 같은 식이 됩니다.
 
  mA*vA + mB*vB = mA*vAp + mB*vBp  ----1번식
 
반발 계수 식은 입니다. 역시 이 식을 위에서 사용한 공 A와 B의 질량, 속도 변수를 사용해서 기술해 봅시다. 완전탄성 충돌한다고 했으므로 반발 계수가 1이 됩니다. 그러나 e의 값이 1이 안되게도 할 수 있게 하려면 e 그대로 계산하면 됩니다. 따라서,
 
   e*vA - e*vB = vBp - vAp    ----2번식
 
이 됩니다.
 
2번식을 vBp에 대한 식으로 바꾸면 vBp = e*vA - e*vB + vAp 입니다. 이 식을 1번 식에 대입합니다. 그러면 vAp의 값을 알 수 있죠.
 
  mA*vA + mB*vB = mA*vAp + mB*(e*vA - e*vB + vAp) 를 전개하면
  mA*vA + mB*vB = mA*vAp + mB*e*vA - mB*e*vB + mB*vAp 에서 vAp를 묶으면
  (mA+mB)*vAp = mA*vA + mB*vB - mB*e*vA + mB*e*vB  를 정리하면
  (mA+mB)*vAp = (mA-mB*e)*vA + (mB+mB*e)*vB 가 됩니다. 따라서 vAp는...
 
  vAp = (mA-mB*e)/(mA+mB)*vA + (mB+mB*e)/(mA+mB)*vB 가 됩니다.
 
  
위 식의 오른쪽 항은 공의 질량과 충돌 전 각각의 공의 속도인 것을 알 수 있습니다. 그러니까 충돌 전의 질량과 속도에 의해 충돌 후의 속도가 결정되는 셈이죠.
 
이제 앞에서 구한 vAp를 2번 식에 대입하면 vBp의 값도 구할 수 있죠. 이 풀이 과정은 생략하겠습니다. 결과는
 
  vBp = (mA+mA*e)/(mA+mB)*vA + (mB-mA*e)/(mA+mB)*vB 가 됩니다.
 

 

자 이제 식도 완성되었고 하니 액션으로 구현해 봅시다.

   

e=1;

mA=10+random(20);  

mB=10+random(20);

vA = 10-random(20); 
vB = 10-random(20);

_root.attachMovie("ball","ballA",1); 

_root["ballA"]._x = 100;              
_root["ballA"]._y = 100;

_root["ballA"]._width=_root["ballA"]._height=10*Math.pow(mA, 1/3); 

_root.attachMovie("ball","ballB",2); 

_root["ballB"]._x = 400;              
_root["ballB"]._y = 100;

_root["ballB"]._width=_root["ballB"]._height=10*Math.pow(mB, 1/3);

this.onEnterFrame = function() {

  if (ballA.hitTest(ballB)) {

    //별거 없습니다. 앞에서 계산한 거 그대로 넣으면 되요. ^^
    vAp = (mA-mB*e)/(mA+mB)*vA+(mB+mB*e)/(mA+mB)*vB;
    vBp = (mA+mA*e)/(mA+mB)*vA+(mB-mA*e)/(mA+mB)*vB;
    vA=vAp;   //충돌 후의 속도를 적용하기 위해...
    vB=vBp;
  }
  if (ballA._x-ballA._width/2+vA<10 || ballA._x+ballA._width/2+vA>490){
    vA *= -1;
  }

  if (ballB._x-ballB._width/2+vB<10 || ballB._x+ballB._width/2+vB>490){
    vB *= -1;
  }
  ballA._x += vA;  
  ballB._x += vB; 
};

 

   

 


3. 과제

 

1. 반발 계수가 0.5가 되면 어떻게 될까요? 예측해 보고 모의실험 해 봅시다.

2. 공 3개를 놓고 충돌하는 거 구현해 볼래요? ^^

3. 평면상에서의 충돌이나 3차원상의 충돌은 어떻게 구현할까요? (다음 강좌에서 평면상의 충돌에 대해 다루겠습니다. 그 전에 나름대로 심각하게 고민들 해보세요. ^^)