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

衝突判定 http://sakef.jp/blog/2010/10/ball_collision01/

以下より
http://sakef.jp/blog/2010/10/ball_collision01/
Get Adobe Flash player
by tayapon 14 Aug 2012
    Embed
/**
 * Copyright tayapon ( http://wonderfl.net/user/tayapon )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/cCaZ
 */

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)];
   }
}