■ ボールの衝突のシミュレーション

<Flash教材>

 Flash CS3で作成したボールを衝突させるシミュレーション教材です。ボールをドラッグ&ドロップすることでボールを衝突させることができます。

Gravity重力
Friction空気抵抗
Gravity壁との反発係数

<教材の説明>

上のスラーダーは左から重力、空気抵抗、壁との 反発係数、緑球と青球の質量比をそれぞれ設定できる ようになっています。

これらを設定したうえで、いずれかの球をドラッグして投げると 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