In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

円同士が衝突するまでのフレーム時間検出

-------------------------------------------------
円同士が衝突するまでのフレーム時間検出
円は、ドラッグすることができます。
円以外の余白をクリックすると円を追加できます。
-------------------------------------------------
/**
 * Copyright Hakuhin ( http://wonderfl.net/user/Hakuhin )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/q2fX
 */

// -------------------------------------------------
//
// 円同士が衝突するまでのフレーム時間検出
//
// 円は、ドラッグすることができます。
// 円以外の余白をクリックすると円を追加できます。
//
// -------------------------------------------------
package {
    import flash.events.*;
    import flash.display.*;
    import flash.net.*;
    import flash.text.*;
    import flash.utils.*;
    import flash.system.*;
    import flash.geom.*;
    import flash.filters.*;
    import flash.ui.*;
    import flash.media.*;

    public class Main extends Sprite {
        public function Main() {

      
// -------------------------------------------------
// コンストラクタ
// -------------------------------------------------

// キャプチャタイミング
Wonderfl.capture_delay( 30 );

// フレームレート
stage.frameRate = 60;

// 100%表示
stage.scaleMode = StageScaleMode.NO_SCALE;

// 左上
stage.align = StageAlign.TOP_LEFT;
stage.align = "TL";

// スプライトを作成
var sprite:Sprite = new Sprite();
var g:Graphics = sprite.graphics;
addChild(sprite);




// 円の作成
function CircleObjCreate():Object{
    var w:int = 400;
    var h:int = 400;
    var s:Number = 5;                // 最高速度
    var d:Number = Math.random();    // 乱数
    var r:Number = d * 45 + 5;        // 半径
    var m:Number = d * 100 + 1;        // 質量

    return {
        pos:new Point(Math.random() * w,Math.random() * h),
        spd:new Point((Math.random() * 2 - 1) * s,(Math.random() * 2 - 1) * s),
        r:r,
        m:m
    };
}

// 円の処理
function CircleObjExecute(obj:Object):void{
    var w:int = stage.stageWidth;
    var h:int = stage.stageHeight;
    
    // 座標に速度を加算
    obj.pos = obj.pos.add(obj.spd);
    
    // 壁との当たり判定
    if(obj.pos.x < obj.r){    
        obj.pos.x = obj.r;
        obj.spd.x *= -1.0;
    }
    if(obj.pos.y < obj.r){
        obj.pos.y = obj.r;
        obj.spd.y *= -1.0;
    }
    if(obj.pos.x > w - obj.r){
        obj.pos.x = w - obj.r;
        obj.spd.x *= -1.0;
    }
    if(obj.pos.y > h - obj.r){
        obj.pos.y = h - obj.r;
        obj.spd.y *= -1.0;
    }
}

// 円の描画
function CircleObjDraw(obj:Object,g:Graphics):void{
    g.lineStyle ( 5.0 , 0xD02020 , 1.0 );
    g.beginFill (0xFFBBBB, 1.0);    // 面のスタイル設定
    g.drawCircle  (obj.pos.x, obj.pos.y , obj.r - 2.5);
}

var layer_back:Shape = new Shape();
addChild(layer_back);
var layer_front:Shape = new Shape();
addChild(layer_front);
var layer_font:Sprite = new Sprite();
addChild(layer_font);

var i:int;
var j:int;
var e:Number = 1.0;        // 反発係数
var num:int = 1;    // 初期生成数
var circle_obj:Array = new Array();

// 円を作成
for(i=0;i<num;i++){
    circle_obj.push(CircleObjCreate());
}


addEventListener(Event.ENTER_FRAME,function(event:Event):void {

    // クリア
    layer_back.graphics.clear();
    layer_front.graphics.clear();
    while(layer_font.numChildren){
        layer_font.removeChildAt(0);
    }
    
    

    // マウス移動
    mouse_spd.x = stage.mouseX - mouse_pos.x;
    mouse_spd.y = stage.mouseY - mouse_pos.y;
    mouse_pos.x = stage.mouseX;
    mouse_pos.y = stage.mouseY;
    mouse_ave.x = (mouse_ave.x * 4.0 + mouse_spd.x) / 5.0;
    mouse_ave.y = (mouse_ave.y * 4.0 + mouse_spd.y) / 5.0;

    // ドラッグ中
    if(drag){
        drag.pos.x = mouse_pos.x;
        drag.pos.y = mouse_pos.y;
        drag.spd.x = mouse_ave.x;
        drag.spd.y = mouse_ave.y;
    }


    // 総当り判定を計算
    for(i=0;i<circle_obj.length - 1;i++){
        var a:Object = circle_obj[i];
        for(j=i+1;j<circle_obj.length;j++){
            var b:Object = circle_obj[j];
            
            var _a:Number =     (a.spd.x * a.spd.x) - 2 * (a.spd.x * b.spd.x) +     (b.spd.x * b.spd.x) +     (a.spd.y * a.spd.y) - 2 * (a.spd.y * b.spd.y) +     (b.spd.y * b.spd.y);
            var _b:Number = 2 * (a.pos.x * a.spd.x) - 2 * (a.pos.x * b.spd.x) - 2 * (a.spd.x * b.pos.x) + 2 * (b.pos.x * b.spd.x) + 2 * (a.pos.y * a.spd.y) - 2 * (a.pos.y * b.spd.y) - 2 * (a.spd.y * b.pos.y) + 2 * (b.pos.y * b.spd.y);
            var _c:Number =     (a.pos.x * a.pos.x) - 2 * (a.pos.x * b.pos.x) +     (b.pos.x * b.pos.x) +     (a.pos.y * a.pos.y) - 2 * (a.pos.y * b.pos.y) +     (b.pos.y * b.pos.y) - (a.r + b.r) * (a.r + b.r);
            var _d:Number = _b * _b - 4 * _a * _c;
            var vx:Number;
            var vy:Number;
            
            if(_d <= 0){
            }else{
                // 当たりあり
                _d = Math.sqrt(_d);
            
                var f0:Number = (- _b - _d) / (2 * _a);    // 接触する瞬間
                var f1:Number = (- _b + _d) / (2 * _a);    // 離れる瞬間

                // 衝突する瞬間の座標
                var apx:Number = a.pos.x + a.spd.x * f0;
                var apy:Number = a.pos.y + a.spd.y * f0;
                var bpx:Number = b.pos.x + b.spd.x * f0;
                var bpy:Number = b.pos.y + b.spd.y * f0;
                var cpx:Number = (bpx - apx) / 2.0 + apx;
                var cpy:Number = (bpy - apy) / 2.0 + apy;
            
                if(f0 >= 0){
                    var g:Graphics
                    g = layer_back.graphics;
                    g.lineStyle ( a.r * 2 , 0x0000FF , 0.1 );
                    g.moveTo (a.pos.x, a.pos.y);    // 面のスタイル設定
                    g.lineTo (apx, apy);

                    g.lineStyle ( b.r * 2 , 0x00FF00 , 0.1 );
                    g.moveTo (b.pos.x, b.pos.y);    // 面のスタイル設定
                    g.lineTo (bpx, bpy);
                    
                    var tf:TextField = new TextField();
                    var format:TextFormat = new TextFormat();
                    format.size = 14;
                    format.font = "MS ゴシック";
                    format.align = TextFormatAlign.CENTER;
                    tf.defaultTextFormat = format;
                    tf.x = cpx - 30;
                    tf.y = cpy - 15;
                    tf.width = 60;
                    tf.height = 30;
                    tf.text = String(Math.floor(f0 * 100) / 100);
                    tf.alpha = 0.2;
                    layer_font.addChild(tf);
                    
                }
                
                // めり込み補正
                if(f0 * f1 < 0){

                    vx = (a.pos.x - b.pos.x);
                    vy = (a.pos.y - b.pos.y);
                    var len:Number = Math.sqrt(vx * vx + vy * vy);
                    var distance:Number = a.r + b.r - len;
                    
                    if(len > 0)    len = 1 / len;
                    vx *= len;
                    vy *= len;
                    
                    distance /= 2.0;
                    a.pos.x += vx * distance;
                    a.pos.y += vy * distance;
                    b.pos.x -= vx * distance;
                    b.pos.y -= vy * distance;
                    
                }else if(f0 <= 1 && f0 >= 0){
                    
                    var f:Number = (Math.abs(f0) < Math.abs(f1)) ? f0 : f1;
                    
                    // 衝突する瞬間の座標
                    a.pos.x = a.pos.x + a.spd.x * f;
                    a.pos.y = a.pos.y + a.spd.y * f;
                    b.pos.x = b.pos.x + b.spd.x * f;
                    b.pos.y = b.pos.y + b.spd.y * f;
                }
                
                // 接触する瞬間は反射
                if(f0 > 1)                continue;
                if(f0 < 0 && f1 < 0)    continue;
                

                // 移動運動用ベクトルと回転運動用ベクトルに分離
                var t:Number;
                vx = (b.pos.x - a.pos.x);
                vy = (b.pos.y - a.pos.y);
                t = -(vx * a.spd.x + vy * a.spd.y) / (vx * vx + vy * vy);
                var arx:Number = a.spd.x + vx * t;
                var ary:Number = a.spd.y + vy * t;
                t = -(-vy * a.spd.x + vx * a.spd.y) / (vy * vy + vx * vx);
                var amx:Number = a.spd.x - vy * t;
                var amy:Number = a.spd.y + vx * t;
                t = -(vx * b.spd.x + vy * b.spd.y) / (vx * vx + vy * vy);
                var brx:Number = b.spd.x + vx * t;
                var bry:Number = b.spd.y + vy * t;
                t = -(-vy * b.spd.x + vx * b.spd.y) / (vy * vy + vx * vx);
                var bmx:Number = b.spd.x - vy * t;
                var bmy:Number = b.spd.y + vx * t;
                
                // 移動運動成分同士の衝突後の方向
                var adx:Number = (a.m * amx + b.m * bmx + bmx * e * b.m - amx * e * b.m) / (a.m + b.m);
                var bdx:Number = - e * (bmx - amx) + adx;
                var ady:Number = (a.m * amy + b.m * bmy + bmy * e * b.m - amy * e * b.m) / (a.m + b.m);
                var bdy:Number = - e * (bmy - amy) + ady;
                
                // 回転運動用ベクトルと加算
                a.spd.x = adx + arx;
                a.spd.y = ady + ary;
                b.spd.x = bdx + brx;
                b.spd.y = bdy + bry;

            }
        }
    }

    // 実行
    var p:String;
    for(i=0;i<circle_obj.length;i++){
        CircleObjExecute(circle_obj[i]);
    }

    // 描画
    for(i=0;i<circle_obj.length;i++){
        CircleObjDraw(circle_obj[i],layer_front.graphics);
    }

});


var drag:Object = null;
var mouse_pos:Point = new Point(0,0);
var mouse_spd:Point = new Point(0,0);
var mouse_ave:Point = new Point(0,0);

// マウスが押されたときに実行されるイベント
stage.addEventListener(MouseEvent.MOUSE_DOWN,function(event:MouseEvent):void {
    // 当たり判定チェック
    for(i=0;i<circle_obj.length;i++){
        var vx:Number = circle_obj[i].pos.x - event.localX;
        var vy:Number = circle_obj[i].pos.y - event.localY;
        if(vx * vx + vy * vy < circle_obj[i].r * circle_obj[i].r){
            drag = circle_obj[i];
            return;
        }
    }
    
    
    // 生成
    var obj:Object = CircleObjCreate();
    circle_obj.push(obj);
    obj.pos.x = event.localX;
    obj.pos.y = event.localY;
    obj.spd.x = 0;
    obj.spd.y = 0;
    drag = obj;
});

// マウスが離されたときに実行されるイベント
stage.addEventListener(MouseEvent.MOUSE_UP,function(event:MouseEvent):void {

    // ドラッグ開放
    drag = null;

});




        }
    }
}




