■ ボールの衝突のシミュレーション
<Flash教材>
Flash CS3で作成したボールを衝突させるシミュレーション教材です。ボールをドラッグ&ドロップすることでボールを衝突させることができます。
|
<教材の説明>
上のスラーダーは左から重力、空気抵抗、壁との 反発係数、緑球と青球の質量比をそれぞれ設定できる ようになっています。これらを設定したうえで、いずれかの球をドラッグして投げると 2つの球は互いに跳ね返り運動をします。
<ActionScript>
1フレーム目の ActionScript |
//2つの球は静止しているので、速度の初期値を0とおく ball0_vx = 0; ball0_vy = 0; ball1_vx = 0; ball1_vy = 0; //系の初期値を設定 var g:Number = 0.5;//重力 var f:Number = 0.005;//空気抵抗 var e:Number = 0.5;//壁との反発係数 var ball1_mass:Number = 1;//青球の質量 g_txt.text = "0.5"; f_txt.text = "0.5"; e_txt.text = "0.5"; mass_txt.text = "1"; |
2フレーム目の ActionScript |
// スライダーの設定 import fl.controls.Slider; import fl.events.SliderEvent; //以下の物理量を選択 //重力g SLg.addEventListener(SliderEvent.CHANGE, changeHandlerSLg); function changeHandlerSLg(e1:SliderEvent):void { var gx:int = e1.value; g = gx*0.01; g_txt.text = String(g); } //空気抵抗f SLf.addEventListener(SliderEvent.CHANGE, changeHandlerSLf); function changeHandlerSLf(e2:SliderEvent):void { var fx:int = e2.value; f = fx*0.01; f_txt.text = String(f); f *= 0.01;//fだけは0.1と表示しても、0.001程度でなくてはならない } //壁との反発係数e SLe.addEventListener(SliderEvent.CHANGE, changeHandlerSLe); function changeHandlerSLe(e3:SliderEvent):void { var ex:int = e3.value; e = ex*0.01; e_txt.text = String(e); } //青球の質量である、ball1_mass SLm.addEventListener(SliderEvent.CHANGE, changeHandlerSLm);//ball1_mass function changeHandlerSLm(e4:SliderEvent):void { var mass:int = e4.value; ball1_mass = mass*0.1+0.9; mass_txt.text = String(ball1_mass); } //境界を設定 var left:Number = 0; var top:Number = 0; var right:Number = 550; var bottom:Number = 400; //緑球の質量を1とする var ball0_mass:Number = 1; //2球の半径 var ball0_radius:Number = 30; var ball1_radius:Number = 30; //ドラッグの変数 var oldX0:Number; var oldY0:Number; var ball0_vx:Number; var ball0_vy:Number; var v0:Number; var angle0:Number; //緑球の上でマウスを押すと、動きが止まり、自由にドラッグできるようにする ball0.addEventListener(MouseEvent.MOUSE_DOWN, x0MouseDown); function x0MouseDown(event:MouseEvent):void { ball0.removeEventListener(Event.ENTER_FRAME, x0EnterFrame); oldX0 = ball0.x;//物体の位置xを、oldX0とする oldY0 = ball0.y;//物体の位置yを、oldY0とする ball0.addEventListener(MouseEvent.MOUSE_UP, x0MouseUp); ball0.startDrag();//ドラッグ開始。mouseDownハンドラで呼び出された addEventListener(Event.ENTER_FRAME, x0trackVelocity); } //ドロップしたときに、ドラッグ中の速度を、球の速度にする function x0trackVelocity(event:Event):void { ball0_vx = ball0.x - oldX0;//現在のx速度 ball0_vy = ball0.y - oldY0;//現在のy速度 oldX0 = ball0.x; oldY0 = ball0.y; } //マウスを離すと、enterFrameイベントが開始され、離す直前のx速度、y速度が保持される function x0MouseUp(event:MouseEvent):void { ball0.stopDrag();//ドラッグ中止。mouseUpハンドラで呼び出された removeEventListener(Event.ENTER_FRAME, x0trackVelocity); ball0.addEventListener(Event.ENTER_FRAME, x0EnterFrame); } //緑球のモーション ball0.addEventListener(Event.ENTER_FRAME, x0EnterFrame); function x0EnterFrame(event:Event) { ball0_vy += g;//y方向に1フレームgで加速される v0 = Math.sqrt(ball0_vx * ball0_vx + ball0_vy * ball0_vy); angle0 = Math.atan2(ball0_vy, ball0_vx);//atan2、なす角が辺の比と1対1に対応 if(v0 > f){ v0 -= f;//摩擦により減速させる }else{ v0 = 0;//速さが十分小さくなれば静止させる } //速度を分解 ball0_vx = v0 * Math.cos(angle0); ball0_vy = v0 * Math.sin(angle0); //位置に加える ball0.x += ball0_vx; ball0.y += ball0_vy; //物体が四方の壁に衝突したときの、跳ね返りのようす if(ball0.x + ball0_radius > right) { ball0.x = right - ball0_radius;//位置を境界面に修正する ball0_vx *= -e;//反発係数eをかけて、減速させる }else if(ball0.x - ball0_radius < left) { ball0.x = left + ball0_radius; ball0_vx *= -e; } if(ball0.y + ball0_radius > bottom) { ball0.y = bottom - ball0_radius; ball0_vy *= -e; }else if(ball0.y - ball0_radius < top) { ball0.y = top + ball0_radius; ball0_vy *= -e; } } //ドラッグの変数 var oldX1:Number; var oldY1:Number; var ball1_vx:Number; var ball1_vy:Number; var v1:Number; var angle1:Number; //青球の上でマウスを押すと、動きが止まり、自由にドラッグできるようにする。 ball1.addEventListener(MouseEvent.MOUSE_DOWN, x1MouseDown); function x1MouseDown(event:MouseEvent):void { ball1.removeEventListener(Event.ENTER_FRAME, x1EnterFrame); oldX1 = ball1.x;//現在の位置xを、古い位置oldX0とする oldY1 = ball1.y;//yについても同じ ball1.addEventListener(MouseEvent.MOUSE_UP, x1MouseUp); ball1.startDrag();//mouseDownハンドラで呼び出された addEventListener(Event.ENTER_FRAME, x1trackVelocity); } //ドロップしたときに、ドラッグ中の速度を、球の速度にする。 function x1trackVelocity(event:Event):void { ball1_vx = ball1.x - oldX1;//現在のx速度 ball1_vy = ball1.y - oldY1;//現在のy速度 oldX1 = ball1.x; oldY1 = ball1.y; } //マウスを離すと、enterFrameイベントが開始され、離す直前のx速度、y速度が保持される function x1MouseUp(event:MouseEvent):void { ball1.stopDrag();//mouseUpハンドラで呼び出された removeEventListener(Event.ENTER_FRAME, x1trackVelocity); ball1.addEventListener(Event.ENTER_FRAME, x1EnterFrame); } //青球のモーション ball1.addEventListener(Event.ENTER_FRAME, x1EnterFrame); function x1EnterFrame(event:Event) { ball1_vy += g;//下方向に1フレームgで加速される v1 = Math.sqrt(ball1_vx * ball1_vx + ball1_vy * ball1_vy); angle1 = Math.atan2(ball1_vy, ball1_vx); if(v1 > f){ v1 -= f;//摩擦により減速させる }else{ v1 = 0;//速さが十分小さくなれば静止させる } //速度を分解 ball1_vx = v1 * Math.cos(angle1); ball1_vy = v1 * Math.sin(angle1); //位置に加える ball1.x += ball1_vx; ball1.y += ball1_vy; //物体が四方の壁に衝突したときの、跳ね返りのようす if(ball1.x + ball1_radius > right) { ball1.x = right - ball1_radius;//位置を境界面に修正する ball1_vx *= -e;//反発係数eをかけて、減速させる }else if(ball1.x - ball1_radius < left) { ball1.x = left + ball1_radius; ball1_vx *= -e; } if(ball1.y + ball1_radius > bottom) { ball1.y = bottom - ball1_radius; ball1_vy *= -e; }else if(ball1.y - ball1_radius < top) { ball1.y = top + ball1_radius; ball1_vy *= -e; } } //以下、球の衝突を記述 addEventListener(Event.ENTER_FRAME, xEnterFrame); function xEnterFrame(event:Event) { var dx:Number = ball1.x - ball0.x; var dy:Number = ball1.y - ball0.y; var dist:Number = Math.sqrt(dx * dx + dy * dy);//2球の中心間の距離 if(dist < ball0_radius+ball1_radius) { var angle:Number=Math.atan2(dy,dx);//2球の相対位置がわかる var sin:Number=Math.sin(angle); var cos:Number=Math.cos(angle); //ball0の位置を(0,0)に固定 var x0:Number=0; var y0:Number=0; //ball1を回転させ、x軸上の衝突に帰着させる var x1:Number=dx*cos+dy*sin; var y1:Number=dy*cos-dx*sin; //ball0の速度を回転させる var vx0:Number=ball0_vx*cos+ball0_vy*sin; var vy0:Number=ball0_vy*cos-ball0_vx*sin; //ball1の速度も同様 var vx1:Number=ball1_vx*cos+ball1_vy*sin; var vy1:Number=ball1_vy*cos-ball1_vx*sin; //x軸上の衝突を考える var vxTotal:Number=vx0-vx1;//ball1からみた速度 vx0=((ball0_mass-ball1_mass)*vx0+2*ball1_mass*vx1)/(ball0_mass+ball1_mass); vx1=vxTotal+vx0; //補正のパラメーター var absV:Number=Math.abs(vx0)+Math.abs(vx1);//速さの絶対和 var overlap:Number=(ball0_radius+ball1_radius)-Math.abs(x0-x1);//2球の重なり //x軸上での位置の更新 x0+=vx0/absV*overlap; x1+=vx1/absV*overlap; //位置を回転させて元に戻す var x0Final:Number=x0*cos-y0*sin; var y0Final:Number=y0*cos+x0*sin; var x1Final:Number=x1*cos-y1*sin; var y1Final:Number=y1*cos+x1*sin; //実際の位置への更新 ball1.x=ball0.x+x1Final; ball1.y=ball0.y+y1Final; ball0.x=ball0.x+x0Final; ball0.y=ball0.y+y0Final; //速度を回転させて元に戻す ball0_vx=vx0*cos-vy0*sin; ball0_vy=vy0*cos+vx0*sin; ball1_vx=vx1*cos-vy1*sin; ball1_vy=vy1*cos+vx1*sin; } gotoAndPlay("a0"); } |
>>TOP