code on 2008-12-23
クラス
package {
import flash.display.*;
import flash.text.*;
import flash.ui.*;
import flash.utils.*;
import flash.events.*;
import flash.net.*;
import flash.geom.*;
//クラス
public class VecTest extends Sprite {
//変数宣言
private var left :Boolean = false;
private var right :Boolean = false;
private var up :Boolean = false;
private var down :Boolean = false;
private var ball:Sprite;
private var rad:int = 5;
private var vx:Number = 0;
private var vy:Number = 0;
private var fld:Sprite;
private var lines:Array = new Array();
private var courseData:Array =
[
[100,300,500,300],
[500,300,200,350],
[200,350,300,400],
];
//コンストラクタ
public function VecTest() {
//初期化
//ボールの描画
ball = new Sprite();
ball.x = 250;
ball.y = 20;
ball.graphics.beginFill(0xff0000);
ball.graphics.drawCircle(0,0,rad);
ball.graphics.endFill();
addChild(ball);
//コースの線が乗るSprite
fld = new Sprite();
addChild(fld);
//courseDataのデータに沿って線を描画
var t:Sprite = new Sprite();
for(var i:int=0; i<courseData.length; i++){
t.graphics.lineStyle(1,0x0000ff);
t.graphics.moveTo(courseData[i][0], courseData[i][1]);
t.graphics.lineTo(courseData[i][2], courseData[i][3]);
}
fld.addChild(t);
//イベントリスナーの登録
stage.addEventListener(Event.ENTER_FRAME, EnterFrame);
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp);
}
//フレームごとの処理
private function EnterFrame(e:Event) : void {
//回転する角度を取得
var deg:int = 0;
if(left ){ deg += 2; }
if(right){ deg -= 2; }
//回転が必要なら
if(deg != 0){
var pPos:Point = fld.globalToLocal(new Point(275, 200));
var oPos:Point; //回転前の座標
var nPos:Point; //回転後の座標
// 回転前と回転後のグローバル座標にそれぞれ変換
oPos = fld.localToGlobal(pPos); //回転前
fld.rotation += deg; //実際に回転させる
nPos = fld.localToGlobal(pPos); //回転後
// 回転前と回転後の座標の差を補正
fld.x += oPos.x - nPos.x;
fld.y += oPos.y - nPos.y;
}
if(up && vy > 0){
vy--;
}
if(vy < 30){
vy++;
}
ball.x += vx;
ball.y += vy;
if(ball.x < 0 || ball.x > 550){
vx = -vx;
}
if(ball.y < 0 || ball.y > 400){
vy = -vy;
}
for(var i:int=0; i<courseData.length; i++){
calcVecLine(courseData[i]);
}
}
//////////////////////////////////////////////////////
//線(pt1.x, pt1.y),(pt2.x, pt2.y)と交差するか判定する
//////////////////////////////////////////////////////
private function calcVecLine( data:Array ):Boolean{
var flg:Boolean = false;
var nx:Number;
var ny:Number;
var len:Number;
var ft:Number;
var fb:Number;
var cx:Number;
var cy:Number;
var sx:Number;
var sy:Number;
var t:Number;
var pt1:Point;
var pt2:Point;
var mtx:Matrix;
var tmp:Array;
//------------------------------------------------------
//変換行列のデータを取得
mtx = fld.transform.matrix;
//座標を回転後の座標にしてpt1とpt2に設定
pt1 = mtx.deltaTransformPoint(new Point(data[0],data[1]));
pt2 = mtx.deltaTransformPoint(new Point(data[2],data[3]));
pt1.offset(fld.x,fld.y);
pt2.offset(fld.x,fld.y);
//------------------------------------------------------
//線の法線のベクトルを計算して正規化する
nx = pt2.y - pt1.y;
ny = pt1.x - pt2.x;
len = Math.sqrt(nx * nx + ny * ny); //辺の長さを計算
if(len > 0){ len = 1/len; }
nx *= len;
ny *= len;
//------------------------------------------------------
//球が表面へ侵入するときのみ判定をする。
//ベクトルの内積が負の数の時表面
fb = nx * vx + ny * vy;
if(fb <= 0){
//球から面と垂直な線
sx = -nx * rad;
sy = -ny * rad;
//-----------------------------------------------------------------
//玉の半径と移動軌跡の2パターンで調べる
//計算用
ft = nx * ball.x + ny * ball.y - (pt1.x * nx + pt1.y * ny);
tmp = [ [(nx * sx + ny * sy), sx, sy] , [fb, vx, vy] ];
//判定の実行
for(var i:int=0; i<2 && flg == false; i++){
//倍数(t)が0~1なら交差している
t = -ft / tmp[i][0];
if( 0 < t && t <= 1.0 ){
//線と交差する座標を算出
cx = ball.x + tmp[i][1] * t;
cy = ball.y + tmp[i][2] * t;
//交差する座標が線分の間か調べる
//ベクトルの内積が負の数の時は範囲内
flg = (cx - pt1.x) * (cx - pt2.x) + (cy - pt1.y) * (cy - pt2.y) < 0;
}
}
//------------------------------------------------------
if(flg == true){
//交差位置に位置修正
ball.x = (cx + nx * rad);
ball.y = (cy + ny * rad);
//動きを反射させる 反射率 1.0~2.0
t = - fb / (nx * nx + ny * ny);
vx += t * nx * 2;
vy += t * ny * 2;
}
}
return flg;
}
//キーが押された時の処理
private function KeyDown(e:KeyboardEvent) : void {
switch(e.keyCode){
case Keyboard.LEFT:
left = true;
break;
case Keyboard.RIGHT:
right = true;
break;
case Keyboard.UP:
up = true;
break;
case Keyboard.DOWN:
down = true;
break;
}
}
//キーが離された時の処理
private function KeyUp(e:KeyboardEvent) : void {
switch(e.keyCode){
case Keyboard.LEFT:
left = false;
break;
case Keyboard.RIGHT:
right = false;
break;
case Keyboard.UP:
up = false;
break;
case Keyboard.DOWN:
down = false;
break;
}
}
}
}