forked from: 衝突判定 http://sakef.jp/blog/2010/10/ball_collision01/
♥0 |
Line 179 |
Modified 2012-08-15 03:39:42 |
MIT License
archived:2017-03-30 08:33:05
ActionScript3 source code
/**
* Copyright hemingway ( http://wonderfl.net/user/hemingway )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/uVvn
*/
// forked from tayapon's 衝突判定 http://sakef.jp/blog/2010/10/ball_collision01/
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(backgroundColor="0xFFFFFF")]
public class Physics01 extends Sprite
{
// はねかえり定数
private static const E:Number = 0.8;
// ボールの半径
private static const RADIUS:Number = 40;
// 摩擦
private static const D:Number = 0.99;
// ボールの数
private static const BALL_NUM:int = 3;
// ボールを保存する変数
private var balls:Vector.<Ball>;
// ドラッグ用
private var drag_ball:int;
private var mouse_x:Number;
private var mouse_y:Number;
// コンストラクタ
public function Physics01()
{
// ステージの設定
stage.frameRate=60;
stage.quality=StageQuality.HIGH;
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;
// ボールを保存するVector
balls = new Vector.<Ball>(BALL_NUM, true);
// ボールの作成
for(var i:int=0 ; i<BALL_NUM ; i++)
{
var ball:Ball = addChild(new Ball(Math.random()*(stage.stageWidth - RADIUS), Math.random()*(stage.stageHeight - RADIUS), RADIUS, i)) as Ball;
balls[i] = ball;
ball.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
}
// ドラッグの用意
mouse_x = mouseX;
mouse_y = mouseY;
drag_ball = -1;
// フレームイベントの追加
addEventListener(Event.ENTER_FRAME, onFrame);
}
// マウスアップ時に実行する関数
private function onUp(e:MouseEvent):void
{
var ball:Ball = balls[drag_ball];
drag_ball = -1;
stage.removeEventListener(MouseEvent.MOUSE_UP , onUp);
ball.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
}
// マウスダウン時に実行する関数
private function onDown(e:MouseEvent):void
{
var ball:Ball = (e.target as Ball);
drag_ball = ball.id;
stage.addEventListener(MouseEvent.MOUSE_UP , onUp);
ball.removeEventListener(MouseEvent.MOUSE_DOWN, onDown);
}
// フレームイベント用関数
private function onFrame(evt:Event):void
{
// ドラッグ中のノードを計算
var ball:Ball;
if(drag_ball != -1)
{
var dx:Number = mouseX - mouse_x;
var dy:Number = mouseY - mouse_y;
ball = balls[drag_ball];
ball.dx = dx;
ball.dy = dy;
ball.x = mouseX;
ball.y = mouseY;
}
mouse_x = mouseX;
mouse_y = mouseY;
// 衝突判定
var i:int;
var j:int;
var a:Ball;
var b:Ball;
for(i=0 ; i<BALL_NUM ; i++)
{
for(j = 0 ; j<BALL_NUM ; j++)
{
if( j<= i) continue;
a = balls[i];
b = balls[j];
// ABベクトルを計算
var AB_x:Number = b.x - a.x;
var AB_y:Number = b.y - a.y;
// 2つの円の中心間の距離
var tr:Number = a.radius + b.radius;
// 三平方の定理より衝突判定を行う
if(AB_x * AB_x + AB_y * AB_y < tr * tr)
{
// 円がめりこんだ量を計算
var len:Number = Math.sqrt(AB_x * AB_x + AB_y * AB_y);
var distance:Number = (a.radius + b.radius) - len;
if(len > 0) len = 1 / len;
AB_x *= len;
AB_y *= len;
// めり込んだ量の半分ずつを追加
distance /= 2.0;
a.x -= AB_x * distance;
a.y -= AB_y * distance;
b.x += AB_x * distance;
b.y += AB_y * distance;
// 衝突後の速度を計算
var s1:Number = a.dx * AB_x + a.dy*AB_y;
var s2:Number = b.dx * AB_x + b.dy*AB_y;
var vn1_x:Number = AB_x * s1;
var vn1_y:Number = AB_y * s1;
var vn2_x:Number = AB_x * s2;
var vn2_y:Number = AB_y * s2;
var vt1_x:Number = a.dx - vn1_x;
var vt1_y:Number = a.dy - vn1_y;
var vt2_x:Number = b.dx - vn2_x;
var vt2_y:Number = b.dy - vn2_y;
var new_s1:Number = (a.m*s1 + b.m*s2 - b.m*E*(s1 - s2))/(a.m + b.m);
var new_s2:Number = (a.m*s1 + b.m*s2 + a.m*E*(s1 - s2))/(a.m + b.m);
var new_vn1_x:Number = AB_x * new_s1;
var new_vn1_y:Number = AB_y * new_s1;
var new_vn2_x:Number = AB_x * new_s2;
var new_vn2_y:Number = AB_y * new_s2;
a.dx = new_vn1_x + vt1_x;
a.dy = new_vn1_y + vt1_y;
b.dx = new_vn2_x + vt2_x;
b.dy = new_vn2_y + vt2_y;
}
}
}
// 座標の更新
for(i=0;i<BALL_NUM;i++)
{
ball = balls[i];
// ドラッグされているものはスキップする
if(ball.id != drag_ball)
{
// 速度に摩擦を乗算
ball.dx *= D;
ball.dy *= D;
// 速度を座標に加算
ball.x += ball.dx;
ball.y += ball.dy;
// 壁との当たり判定
if(ball.x < RADIUS)
{
ball.x = RADIUS;
ball.dx *= -1;
}
if(ball.y < RADIUS)
{
ball.y = RADIUS;
ball.dy *= -1;
}
if(ball.x > stage.stageWidth-RADIUS)
{
ball.x = stage.stageWidth-RADIUS;
ball.dx *= -1;
}
if(ball.y > stage.stageHeight-RADIUS)
{
ball.y = stage.stageHeight-RADIUS;
ball.dy *= -1;
}
}
}
}
}
}
// ボールクラス
import flash.display.Sprite;
import flash.filters.DropShadowFilter;
class Ball extends Sprite
{
// 色をもつ配列
private static const colors:Array = [0x770000, 0x007700, 0x000077, 0x777700];
// 半径・ID・速度・質量
public var radius:Number;
public var id:int;
public var dx:Number;
public var dy:Number;
public var m:Number;
public function Ball(x:Number, y:Number, radius:Number, id:int)
{
// 変数初期化
this.x = x;
this.y = y;
this.id = id;
this.radius = radius;
// radius・dx・dy・mの初期化
dx = 6*Math.random() - 3;
dy = 6*Math.random() - 3;
m = 10;
// 円の描写
graphics.beginFill(colors[id%4],1);
graphics.drawCircle(0,0, radius);
graphics.endFill();
graphics.beginFill(0xffffff,1);
graphics.drawCircle(0,0,radius*0.5);
graphics.endFill();
// フィルタとか
z = 0;
cacheAsBitmap = true;
filters = [new DropShadowFilter(4,45,0x444444, 0.5)];
}
}