// -------------------------------------------------
// 外部画像をサムネイルとしてキャプチャ
// -------------------------------------------------
import flash.net.*;
import flash.events.*;
import flash.display.*;
import flash.geom.*;
function ThumbnailCapture(url:String,time:uint,stage:Stage):void{

    // キャプチャタイミング
    Wonderfl.capture_delay( time );

    // スプライト作成
    var sprite : Sprite = new Sprite();

    // ステージ最前面に配置
    stage.addChildAt(sprite,stage.numChildren);
    
    // ローダー
    var loader_obj : Loader = new Loader();
    loader_obj.contentLoaderInfo.addEventListener (Event.INIT,function(e:Event):void{

        // メモリからインスタンス化
        var loader_memory : Loader = new Loader();
        loader_memory.contentLoaderInfo.addEventListener (Event.INIT,function(e:Event):void{

            // キャプチャ
            var bmp : BitmapData = new BitmapData(loader_memory.width,loader_memory.height,true,0);
            sprite.addChild(loader_memory);
            bmp.draw(sprite);
            sprite.removeChild(loader_memory);
            loader_memory.unload();
            loader_obj.unload();
            loader_memory = null;
            loader_obj = null;
            
            
            // 画像を配置
            var bmp_obj : Bitmap = new Bitmap(bmp);
            bmp_obj .width = stage.stageWidth;
            bmp_obj .height = stage.stageHeight;
            stage.addChild(bmp_obj );
            
        });
        
        // 読み込み開始
        loader_memory.loadBytes(loader_obj.contentLoaderInfo.bytes);
    });
    
    // 読み込み開始
    loader_obj.load(new URLRequest(url));
}