黒玉は白玉の4倍重い
----------------------------------------
2010年4月1日木曜日
完全弾性衝突する二つの玉
黒玉は白玉の4倍重く設定してあります
赤い点は両者の重心です
壁で跳ね返ると重心の動きが変わるけれど
黒玉と白玉の衝突では重心の動きは変化しません
(作用・反作用の法則 あるいは 運動量の保存)
けど, 本当はグラデーションの実習として作ったのです
----------------------------------------
/**
* Copyright tenasaku ( http://wonderfl.net/user/tenasaku )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/foPw
*/
/* ----------------------------------------
2010年4月1日木曜日
完全弾性衝突する二つの玉
黒玉は白玉の4倍重く設定してあります
赤い点は両者の重心です
壁で跳ね返ると重心の動きが変わるけれど
黒玉と白玉の衝突では重心の動きは変化しません
(作用・反作用の法則 あるいは 運動量の保存)
けど, 本当はグラデーションの実習として作ったのです
----------------------------------------
*/
package {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
public class Main extends Sprite {
private var ball1:MassiveBall = new MassiveBall();
private var ball2:MassiveBall = new MassiveBall();
private var baricentre:Shape = new Shape(); // 重心の位置を示す点
private var monitor:TextField = new TextField();
private function atEveryFrame(e:Event):void {
var b:MassiveBall;
for each ( b in [ball1, ball2] ) {
with (b) {
if ( x <= radius ) { Vx = Math.abs(Vx); }
if ( x >= stage.stageWidth - radius ) { Vx = -Math.abs(Vx); }
if ( y <= radius ) { Vy = Math.abs(Vy); }
if ( y >= stage.stageHeight - radius ) { Vy = -Math.abs(Vy); }
x += Vx;
y += Vy;
}
}
var Rx:Number = ball2.x - ball1.x; // 相対位置
var Ry:Number = ball2.y - ball1.y;
var rVx:Number = ball2.Vx - ball1.Vx; // 相対速度
var rVy:Number = ball2.Vy - ball1.Vy;
var distance:Number = Math.sqrt(Rx*Rx+Ry*Ry); // 距離
var scalarProd:Number = Rx*rVx+Ry*rVy; // 相対速度と相対位置の内積
if ( ( Math.abs(distance-ball1.radius-ball2.radius)<5.0 )
&& (scalarProd <= 0) ) { // 衝突!!
// 完全弾性衝突として速度の変化を計算する
var k:Number = scalarProd/(distance*distance);
ball1.Vx += k*(2*ball2.mass)/(ball1.mass+ball2.mass)*Rx;
ball1.Vy += k*(2*ball2.mass)/(ball1.mass+ball2.mass)*Ry;
ball2.Vx += -k*(2*ball1.mass)/(ball1.mass+ball2.mass)*Rx;
ball2.Vy += -k*(2*ball1.mass)/(ball1.mass+ball2.mass)*Ry;
}
baricentre.x = (ball1.x*ball1.mass+ball2.x*ball2.mass)/(ball1.mass+ball2.mass);
baricentre.y = (ball1.y*ball1.mass+ball2.y*ball2.mass)/(ball1.mass+ball2.mass);
report();
}
// 情報フィールドの更新処理
// Momentum: 運動量の大きさ
// Energy: 運動エネルギー
private function report():void {
var mX:Number = ball1.Vx*ball1.mass+ball2.Vx*ball2.mass;
var mY:Number = ball1.Vy*ball1.mass+ball2.Vy*ball2.mass;
var M:Number = Math.sqrt(mX*mX+mY*mY);
var K:Number =
0.5*ball1.mass*(ball1.Vx*ball1.Vx+ball1.Vy*ball1.Vy)
+ 0.5*ball2.mass*(ball2.Vx*ball2.Vx+ball2.Vy*ball2.Vy);
monitor.text = "Momentum: "+M.toFixed(6)+"\nEnergy: "+K.toFixed(6);
}
private function initialize(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, initialize);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
// 背景を夕焼け空ふうにする...
var m:Matrix = new Matrix();
m.createGradientBox(
stage.stageHeight/3*2, stage.stageWidth,
Math.PI/2,
0, stage.stageHeight/3
);
this.graphics.clear();
this.graphics.beginGradientFill(
GradientType.LINEAR,
[0x000066, 0x995033, 0xff9900],
[1, 1, 1],
[0, 100, 255],
m,
SpreadMethod.PAD
);
this.graphics.drawRect(0,0,stage.stageWidth,stage.stageHeight);
this.graphics.endFill();
// 情報テキストフィールドの初期化と登録
monitor.background = true;
monitor.backgroundColor = 0x999999;
monitor.alpha = 0.5;
monitor.width = 160;
monitor.height = 50;
this.addChild(monitor);
// 玉オブジェクトの初期化
with (ball1) {
bottomColor = 0x666666;
topColor = 0x000000;
radius = 50;
Vx = 0.0;
Vy = 0.0;
mass = 4.0;
}
with (ball2) {
bottomColor = 0xffffff;
topColor = 0x330033;
radius = 40;
Vx = 4.0;
Vy = 0;
mass = 1.0;
}
// with 構文の中で x と y を設定したら表示がおかしくなったので外に出す
ball1.x = stage.stageWidth/2;
ball1.y = stage.stageHeight/2;
ball2.x = ball2.radius;
ball2.y = stage.stageHeight/2+Math.random()*10-5; // 少し上下にずらす
// 設定を反映させ表示する
ball1.redraw();
ball2.redraw();
this.addChild(ball1);
this.addChild(ball2);
// 重心の位置を示すオブジェクトを生成
baricentre.graphics.clear();
baricentre.graphics.beginFill(0xff0000);
baricentre.graphics.drawCircle(0,0,5);
baricentre.graphics.endFill();
baricentre.x = (ball1.x*ball1.mass+ball2.x*ball2.mass)/(ball1.mass+ball2.mass);
baricentre.y = (ball1.y*ball1.mass+ball2.y*ball2.mass)/(ball1.mass+ball2.mass);
this.addChild(baricentre);
stage.addEventListener(Event.ENTER_FRAME, atEveryFrame);
}
public function Main():void {
if ( stage != null ) {
initialize(null);
} else {
this.addEventListener(Event.ADDED_TO_STAGE, initialize);
}
}
} // end of class Main
} // end of package
import flash.display.*;
import flash.events.*;
import flash.geom.*;
class MassiveBall extends Shape {
public var radius:Number;
public var gm:Matrix;
public var topColor:uint, bottomColor:uint;
public var Vx:Number,Vy:Number; // 速度ベクトル
public var mass:Number; // 質量
public function redraw():void {
this.graphics.clear();
gm.createGradientBox(2*radius,2*radius,Math.PI/2,0,-radius);
this.graphics.beginGradientFill(
GradientType.LINEAR,
[topColor,bottomColor], [1,1], [0,255],
gm,SpreadMethod.PAD
);
this.graphics.drawCircle(0,0,radius);
this.graphics.endFill();
}
public function MassiveBall() {
radius = 50;
gm = new Matrix();
Vx = 0;
Vy = 0;
mass = 1.0;
topColor = 0xffffff;
bottomColor = 0x666666;
redraw();
}
}