■ ボールの衝突のシミュレーション
<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