flashで物理演算

ようやくmixiアプリ2作目リリース。
http://mixi.jp/run_appli.pl?id=19303

このアプリでも若干物理演算を入れているものの、
弾道計算自体は、
昔習った物理の法則でx方向は一定、y方向は等加速度を使って、簡単にできた。
x = 一定;
y = -1/2*g*t*t (g=9.8);

次回はピンボールのようなボールの衝突をゲームに取り入れたいと思い、
調べたので自分メモ。
参考)
http://hakuhin.jp/as/collision.html#COLLISION_00


①状況作成
状況:投げるボール1個、固定された壁1枚

②初期設定
1.ボールの位置(my_x,my_y)
2.ボールの加速度の方向(my_dx,my_dy)
3.壁のベクトル(sx,sy)
4.壁と垂直な法線ベクトル(nx,ny)
を用意。

③円と線が交差しているかどうかのチェック
参考サイトには下記のように書いてあるが、難しいので、丸覚えすることに。。
「移動ベクトルをどれくらい伸ばせば線と交差点に到達するか調べる、この倍率をtとする。」
var d = -(ax * nx + ay * ny);
var t = -(nx * my_x + ny * my_y + d) / (nx * sx + ny * sy);
「t が 0 より大きく 1 以下の場合は交差している。」

④交点を調べる
var cx = my_x + t * sx;
var cy = my_y + t * sy;

④衝突の処理(交点に垂直方向にボールの中心座標を持ってくる)=線に円を乗っける。
my_x = cx + my_rad * nx;
my_y = cy + my_rad * ny;

⑤反射方向の計算(反射係数:0.8)
var t = -(nx * dx + ny * my_dy)/(nx * nx + ny * ny);
dx += t * nx * 2 * 0.8;
dy += t * ny * 2 * 0.8;

onClipEvent (load) {
	//円のパラメータ(my)
	my_x = this._x;
	my_y = this._y;
	//移動量
	my_dx = 0;
	my_dy = 0;
	//円半径
	my_rad = 25;
	//ブロックのパラメーター(a/b)
	bx = 50;
	by = 250;
	ax = 250;
	ay = 250;
	//円の加速度を初期化
	var dx = 0;
	var dy = 0;
	mouse_dx = 0;
	mouse_dy = 0;
	fx = 0;
	fy = 0;
	//始点から終点のベクトル(s)
	var sx = bx-ax;
	var sy = by-ay;
	length = Math.sqrt((sx*sx)+(sy*sy));
	if (length>0) {
		length = 1/length;
	}
	sx *= length;
	sy *= length;
	//線の法線(n)
	var nx = -(sy);
	var ny = sx;
	//ドラッグ中
	var drag = false;
}
onClipEvent (enterFrame) {
	// 過去5フレームの平均を取る
	mouse_dx = (mouse_dx*4+_root._xmouse-fx)/5;
	mouse_dy = (mouse_dy*4+_root._ymouse-fy)/5;
	// マウス座標退避
	fx = _root._xmouse;
	fy = _root._ymouse;
	// ドラッグ中なら処理しない
	if (drag) {
		return;
	}
	//落下速度    
	dy += 0.3;
	// 移動量の単位ベクトル
	var length = Math.sqrt((dx*dx)+(dy*dy));
	if (length>0) {
		length = 1/length;
	}
	var vx = dx*length;
	var vy = dy*length;
	//円を動かす
	_x += dx;
	_y += dy;
	// 速度制限
	if (Math.sqrt(dx*dx+dy*dy)>my_rad) {
		var length = Math.sqrt((dx*dx)+(dy*dy));
		if (length>0) {
			length = 1/length;
		}
		dx = dx*length;
		dy = dy*length;
		dx *= my_rad;
		dy *= my_rad;
	}
	//玉から面と垂直な線を出して面と交差するか調べる 
	var sx = -nx*my_rad;
	//法線×半径
	var sy = -ny*my_rad;
	//法線×半径
	var d = -(ax*nx+ay*ny);
	var t = -(nx*_x+ny*_y+d)/(nx*sx+ny*sy);
	_root.t_txt = t;
	//線と交差している
	if (t>0 && t<=1) {
		//交差
		var cx = _x+t*sx;
		var cy = _y+t*sy;
		//交差が線分の間にあるか調べる
		var acx = cx-ax;
		var acx = cy-ay;
		var bcx = cy-by;
		var bcy = cy-by;
		if ((acx*bcx)+(acy*byc)<=0) {
			//当たり
			//trace("atari");
			//反射ベクトルを計算する
			if ((acx*bcx)+(acy*bcy)<=0) {
				_x = cx+my_rad*nx;
				_y = cy+my_rad*ny;
				// 反射ベクトル
				var t = -(nx*dx+ny*dy)/(nx*nx+ny*ny);
				dx += t*nx*2*0.73;
				dy += t*ny*2*0.73;
				continue;
			}
		}
	}
}