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

球体交換 -Ball Swap-

ボールの位置を交換してゴールを目指すゲーム

操作方法(How to Play)
・別のボールをタッチ(Touch another ball)
 ・位置交換(Swap)


Android版
・試作品として以下に追加
 ・https://play.google.com/store/apps/details?id=air.showohealer.game.airprototype

注意事項
・Box2Dのバージョンは2.0.2
 ・wonderfl対応も一因だが、単純に2.1への対応コストが高いので2.0.2のままにしてる
Get Adobe Flash player
by o_healer 17 Jan 2013
/**
 * Copyright o_healer ( http://wonderfl.net/user/o_healer )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/bVKw
 */

/*
「球体交換 -Ball Swap-」
・ボールの位置を交換してゴールを目指すゲーム

操作方法(How to Play)
・別のボールをタッチ(Touch another ball)
 ・位置交換(Swap)


Android版
・試作品として以下に追加
 ・https://play.google.com/store/apps/details?id=air.showohealer.game.airprototype

注意事項
・Box2Dのバージョンは2.0.2
 ・wonderfl対応も一因だが、単純に2.1への対応コストが高いので2.0.2のままにしてる

メモ
・スマホではタッチが難しかったのでステージの量産を断念
 ・移動している球のタッチが難しい
  ・マウスでもわりと難しい
 ・球の種類を増やしたり、それとは別にブロックの種類を増やすことでバリエーションは出せそうだったんだけど
  ・磁石ボール&ブロックとか、特定のボールだけが通過できるブロックとか、ダッシュパネルやトランポリン的なブロックとか
  ・斜めに設定できる固定ブロックはすでにあり、坂道として使ったりすることとかが可能
   ・普通に登ったり天井に逆登り坂として配置したり跳ねさせて方向変換したり坂の昇り降りで左右移動の方向変更とかができる
*/

/*
ToDo
・PlayerとGoal以外はグレアでタッチ可能状態を可視化
 ・Animの方には含めない
 ・ワープ時は非表示にしたい
 →対応を忘れてしまったが、微妙に対応コストがかかるので対応はやめておく
*/


/*
反重力
・b2Islandにて「b.m_linearVelocity.x += step.dt * (gravity.x + b.m_invMass * b.m_force.x);」とある
・なのでgravityは0にしてinvMass * forceがそれと同じになるようにすればOK
 →force = gravity * mass
・ただし、forceはその処理内でSetZeroによるリセットを受けるため、それでリセットされないようなb2Vec2を用意して置き換えた

ワープアニメ
・基本的にはパラパラ漫画の原理を利用する
・事前に拡散→収束するパーティクルアニメを用意しておき、それを移動しつつ順次表示することで実現する
*/



package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;

    //Box2D
    import Box2D.Dynamics.*;
    import Box2D.Collision.*;
    import Box2D.Collision.Shapes.*;
    import Box2D.Common.*;
    import Box2D.Common.Math.*;
    import Box2D.Dynamics.Joints.*;

    [SWF(width="465", height="465", frameRate="30", backgroundColor="0x004400")]
    public class BallSwap extends Sprite {
        //==Const==

        //画像ファイル名
//*
        static public const URL_IMAGE:String = "http://assets.wonderfl.net/images/related_images/8/84/848f/848f9b44d9dac57756643368e83b1cc3ca0caa3a";
/*/
        [Embed(source='ballswap.png')]
         private static var Bitmap_Image: Class;
//*/

        //画面サイズ
        static public const VIEW_W:int = 465;
        static public const VIEW_H:int = 465;

        //重力
        static public const GRAVITY:Number = 5;//10;

        //1マスの大きさ
        static public const PANEL_LEN:int = 32;

        //画像サイズ
        static public const PANEL_W:int = 24;
        static public const PANEL_H:int = 32;
        static public const PANEL_NUM_X:int = 3;
        static public const PANEL_NUM_Y:int = 4;

        //マップ要素
        static public var MapIndexIter:int = 0;
        static public const O:int = MapIndexIter++;
        static public const W:int = MapIndexIter++;
        static public const X:int = MapIndexIter++;
        static public const P:int = MapIndexIter++;
        static public const G:int = MapIndexIter++;
        static public const F:int = MapIndexIter++;
        static public const U:int = MapIndexIter++;
        static public const L:int = MapIndexIter++;
        static public const R:int = MapIndexIter++;
        static public const N:int = MapIndexIter++;

        //マップ
        static public const MAP:Array = [
/*
            {
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,F,O,O,O,F,O,O,O,F,O,O,O,F,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,P,O,O,O,O,O,O,O,O,O,O,O,O,O,O,G,O,O,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                ]
            },
//*/
/*
            {
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,O,O,O,W,O,O,O,O,W],
                    [W,O,O,O,O,W,O,O,O,O,W],
                    [W,O,L,O,O,W,O,O,R,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,P,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                ]
            },
//*/
/*
            {//慣性で坂の先へ
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,U,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,P,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,W,W,W,W,O,O,O,O,W,W,W,W,W],
                    [W,W,W,W,W,O,O,O,O,W,W,W,W,W],
                    [W,W,W,W,W,O,O,O,O,W,W,W,W,W],
                    [W,W,W,W,W,O,O,O,O,W,W,W,W,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                    {x:3.5, y:7.0, w:5, h:0.5, ang:45},
                ]
            },
//*/
/*
            {//easy:逆上り坂
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W],
                    [W,W,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,W],
                    [W,W,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,U,P,O,O,O,O,O,O,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                    {x:3.5, y:3.0, w:5, h:0.5, ang:-45},
                ]
            },
//*/
/*
            {//easy:上り坂
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,P,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,W],
                    [W,R,O,O,O,O,O,O,O,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                    {x:5.5, y:5.0, w:13, h:0.5, ang:-45},
                ]
            },
//*/
/*
            {//easy:エレベーター
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W,W,W,W],
                    [W,W,W,W,W,W,W,O,O,W,W,W,W],
                    [W,W,W,W,W,W,W,O,O,W,W,W,W],
                    [W,W,W,W,W,W,W,O,O,W,W,W,W],
                    [W,W,W,W,W,W,W,O,O,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W,W,W,W],
                    [W,W,W,L,O,U,O,P,O,W,W,W,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                ]
            },
//*/
/*
            {//mid:多重エレベーター
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W,W,W,W],
                    [W,W,W,O,O,W,W,W,W,W,W,W,W],
                    [W,W,W,O,O,W,W,W,W,W,W,W,W],
                    [W,W,W,O,O,W,W,W,W,W,W,W,W],
                    [W,W,W,O,O,W,W,W,W,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W,W,W,W],
                    [W,W,W,W,W,W,W,O,O,W,W,W,W],
                    [W,W,W,W,W,W,W,O,O,W,W,W,W],
                    [W,W,W,W,W,W,W,O,O,W,W,W,W],
                    [W,W,W,W,W,W,W,O,O,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W,W,W,W],
                    [W,W,W,L,O,U,O,P,R,W,W,W,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                ]
            },
//*/
/*
            {//??:シリンダー(全体を上に持ち上げる実験)(タッチの近さを考えないと誤検出される)
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,W,W,W,W,W,O,W,W,W,W,W,W],
                    [W,W,W,W,W,W,O,W,W,W,W,W,W],
                    [W,W,W,W,W,W,O,W,W,W,W,W,W],
                    [W,W,W,W,W,W,O,W,W,W,W,W,W],
                    [W,W,W,W,W,W,O,W,W,W,W,W,W],
                    [W,W,W,W,W,W,O,W,W,W,W,W,W],
                    [W,W,W,W,W,W,U,W,W,W,W,W,W],
                    [W,W,W,W,W,W,U,W,W,W,W,W,W],
                    [W,W,W,W,W,W,U,W,W,W,W,W,W],
                    [W,W,W,W,W,W,U,W,W,W,W,W,W],
                    [W,W,W,W,W,W,N,W,W,W,W,W,W],
                    [W,W,W,W,W,W,N,W,W,W,W,W,W],
                    [W,W,W,W,W,W,P,W,W,W,W,W,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                ]
            },
//*/
/*
            {//目詰り解消
                map:[
                    [W,W,W,W,W,W,W,W,W,W],
                    [W,W,W,O,O,O,O,O,O,W],
                    [W,W,W,O,O,O,O,O,O,W],
                    [W,W,W,O,O,O,O,O,O,W],
                    [W,W,W,O,W,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,O,O,O,W,W,W,O,W],
                    [W,W,U,P,U,W,W,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                    {x:2.0, y:6.0, w:2.4, h:0.5, ang:-45},
                    {x:5.0, y:6.0, w:2.4, h:0.5, ang: 45},

                    {x:4.2, y:2.0, w:4.4, h:0.5, ang:-45},
                ]
            },
//*/
//*
            {//UP用
                map:[
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,F,O,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,O,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,O,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,O,O,O,O,W,G,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
                    [W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
                    [W,W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,F,W],
                    [W,W,W,W,W,O,O,O,O,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,U,W],
                    [W,W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,U,W],
                    [W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W],
                    [W,L,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,R,L,O,O,O,O,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,O,O,O,O,O,O,O,O,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,O,O,O,O,O,O,O,O,W,O,O,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,W,W,W,W,W,W,W,W,O,W,O,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,W,W,W,R,W,U,W,L,W,W,W,W,W,O,O,O,O,O,W,W,U,W,L,W,W,W,W,W,W],
                    [W,O,W,W,W,O,W,O,W,O,W,W,W,W,W,O,O,O,O,O,W,W,O,W,O,W,W,W,W,W,W],
                    [W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,O,W,W,W,W,W,W,W,W,W,W,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W,W,O,O,O,O,O,F,O,O,O,O,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,O,W,W,W,W,W,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,O,W,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W,O,W,W,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W,W,O,W,W,W,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,O,W,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,O,W,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,O,W,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,F,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,F,O,O,O,O,O,O,O,O,O,O,F,O,O,O,O,U,W],
                    [W,O,P,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W],
                    [W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W],
                ],
                append:[
                ]
            },
//*/
        ];

        //マップのパネル数
        static public const MAP_NUM_X:int = MAP[0].map[0].length;
        static public const MAP_NUM_Y:int = MAP[0].map.length;
        //マップの大きさ
        static public const MAP_W:int = MAP_NUM_X * PANEL_LEN;
        static public const MAP_H:int = MAP_NUM_Y * PANEL_LEN;

        //Box2Dと実際の表示の比率(Box2Dに大きすぎる値を入れると上手く動かなかったりする)
        static public const PHYS_SCALE:Number = 10;
        static public function PHYS_to_IMAGE(in_Val:Number):Number{return in_Val * PHYS_SCALE;}
        static public function IMAGE_to_PHYS(in_Val:Number):Number{return in_Val / PHYS_SCALE;}
        //Box2Dの画面外の余白
        static public const BOX2D_RANGE_OFFSET:int = 100;

        //モード
        static public var ModeIter:int = 0;
        static public const MODE_MAIN:int    = ModeIter++;
        static public const MODE_GOAL:int    = ModeIter++;
        static public const MODE_GAME_OVER:int    = ModeIter++;


        //==Var==

        //Pseudo Singleton
        static public var Instance:BallSwap;

        //マップ(プレイヤーなどを地面に置き換えたりしたもの)
        public var m_Map:Vector.<Vector.<int> >;

        //プレイヤーの初期位置
        public var m_PlayerX:int = 2.5*PANEL_LEN;//一応それっぽい位置に初期化
        public var m_PlayerY:int = 2.5*PANEL_LEN;

        //ゴールの初期位置
        public var m_GoalX:int = 0.5*PANEL_LEN;//一応それっぽい位置に初期化
        public var m_GoalY:int = 0.5*PANEL_LEN;

        //レイヤー
        public var m_Layer_Root:Sprite = new Sprite();//Root
        public var  m_Layer_Ground:Sprite = new Sprite();//地面用レイヤー
        public var  m_Layer_Obj:Sprite = new Sprite();//通常表示用レイヤー
        public var  m_Layer_Debug:Sprite = new Sprite();//デバッグ描画用
        public var m_Layer_HUD:Sprite = new Sprite();//情報表示用レイヤー

        //地形画像
        public var m_BitmapData_Floor:BitmapData = new BitmapData(MAP_W, MAP_H, true, 0x00000000);

        //トゲ判定のためのダミーSprite
        public var m_NeedleSprite:Sprite = new Sprite();


        //GameObjectのリスト
        public var m_GameObjectList:Vector.<GameObject> = new Vector.<GameObject>();

        //タッチ中のGameObject(リリース時に反応するためUpdateでタッチのチェックを行う)
        public var m_TouchObj:GameObject = null;

        //Swapまわり
        public var m_SwapFlag:Boolean = false;
        public var m_SwapAnimCount:int = 0;
        public var m_SrcX:int;
        public var m_SrcY:int;
        public var m_DstX:int;
        public var m_DstY:int;


        //プレイヤー
        public var m_Player:Player;

        //ゴール
        public var m_Goal:Goal;
        public var m_GoalAnimIndex:int = 0;

        //テキスト
        public var m_Text:TextField = new TextField();

        //モード
        public var m_Mode:int = MODE_MAIN;


        //Box2D
        public var m_Box2D_World:b2World;


        //==Function==

        //Init
        public function BallSwap(){
            if(stage != null){
                Init(null);
            }else{
                addEventListener(
                    Event.ADDED_TO_STAGE,//ステージに追加されたら
                    Init
                );
            }
        }
        public function Init(e:Event):void
        {
            var x:int;
            var y:int;

            //Pseudo Singleton
            {
                Instance = this;
            }

            //Common
            {
                stage.scaleMode = StageScaleMode.NO_SCALE;
                stage.align = StageAlign.TOP_LEFT;
            }

            //Static Init
            {
                ImageManager.Init();
                //Player.Initialize();
            }

            //MAP => m_Map
            {
                m_Map = new Vector.<Vector.<int> >(MAP_NUM_Y);
                for(y = 0; y < MAP_NUM_Y; y++){
                    m_Map[y] = new Vector.<int>(MAP_NUM_X);
                    var PosY:int = (y+0.5) * PANEL_LEN;
                    for(x = 0; x < MAP_NUM_X; x++){
                        var PosX:int = (x+0.5) * PANEL_LEN;
                        var index:int = MAP[0].map[y][x];

                        switch(index){
                        case P:
                            index = O;//プレイヤーの居た位置は地面扱いする
                            m_PlayerX = PosX;
                            m_PlayerY = PosY;
                            break;
                        case G:
                            index = O;//ゴールのある位置は地面扱いする
                            m_GoalX = PosX;
                            m_GoalY = PosY;
                            break;
                        }

                        m_Map[y][x] = index;
                    }
                }
            }

            //Box2D
            {
                //考慮する領域
                var worldAABB:b2AABB = new b2AABB();
                worldAABB.lowerBound.Set(IMAGE_to_PHYS(-BOX2D_RANGE_OFFSET), IMAGE_to_PHYS(-BOX2D_RANGE_OFFSET));
                worldAABB.upperBound.Set(IMAGE_to_PHYS(MAP_W+BOX2D_RANGE_OFFSET), IMAGE_to_PHYS(MAP_H+BOX2D_RANGE_OFFSET));
                //重力ベクトル
                //var gravity:b2Vec2 = new b2Vec2(0, GRAVITY);
                var gravity:b2Vec2 = new b2Vec2(0, 0);//重力は個々で設定することにして、上方向の重力などを実現
                //Sleep
                var useSleep:Boolean = false;//位置交換するし動く物体の数は少ないはずなのでスリープはさせない
                //物理world
                m_Box2D_World = new b2World(worldAABB, gravity, useSleep);

                //ContactListener
                m_Box2D_World.SetContactListener(new ContactListener());
            }

            //Layer
            {
                addChild(m_Layer_Root);
                {
                    m_Layer_Root.addChild(m_Layer_Ground);
                    m_Layer_Root.addChild(m_Layer_Obj);
                    m_Layer_Root.addChild(m_Layer_Debug);
                }

                addChild(m_Layer_HUD);
            }

            //地形
            {
                ImageManager.Map_to_Bitmap(
                    m_Map,
                    m_BitmapData_Floor
                );

                var bmp:Bitmap;

                //Floor
                {
                    bmp = new Bitmap(m_BitmapData_Floor);
                    m_Layer_Ground.addChild(bmp);
                }
            }

            //Text
            {
                m_Text.selectable = false;
                m_Text.autoSize = TextFieldAutoSize.LEFT;
                m_Text.defaultTextFormat = new TextFormat('Verdana', 60, 0xFFFF00, true);
                m_Text.text = '';
                m_Text.filters = [new GlowFilter(0xFF0000,1.0, 8,8)];

                addChild(m_Text);
            }

            //Touch
            {
                stage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
                stage.addEventListener(MouseEvent.MOUSE_MOVE, OnMouseMove);
                stage.addEventListener(MouseEvent.MOUSE_UP, OnMouseUp);
            }

            //画像ロード開始
            {
//*
                const LoadFunc:Function = function(in_URL:String, in_OnLoad:Function):void{
                    var loader:Loader = new Loader();
                    loader.load(new URLRequest(in_URL), new LoaderContext(true));//画像のロードを開始して
                    loader.contentLoaderInfo.addEventListener(
                        Event.COMPLETE,//ロードが完了したら
                        function(e:Event):void{
                            in_OnLoad(loader.content);//初期化に入る
                        }
                    );
                }

                LoadFunc(URL_IMAGE, OnLoadEnd);
/*/
                OnLoadEnd(new Bitmap_Image());
//*/
            }

/*
            //Debug
            {
                var debugDraw:b2DebugDraw = new b2DebugDraw();
                debugDraw.m_sprite = m_Layer_Debug;//this;
                debugDraw.m_drawScale = PHYS_SCALE;
                debugDraw.m_fillAlpha = 0.6;
                debugDraw.m_lineThickness = 1;
                debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
                m_Box2D_World.SetDebugDraw(debugDraw);
            }
//*/
        }

        //Reset
        public function Reset():void{
            var x:int;
            var y:int;
            var i:int;

            //Param
            {
                m_SwapFlag = false;
            }

            //GameObject
            {
                //Remove Old
                ClearGameObjectList();

                //Playerを追加
                //Goalを追加
                //Ballを生成のたびに追加
                m_Map = new Vector.<Vector.<int> >(MAP_NUM_Y);
                for(y = 0; y < MAP_NUM_Y; y++){
                    m_Map[y] = new Vector.<int>(MAP_NUM_X);
                    var pos_y:int = (y+0.5) * PANEL_LEN;
                    for(x = 0; x < MAP_NUM_X; x++){
                        var pos_x:int = (x+0.5) * PANEL_LEN;
                        var index:int = MAP[0].map[y][x];

                        switch(index){
                        case P:
                            m_Player = new Player();
                            RegisterGameObject(m_Player, pos_x, pos_y);

                            index = O;//プレイヤーの居た位置は地面扱いする
                            m_PlayerX = pos_x;
                            m_PlayerY = pos_y;
                            break;
                        case G:
                            m_Goal = new Goal();
                            RegisterGameObject(m_Goal, pos_x, pos_y);
                            m_GoalAnimIndex = 0;

                            index = O;//ゴールのある位置は地面扱いする
                            m_GoalX = pos_x;
                            m_GoalY = pos_y;
                            break;
                        case F:
                            RegisterGameObject(new GameObject_Ball_Fix(), pos_x, pos_y);
                            break;
                        case U:
                            RegisterGameObject(new GameObject_Ball_Move(0, -1), pos_x, pos_y);
                            break;
                        case L:
                            RegisterGameObject(new GameObject_Ball_Move(-1, 0), pos_x, pos_y);
                            break;
                        case R:
                            RegisterGameObject(new GameObject_Ball_Move(+1, 0), pos_x, pos_y);
                            break;
                        case N:
                            RegisterGameObject(new GameObject_Ball(), pos_x, pos_y);
                            break;
                        }

                        m_Map[y][x] = index;
                    }
                }

                //一応リセット
                m_TouchObj = null;
            }

            //
            {
                var param_arr:Array = MAP[0].append;
                var param_num:int = param_arr.length;
                for(i = 0; i < param_num; ++i){
                    var param:* = param_arr[i];

                    RegisterGameObject(new GameObject_Box(param.w * PANEL_LEN, param.h * PANEL_LEN, param.ang), param.x * PANEL_LEN, param.y * PANEL_LEN);
                }
            }

            //地形コリジョン
            {
                Init_Terrain_Collision();
            }

            //Camera
            {
                Update_Camera(1.0);
            }
        }

        //GameObjectの登録を全部解除
        public function ClearGameObjectList():void{
            var num:int = m_GameObjectList.length;
            for(var i:int = 0; i < num; ++i){
                var obj:GameObject = m_GameObjectList[i];
                if(obj.parent != null){
                    obj.parent.removeChild(obj);
                }
            }

            m_GameObjectList = new Vector.<GameObject>();
        }

        //GameObjectを登録
        public function RegisterGameObject(in_GameObj:GameObject, in_X:Number, in_Y:Number):void{
            in_GameObj.SetPosition(in_X, in_Y);

            m_Layer_Obj.addChild(in_GameObj);

            m_GameObjectList.push(in_GameObj);
        }

        //Init : Terrain Collision
        public function Init_Terrain_Collision():void{
            var x:int;
            var y:int;
            var r:Rectangle;

            //準備:トゲ判定
            const NEEDLE_W:Number = 0.5*PANEL_LEN * 1.1;
            var body_needle:b2Body;
            var shapeDef_needle:b2PolygonDef;
            {
                //まずはトゲ用のBodyを一つだけ作成
                //var body_needle:b2Body;
                {
                    body_needle = m_Box2D_World.CreateBody(new b2BodyDef());
                    body_needle.SetUserData(m_NeedleSprite);
                }

                //作成するShapeのベースを作成
                //var shapeDef_needle:b2PolygonDef;
                {
                    shapeDef_needle = new b2PolygonDef();
                    shapeDef_needle.density = 0;//Fix
                    shapeDef_needle.isSensor = true;
                }
            }

            //コリジョンリスト
            var RectList:Vector.<Rectangle> = new Vector.<Rectangle>();
            {
                //現在の行のコリジョン
                var RectList_Now:Vector.<Rectangle> = new Vector.<Rectangle>(MAP_NUM_X);
                //結合するため、一時的に溜めておく
                var RectList_Pre:Vector.<Rectangle> = new Vector.<Rectangle>(MAP_NUM_X);

                for(y = 0; y < MAP_NUM_Y; y++){
                    var PosY:int = (y+0.5) * PANEL_LEN;
                    r = null;

                    //まずはこの行のまとめられるところをまとめる
                    for(x = 0; x < MAP_NUM_X; x++){
                        var PosX:int = (x+0.5) * PANEL_LEN;
                        var index:int = m_Map[y][x];

                        switch(index){
                        case X:
                            index = W;//壁として一体化する
                            //トゲ判定を追加する
                            shapeDef_needle.SetAsOrientedBox(IMAGE_to_PHYS(NEEDLE_W), IMAGE_to_PHYS(NEEDLE_W), new b2Vec2(IMAGE_to_PHYS(PosX), IMAGE_to_PHYS(PosY)));
                            body_needle.CreateShape(shapeDef_needle);
                            break;
                        }

                        if(index == W){
                            if(r == null){
                                r = new Rectangle(x*PANEL_LEN, y*PANEL_LEN, PANEL_LEN, PANEL_LEN);
                                RectList_Now[x] = r;
                            }else{
                                r.width += PANEL_LEN;
                            }
                        }else{
                            r = null;
                        }
                    }

                    //前回の結果と統合できるなら統合する
                    for(x = 0; x < MAP_NUM_X; x++){
                        if(RectList_Pre[x] != null){//前回の結果と
                            if(RectList_Now[x] != null){//今回の結果で同じ始点のものがあり
                                if(RectList_Pre[x].width == RectList_Now[x].width){//幅が同じなら
                                    //統合する
                                    RectList_Pre[x].height += PANEL_LEN;
                                    RectList_Now[x] = null;
                                    continue;
                                }
                            }

                            //前回の結果が統合できない場合、もう統合することもないのでResultに入れてしまう
                            RectList.push(RectList_Pre[x]);
                        }

                        //今回の結果を前回の結果の方に移す
                        RectList_Pre[x] = RectList_Now[x];
                        RectList_Now[x] = null;
                    }
                }

                //残っているやつをResultに移す
                for(x = 0; x < MAP_NUM_X; x++){
                    if(RectList_Pre[x] != null){
                        RectList.push(RectList_Pre[x]);
                    }
                }
            }

            //実際に作成
            {
                //まずは地形用のBodyを一つだけ作成
                var body:b2Body;
                {
                    body = m_Box2D_World.CreateBody(new b2BodyDef());
                }

                //作成するShapeのベースを作成
                var shapeDef:b2PolygonDef;
                {
                    shapeDef = new b2PolygonDef();
                    shapeDef.density = 0;//Fix
                    shapeDef.friction = 0;
                    shapeDef.restitution = 0.5;
                }

                //あとはリストの形状を追加していく
                var w:Number;
                var h:Number;
                var center:b2Vec2 = new b2Vec2();
                var ColNum:int = RectList.length;
                for(var i:int = 0; i < ColNum; i++){
                    r = RectList[i];

                    w = IMAGE_to_PHYS(r.width/2);
                    h = IMAGE_to_PHYS(r.height/2);
                    center.x = IMAGE_to_PHYS(r.x) + w;
                    center.y = IMAGE_to_PHYS(r.y) + h;

                    shapeDef.SetAsOrientedBox(w, h, center);
                    body.CreateShape(shapeDef);
                }

                //一応、追加したShapeに合わせてMassを計算(Fixなので不要かもしれない)
                body.SetMassFromShapes();
            }

/*
            //Debug
            var sprite:Sprite = new Sprite();
            m_Layer_Debug.addChild(sprite);
            var g:Graphics = sprite.graphics;
            g.lineStyle(3,0x00FFFF,1.0);
            for(i = 0; i < ColNum; i++){
                r = RectList[i];

                g.drawRect(r.x, r.y, r.width, r.height);
            }
//*/
        }

        //OnLoad
        public function OnLoadEnd(in_Graphic:DisplayObject):void{
            //Init ImageManager
            {
                ImageManager.SetImage(in_Graphic);//それを保持した後
            }

            //今の表示のスクリーンショットを撮っておいて、α減衰させつつ画像表示に移行させてみる
            {
                var bmd:BitmapData = new BitmapData(VIEW_W, VIEW_H, false, 0x000000);
                bmd.draw(m_Layer_Root, new Matrix(1,0,0,1, m_Layer_Root.x,m_Layer_Root.y));

                var bmp:Bitmap = new Bitmap(bmd);
                addChild(bmp);

                addEventListener(Event.ENTER_FRAME, function f(e:Event):void{
                    var DeltaAlpha:Number = 5 * 1.0/30.0;
                    bmp.alpha -= DeltaAlpha;
                    if(bmp.alpha <= 0){
                        removeChild(bmp);
                        removeEventListener(Event.ENTER_FRAME, f);
                    }
                });
            }

            //ブロック描画
            {
                ImageManager.Map_to_Bitmap(
                    m_Map,
                    m_BitmapData_Floor
                );
            }

            var mtx:Matrix = new Matrix();

            //各ボールの画像
            {//Player
                mtx.tx = -0*32;
                mtx.ty = -2*32;
                Player.s_BitmapData.draw(in_Graphic, mtx);
            }
            {//GameObject_Ball_Fix
                mtx.tx = -1*32;
                mtx.ty = -2*32;
                GameObject_Ball_Fix.s_BitmapData.draw(in_Graphic, mtx);
            }
            {//GameObject_Ball_Move
                mtx.tx = -2*32;
                mtx.ty = -2*32;
                GameObject_Ball_Move.s_BitmapData.draw(in_Graphic, mtx);
                mtx.tx = -0*32;
                mtx.ty = -3*32;
                GameObject_Ball_Move.s_BitmapData_Arrow.draw(in_Graphic, mtx);
            }
            {//Goal
                mtx.tx = -3*32;
                mtx.ty = -2*32;
                Goal.s_BitmapData.draw(in_Graphic, mtx);
            }

            //Update
            {
                addEventListener(Event.ENTER_FRAME, Update);
            }

            //残りはResetと同じ処理
            {
                Reset();
            }
        }


        //Touch : Down
        private function OnMouseDown(e:MouseEvent):void{
            if(m_SwapFlag){
                return;
            }

            m_TouchObj = null;
            var min_ratio:Number = 1.0;
            var num:int = m_GameObjectList.length;
            for(var i:int = 0; i < num; ++i){
                var obj:GameObject = m_GameObjectList[i];
                var touch_ratio:Number = obj.GetTouchRangeRatio();
                if(touch_ratio < min_ratio){
                    m_TouchObj = obj;
                    min_ratio = touch_ratio;
                }
            }
        }

        //Touch : Move
        private function OnMouseMove(e:MouseEvent):void{
            //ここでやるよりはUpdateでチェックしたほうがコリジョン自身の移動にも対応できて良い
        }

        //Touch : Up
        private function OnMouseUp(e:MouseEvent):void{
            if(m_SwapFlag){
                return;
            }

/*
            if(m_TouchObj != null){
                //Swap
                var another_x:Number = m_TouchObj.x;
                var another_y:Number = m_TouchObj.y;

                m_TouchObj.SetPosition(m_Player.x, m_Player.y);
                m_Player.SetPosition(another_x, another_y);
            }

            m_TouchObj = null;
/*/
            if(m_TouchObj != null){
                //Swap
                Begin_Swap();
            }
//*/
        }


        //Swap : Begin
        public function Begin_Swap():void{
            m_SwapFlag = true;
            m_SwapAnimCount = 0;
            m_SrcX = m_Player.x;
            m_SrcY = m_Player.y;
            m_DstX = m_TouchObj.x;
            m_DstY = m_TouchObj.y;
        }

        //Swap : End
        public function End_Swap():void{
            m_Player.SetPosition(m_DstX, m_DstY);
            m_TouchObj.SetPosition(m_SrcX, m_SrcY);

            m_Player.SetAnimIndex(0);
            m_TouchObj.SetAnimIndex(0);
            m_SwapFlag = false;

            m_TouchObj = null;
        }


        //Update
        public function Update(e:Event=null):void{
            //Check
            if(IsEnd()){
                if(m_GoalAnimIndex < GameObject.ANIM_NUM-1){
                    ++m_GoalAnimIndex;
                }
                m_Goal.SetAnimIndex(m_GoalAnimIndex);
                return;
            }

            //今回進める時間
            var DeltaTime:Number = 1.0/30.0;

            //Swap処理
            if(m_SwapFlag){
                Update_Swap();
                return;
            }

            //タッチを開始した相手をタッチし続けてるかチェック
            //- 途中で外れたら離した時に反応しないようにする
            if(m_TouchObj != null){
                if(1.0 < m_TouchObj.GetTouchRangeRatio()){
                    m_TouchObj = null;
                }
            }

            //物理まわりの更新
            Update_Phys(DeltaTime);

            //GameObjectの更新
            Update_GameObj(DeltaTime);

            //Player
            //m_Player.Update(DeltaTime);

            //Goal
            //m_Goal.Update();

            //Camera
            Update_Camera();
        }

        //Swapの移動処理
        public function Update_Swap():void{
            //Ratio
            var lerp_ratio:Number = 1.0 * m_SwapAnimCount / GameObject.ANIM_NUM;
            lerp_ratio = 0.5 - 0.5*Math.cos(Math.PI * lerp_ratio);
            //lerp_ratio = 0.5 - 0.5*Math.cos(Math.PI * lerp_ratio);

            //m_Player    : Src => Dst
            m_Player.x = Util.Lerp(m_SrcX, m_DstX, lerp_ratio);
            m_Player.y = Util.Lerp(m_SrcY, m_DstY, lerp_ratio);
            m_Player.SetAnimIndex(m_SwapAnimCount);

            //m_TouchObj: Dst => Src
            m_TouchObj.x = Util.Lerp(m_DstX, m_SrcX, lerp_ratio);
            m_TouchObj.y = Util.Lerp(m_DstY, m_SrcY, lerp_ratio);
            m_TouchObj.SetAnimIndex(m_SwapAnimCount);

            //Count
            ++m_SwapAnimCount;
            if(GameObject.ANIM_NUM <= m_SwapAnimCount){
                End_Swap();
            }
        }

        //物理まわりの更新
        public function Update_Phys(in_DeltaTime:Number):void{
            var b:b2Body;

            //物理エンジンをDeltaTimeだけ進める
            m_Box2D_World.Step(in_DeltaTime, 10);

            //Sync
            for(b = m_Box2D_World.m_bodyList; b; b = b.m_next){
                //画像との同期
                if(b.m_userData != null){
                    var sprite:Sprite = b.m_userData as Sprite;
                    sprite.x = PHYS_to_IMAGE(b.GetPosition().x);
                    sprite.y = PHYS_to_IMAGE(b.GetPosition().y);
                    //b.m_userData.m_VX = PHYS_to_IMAGE(b.m_linearVelocity.x);
                    //b.m_userData.m_VY = PHYS_to_IMAGE(b.m_linearVelocity.y);

                    sprite.rotation = b.GetAngle() * 180/Math.PI;
                }
/*
                //擬似摩擦
                {
                    const Ratio:Number = 0.99;//本当はDeltaTime依存の値にした方が良い
                    b.GetLinearVelocity().x *= Ratio;
                    b.GetLinearVelocity().y *= Ratio;
                    b.SetAngularVelocity(b.GetAngularVelocity() * Ratio);
                }
//*/
            }
        }

        //GameObjectの更新
        public function Update_GameObj(in_DeltaTime:Number):void{
            var num:int = m_GameObjectList.length;
            for(var i:int = 0; i < num; ++i){
                var obj:GameObject = m_GameObjectList[i];
                obj.Update(in_DeltaTime);
            }
        }

        //Update : Camera
        public function Update_Camera(in_LerpRatio:Number = 0.2):void{
            var PlayerX:int = m_Player.x;
            var PlayerY:int = m_Player.y;

            //移動量
            var CameraMoveX:int = 0;
            var CameraMoveY:int = 0;
            {
                //現在のカメラでのプレイヤー相対位置
                var RelPlayerX:Number = PlayerX + m_Layer_Root.x;
                var RelPlayerY:Number = PlayerY + m_Layer_Root.y;

                //中央からの差がそのまま移動量
                CameraMoveX = VIEW_W/2 - RelPlayerX;
                CameraMoveY = VIEW_H/2 - RelPlayerY;
            }

            //目標値
            var RootX:int = m_Layer_Root.x + CameraMoveX;
            var RootY:int = m_Layer_Root.y + CameraMoveY;
            {
                //端制限
                if(RootX < -MAP_W + VIEW_W){
                    RootX = -MAP_W + VIEW_W;
                }
                if(RootX > 0){
                    RootX = 0;
                }
                if(RootY < -MAP_H + VIEW_H){
                    RootY = -MAP_H + VIEW_H;
                }
                if(RootY > 0){
                    RootY = 0;
                }
            }

/*
            m_Layer_Root.x = RootX;
            m_Layer_Root.y = RootY;
/*/
            //補間(ワープ時にカメラはゆっくり追いかけるようにするため)
            m_Layer_Root.x = Util.Lerp(m_Layer_Root.x, RootX, in_LerpRatio);
            m_Layer_Root.y = Util.Lerp(m_Layer_Root.y, RootY, in_LerpRatio);
//*/
        }

        //Goal
        public function OnGoal():void{
            //Mode
            {
                m_Mode = MODE_GOAL;
            }

            //Text
            {
                //Text
                m_Text.text = 'Clear';

                //Centering
                m_Text.x = (stage.stageWidth - m_Text.width) / 2;
                m_Text.y = (stage.stageHeight - m_Text.height) * 4/9;
            }
        }

        //Game Over : Damage
        public function OnDead_Damage():void{
            //Mode
            {
                m_Mode = MODE_GAME_OVER;
            }

            //Text
            {
                //Text
                m_Text.text = 'Game Over';

                //Centering
                m_Text.x = (stage.stageWidth - m_Text.width) / 2;
                m_Text.y = (stage.stageHeight - m_Text.height) / 2;
            }
        }

        //Game Over : Fall
        public function OnDead_Fall():void{
            //Mode
            {
                m_Mode = MODE_GAME_OVER;
            }

            //Text
            {
                //Text
                m_Text.text = 'Game Over';

                //Centering
                m_Text.x = (stage.stageWidth - m_Text.width) / 2;
                m_Text.y = (stage.stageHeight - m_Text.height) / 2;
            }
        }

        //#IsGameOver
        public function IsEnd():Boolean{
            return (m_Mode != MODE_MAIN);
        }
    }
}


import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
import flash.sensors.*;

//Box2D
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.Joints.*;

class ContactListener extends b2ContactListener
{
    //衝突が発生した
    override public function Add(in_ContactPoint:b2ContactPoint):void{
        var body1:b2Body = in_ContactPoint.shape1.GetBody();
        var body2:b2Body = in_ContactPoint.shape2.GetBody();

        //ダメージ処理
        {
//*
            var body_needle:b2Body;
            var body_object:b2Body;
            {
                if(body1.GetUserData() == BallSwap.Instance.m_NeedleSprite){
                    body_needle = body1;

                    if(body2.IsDynamic()){
                        body_object = body2;
                    }
                }
                if(body2.GetUserData() == BallSwap.Instance.m_NeedleSprite){
                    body_needle = body2;

                    if(body1.IsDynamic()){
                        body_object = body1;
                    }
                }
            }

            //if(body_needle && body_object)
            if(body_needle)
            {
                //今は仮ですぐにゲームオーバーにしてしまう
                BallSwap.Instance.OnDead_Damage();
            }
//*/
        }

        //ゴール処理
        {
            var body_player:b2Body;
            var body_goal:b2Body;
            {
                if(body1.GetUserData() == BallSwap.Instance.m_Player){
                    body_player = body1;
                }
                if(body2.GetUserData() == BallSwap.Instance.m_Player){
                    body_player = body2;
                }

                if(body1.GetUserData() == BallSwap.Instance.m_Goal){
                    body_goal = body1;
                }
                if(body2.GetUserData() == BallSwap.Instance.m_Goal){
                    body_goal = body2;
                }
            }

            if(body_player != null && body_goal != null){
                BallSwap.Instance.OnGoal();
            }
        }
    }
}


class ImageManager
{
    //==Const==

    //#Graphic
    static public var m_GraphicIndexIter:int = 0;

    static public const GRAPHIC_INDEX_BG:int            = m_GraphicIndexIter++;

    static public const GRAPHIC_INDEX_WALL:int            = m_GraphicIndexIter++;
    static public const GRAPHIC_INDEX_WALL_X:int        = m_GraphicIndexIter++;
    static public const GRAPHIC_INDEX_WALL_Y:int        = m_GraphicIndexIter++;
    static public const GRAPHIC_INDEX_WALL_XorY:int        = m_GraphicIndexIter++;
    static public const GRAPHIC_INDEX_WALL_XandY:int    = m_GraphicIndexIter++;

    static public const GRAPHIC_INDEX_NEEDLE:int        = m_GraphicIndexIter++;
    static public const GRAPHIC_INDEX_NEEDLE_X:int        = m_GraphicIndexIter++;
    static public const GRAPHIC_INDEX_NEEDLE_Y:int        = m_GraphicIndexIter++;
    static public const GRAPHIC_INDEX_NEEDLE_XY:int        = m_GraphicIndexIter++;

    static public const GRAPHIC_INDEX_NUM:int            = m_GraphicIndexIter;


    //#enum:Quater
    static public const LU:int = 0;
    static public const RU:int = 1;
    static public const LD:int = 2;
    static public const RD:int = 3;

    //#enum:Pos
    static public const POS_X:int = 0;
    static public const POS_Y:int = 1;


    //#Graphic
    static public var m_BitmapData_View:BitmapData;

    //#Mapping
    static public var GRAPHIC_INDEX_TO_POS:Array;


    //#Palette
    static public var m_Palette_ForView:Array;


    //#Utility
    static public const POS_ZERO:Point = new Point(0,0);


    //==Function==

    //#Init
    static public function Init():void{
        var x:int, y:int, i:int;

        //m_BitmapData_View
        {
            m_BitmapData_View = new BitmapData(256, 256, false, 0x000000);
        }

        //GRAPHIC_INDEX_TO_POS
        {//GRAPHIC_INDEX_~から画像の位置へのマッピング(さらにどの隅での処理かも含む)(そして左から何マス目、上から何マス目、という指定)
            GRAPHIC_INDEX_TO_POS = new Array(GRAPHIC_INDEX_NUM);

            //[LU][RU][LD][RD]

            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_BG]            = [[3,2], [3,2], [3,2], [3,2]];

            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL]        = [[1,1], [1,1], [1,1], [1,1]];
            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL_X]        = [[0,1], [2,1], [0,1], [2,1]];
            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL_Y]        = [[1,0], [1,0], [1,2], [1,2]];
            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL_XorY]    = [[0,0], [2,0], [0,2], [2,2]];
            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_WALL_XandY]    = [[3,0], [4,0], [3,1], [4,1]];

            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_NEEDLE]        = [[3,3], [4,3], [3,4], [4,4]];
            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_NEEDLE_X]    = [[0,4], [2,4], [0,4], [2,4]];
            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_NEEDLE_Y]    = [[1,3], [1,3], [1,5], [1,5]];
            GRAPHIC_INDEX_TO_POS[GRAPHIC_INDEX_NEEDLE_XY]    = [[0,3], [2,3], [0,5], [2,5]];
        }

        //m_Palette_ForView
        {
            m_Palette_ForView = new Array(256);

            var index_graphic:int = GRAPHIC_INDEX_BG;
            for(i = 0; i < 256; i++){
                //区切りごとにindexを変更。次の区切りまではその値をセット
                switch(i){
                case 0:
                case 6:
                case 18:
                case 24:
                    index_graphic = GRAPHIC_INDEX_BG; break;
                case 3:
                case 21:
                    index_graphic = GRAPHIC_INDEX_NEEDLE_Y; break;
                case 9:
                case 15:
                    index_graphic = GRAPHIC_INDEX_NEEDLE_X; break;
                case 12:
                    index_graphic = GRAPHIC_INDEX_NEEDLE_XY; break;
                case 27:
                    index_graphic = GRAPHIC_INDEX_NEEDLE; break;
                case 54:
                case 63:
                    index_graphic = GRAPHIC_INDEX_WALL_XorY; break;
                case 60:
                case 69:
                    index_graphic = GRAPHIC_INDEX_WALL_X; break;
                case 72:
                    index_graphic = GRAPHIC_INDEX_WALL_Y; break;
                case 78:
                    index_graphic = GRAPHIC_INDEX_WALL_XandY; break;
                case 80:
                    index_graphic = GRAPHIC_INDEX_WALL; break;
                }

                m_Palette_ForView[i] = index_graphic;
            }
        }
    }

    //画像設定
    static public function SetImage(in_Graphic:DisplayObject):void
    {
        m_BitmapData_View.draw(in_Graphic);
    }

    //#Draw : BG
    static public function Map_to_Bitmap(in_Map:Vector.<Vector.<int> >, out_BitmapData_View:BitmapData):void
    {
        var x:int, y:int, i:int;
        var mtx:Matrix = new Matrix();

        var NumX:int = in_Map[0].length;
        var NumY:int = in_Map.length;

        //Map => Bitmap_Base
        //Mapの要素を元に、「0:空白」「1:トゲ」「2:壁」というBitmapを生成
        var BitmapData_Base:BitmapData;
        {
            BitmapData_Base = new BitmapData(NumX, NumY, false, 0x000000);
            for(y = 0; y < NumY; y++){
                for(x = 0; x < NumX; x++){
                    var index:int = 0;//default(O, P, G)
                    {
                        switch(in_Map[y][x]){
                        case BallSwap.W:
                            index = 2;
                            break;
                        case BallSwap.X:
                            index = 1;
                            break;
                        }
                    }

                    BitmapData_Base.setPixel(x, y, index);
                }
            }
        }

        //Bitmap_Base => Bitmap_LU,Bitmap_RU,Bitmap_LD,Bitmap_RD
        //Bitmap_Baseを元に、四隅の隣接状況をそれぞれ求める(Uniqueな値になるようにする)
        var BitmapData_Quater:Array = new Array(4);
        {
            //Create Filter
            const filter:Array = [
                new ConvolutionFilter(3,3,
                    [//LU
                        1,  3,  0,
                        9, 27,  0,
                        0,  0,  0,
                    ]
                ),
                new ConvolutionFilter(3,3,
                    [//RU
                        0,  3,  1,
                        0, 27,  9,
                        0,  0,  0,
                    ]
                ),
                new ConvolutionFilter(3,3,
                    [//LD
                        0,  0,  0,
                        9, 27,  0,
                        1,  3,  0,
                    ]
                ),
                new ConvolutionFilter(3,3,
                    [//RD
                        0,  0,  0,
                        0, 27,  9,
                        0,  3,  1,
                    ]
                ),
            ];

            for(i = 0; i < 4; i++){
                //Init
                BitmapData_Quater[i] = new BitmapData(NumX, NumY, false, 0x000000);

                //Apply Filter
                BitmapData_Quater[i].applyFilter(BitmapData_Base, BitmapData_Base.rect, POS_ZERO, filter[i]);
            }
        }

        //Bitmap_LU,Bitmap_RU,Bitmap_LD,Bitmap_RD => ForView
        //Uniqueな値から、対応するIndexへと変換する
        var BitmapData_ForView:Array = new Array(4);
        {
            for(i = 0; i < 4; i++){
                //Init
                BitmapData_ForView[i] = new BitmapData(NumX, NumY, false, 0x000000);

                //Apply Palette
                BitmapData_ForView[i].paletteMap(BitmapData_Quater[i], BitmapData_Quater[i].rect, POS_ZERO, null, null, m_Palette_ForView);
            }
        }


        //Draw
        //上で求めたIndexに基づき描画
        {
            var rect:Rectangle = new Rectangle(0,0, 16,16);

            for(y = 0; y < NumY; y++){
                for(x = 0; x < NumX; x++){
                    for(i = 0; i < 4; i++){
                        rect.x = x * 32 + 16 * ((i&1)>>0);
                        rect.y = y * 32 + 16 * ((i&2)>>1);

                        //#view
                        mtx.tx = rect.x - 16 * GRAPHIC_INDEX_TO_POS[BitmapData_ForView[i].getPixel(x, y)][i][POS_X];
                        mtx.ty = rect.y - 16 * GRAPHIC_INDEX_TO_POS[BitmapData_ForView[i].getPixel(x, y)][i][POS_Y];
                        out_BitmapData_View.draw(m_BitmapData_View, mtx, null, null, rect);
                    }
                }
            }
        }
    }
}


//Game用のObject全般クラス
class GameObject extends Sprite
{//コリジョンまで含めたもの
    //==Const==

    static public const ANIM_NUM:int = 24;//16;//32;
    static public const ANIM_EXPAND_RATIO:Number = 5.0;//5.0;//3.0;


    //==Var==

    //コリジョン本体
    //- Swapの際に外部から位置を設定する場合などに使用
    public var m_Body:b2Body;

    //表示まわり
    public var m_Bitmap:Bitmap = new Bitmap();
    public var m_AnimList:Vector.<BitmapData> = new Vector.<BitmapData>(ANIM_NUM);


    //==Function==

    //Init
    public function GameObject(){
        addChild(m_Bitmap);
    }

    public function SetAnimIndex(in_Index:int):void{
        m_Bitmap.bitmapData = m_AnimList[in_Index];
    }

    public function CreateAnimList(in_BitmapData_Ori:BitmapData):void{
        var xx:int;
        var yy:int;

        var panel_len:int = BallSwap.PANEL_LEN;
        var anim_w:int = panel_len * ANIM_EXPAND_RATIO;
        var center_x:Number = panel_len / 2.0;
        var center_y:Number = panel_len / 2.0;

        var bmd_ori:BitmapData = in_BitmapData_Ori;

        var append_ratio:Vector.<Vector.<Number> > = new Vector.<Vector.<Number> >(panel_len);
        var timing_ratio:Vector.<Vector.<Number> > = new Vector.<Vector.<Number> >(panel_len);
        var rot_sin_ratio:Vector.<Vector.<Number> > = new Vector.<Vector.<Number> >(panel_len);
        var rot_cos_ratio:Vector.<Vector.<Number> > = new Vector.<Vector.<Number> >(panel_len);
        for(yy = 0; yy < panel_len; ++yy){
            append_ratio[yy] = new Vector.<Number>(panel_len);
            timing_ratio[yy] = new Vector.<Number>(panel_len);
            rot_sin_ratio[yy] = new Vector.<Number>(panel_len);
            rot_cos_ratio[yy] = new Vector.<Number>(panel_len);
            for(xx = 0; xx < panel_len; ++xx){
                append_ratio[yy][xx] = 1;// + 0.5*Math.random();
                timing_ratio[yy][xx] = 0.7 * (1 - 2*Math.random());
                var theta:Number = 0.1 * Math.PI * (1 - 2*Math.random());
                rot_sin_ratio[yy][xx] = Math.sin(theta);
                rot_cos_ratio[yy][xx] = Math.cos(theta);
            }
        }

        for(var i:int = 0; i < ANIM_NUM; ++i){
            var bmd:BitmapData = new BitmapData(anim_w, anim_w, true, 0x00000000);

            for(xx = 0; xx < panel_len; ++xx){
                var gap_x:Number = xx - center_x;
                for(yy = 0; yy < panel_len; ++yy){
                    var gap_y:Number = yy - center_y;

                    var color:uint = bmd_ori.getPixel32(xx, yy);
                    if((color & 0xFF000000) == 0x00000000){continue;}//透明部分はムシ

                    var gap:Number = Math.sqrt(gap_x*gap_x + gap_y*gap_y);

                    var expand_ratio:Number = 1.0 * i / ANIM_NUM;
                    if(0 < timing_ratio[yy][xx]){
                        expand_ratio = Util.Lerp(expand_ratio, Math.sin(0.5*Math.PI * expand_ratio), timing_ratio[yy][xx]);
                    }else{
                        expand_ratio = Util.Lerp(expand_ratio, 1-Math.cos(0.5*Math.PI * expand_ratio), -timing_ratio[yy][xx]);
                    }
                    expand_ratio = Util.Lerp(1, ANIM_EXPAND_RATIO * append_ratio[yy][xx], Math.sin(Math.PI * expand_ratio));

                    var expand_distance:Number = gap * expand_ratio;

                    if(gap <= 1){gap = 1;}//一応0を避ける

                    var base_expand_x:Number = gap_x * expand_distance / gap;
                    var base_expand_y:Number = gap_y * expand_distance / gap;
                    var cos:Number = Util.Lerp(1, rot_cos_ratio[yy][xx], Math.sin(Math.PI * i / ANIM_NUM));
                    var sin:Number = Util.Lerp(0, rot_sin_ratio[yy][xx], Math.sin(Math.PI * i / ANIM_NUM));
                    var expand_x:Number = base_expand_x * cos - base_expand_y * sin;
                    var expand_y:Number = base_expand_x * sin + base_expand_y * cos;

                    var trg_x:int = int(anim_w/2 + expand_x + 0.5);
                    var trg_y:int = int(anim_w/2 + expand_y + 0.5);

                    bmd.setPixel32(trg_x, trg_y, color);
                }
            }

            m_AnimList[i] = bmd;
        }
    }

    //Position
    public function SetPosition(in_X:Number, in_Y:Number):void{
        //Image
        {
            this.x = in_X;
            this.y = in_Y;
        }

        //Phys
        if(m_Body != null)
        {
            var pos:b2Vec2 = m_Body.GetPosition();
            pos.x = BallSwap.IMAGE_to_PHYS(in_X);
            pos.y = BallSwap.IMAGE_to_PHYS(in_Y);

            var angle:Number = m_Body.GetAngle();

            m_Body.SetXForm(pos, angle);
        }
    }

    //Touch
    public function GetTouchRangeRatio():Number{
        //タッチの近さを返す:1未満ならタッチ扱い、低いほど近い
        //Overrideして使う
        return 1.0;
    }

    //Update
    public function Update(in_DeltaTime:Number):void{
        //Overrideして使う
    }

    //Gravity
    public function SetGravity(in_GravityX:Number, in_GravityY:Number):void{
        m_Body.m_force = new b2Vec2_ForGravity(m_Body.GetMass() * in_GravityX, m_Body.GetMass() * in_GravityY);
    }
}


//
class GameObject_Ball extends GameObject
{
    //==Var==

    //タッチの範囲は実際の表示より少し大きくとる
    public var m_Range:Number = BallSwap.PANEL_LEN * 0.8;//BallSwap.PANEL_LEN/2;


    //==Function==

    //Init
    public function Init():void{
        //グラフィック
        {
            //Anim
            {
/*
                var bmd_ori:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);

                var shape:Shape = new Shape();
                DrawGraphics(shape.graphics);

                bmd_ori.draw(shape);
/*/
                var bmd_ori:BitmapData = GetOriBitmapData();
//*/
                CreateAnimList(bmd_ori);
            }

            //m_Bitmap
            {
                m_Bitmap.x = -m_AnimList[0].width/2;
                m_Bitmap.y = -m_AnimList[0].height/2;
                SetAnimIndex(0);
            }
        }

        //コリジョン
        {
            //Shape Def
            var shapeDef:b2ShapeDef = CreateShapeDef();

            //Body Def
            var bodyDef:b2BodyDef;
            {
                bodyDef = new b2BodyDef();
                bodyDef.position.Set(BallSwap.IMAGE_to_PHYS(this.x), BallSwap.IMAGE_to_PHYS(this.y));
                //bodyDef.fixedRotation = true;
            }

            //Body
            var body:b2Body;
            {
                body = BallSwap.Instance.m_Box2D_World.CreateBody(bodyDef);
                body.CreateShape(shapeDef);
                body.SetMassFromShapes();
                body.m_userData = this;
            }

            m_Body = body;

            SetGravity(0, BallSwap.GRAVITY);
        }
    }

    //Init : Graphic
/*
    public function DrawGraphics(g:Graphics):void{
        g.lineStyle(2, 0x000000, 0.9);
        g.beginFill(0x888888, 1.0);
        g.drawCircle(BallSwap.PANEL_LEN/2, BallSwap.PANEL_LEN/2, BallSwap.PANEL_LEN/2 * 0.9);
        g.endFill();
    }
/*/
    public function GetOriBitmapData():BitmapData{
        //Overrideして使う
        var bmd_ori:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);

        var shape:Shape = new Shape();
        var g:Graphics = shape.graphics;
        g.lineStyle(2, 0x000000, 0.9);
        g.beginFill(0x888888, 1.0);
        g.drawCircle(BallSwap.PANEL_LEN/2, BallSwap.PANEL_LEN/2, BallSwap.PANEL_LEN/2 * 0.9);
        g.endFill();

        bmd_ori.draw(shape);

        return bmd_ori;
    }
//*/

    //Init : Collision Param
    public function CreateShapeDef():b2ShapeDef{
        return CreateCircleDef();
    }
    public function CreateCircleDef():b2CircleDef{
        //Overrideして必要なものは変更する

        var shapeDef:b2CircleDef;
        {
            shapeDef = new b2CircleDef();
            shapeDef.radius = BallSwap.IMAGE_to_PHYS(BallSwap.PANEL_LEN/2 * 0.9);
            shapeDef.density = 1;//tekitou
            shapeDef.friction = 0;//5;
            shapeDef.restitution = 0.01;
        }

        return shapeDef;
    }

    //Touch
    override public function GetTouchRangeRatio():Number{
        var distance:Number = Math.sqrt(mouseX*mouseX + mouseY*mouseY);
        return (distance / m_Range);
    }
}

//
class Player extends GameObject_Ball
{
    //==Var==

    static public var s_BitmapData:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);


    //==Function==

    //Init
    public function Player(){
        Init();
    }

    //Init : Graphic
    override public function GetOriBitmapData():BitmapData{
        return s_BitmapData;
    }

    //Init : Collision
    override public function CreateCircleDef():b2CircleDef{
        var shapeDef:b2CircleDef;
        {
            shapeDef = super.CreateCircleDef();
            shapeDef.friction = 0;//0.01;
        }

        return shapeDef;
    }

    //Touch
    override public function GetTouchRangeRatio():Number{
        return 1.0;//プレイヤー自身は交換されない
    }
}

//
class GameObject_Ball_Fix extends GameObject_Ball
{
    //==Var==

    static public var s_BitmapData:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);


    //==Function==

    //Init
    public function GameObject_Ball_Fix(){
        Init();
    }

    //Init : Graphic
    override public function GetOriBitmapData():BitmapData{
        return s_BitmapData;
    }

    //Init : Collision
    override public function CreateCircleDef():b2CircleDef{
        var shapeDef:b2CircleDef;
        {
            shapeDef = super.CreateCircleDef();
            shapeDef.density = 0;//Fix
        }

        return shapeDef;
    }
}


//
class GameObject_Ball_Move extends GameObject_Ball
{
    //==Var==

    static public var s_BitmapData:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);
    static public var s_BitmapData_Arrow:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);


    //==Var==

//    public var m_IsRotRight:Boolean;

    public var m_RatioX:Number;
    public var m_RatioY:Number;


    //==Function==

    //Init
    public function GameObject_Ball_Move(in_RatioX:Number, in_RatioY:Number){
        m_RatioX = in_RatioX;
        m_RatioY = in_RatioY;

        Init();

//        m_IsRotRight = in_IsRotRight;

        SetGravity(in_RatioX * BallSwap.GRAVITY, in_RatioY * BallSwap.GRAVITY);
    }

    //Init : Graphic
    override public function GetOriBitmapData():BitmapData{
        var bmd:BitmapData = s_BitmapData.clone();

        var mtx:Matrix = new Matrix();
//        if(0 < m_RatioX){mtx.rotate(  0);        mtx.translate( 0*32, 0*32);}
        if(m_RatioX < 0){mtx.rotate(Math.PI);    mtx.translate( 1*32, 1*32);}
        if(m_RatioY < 0){mtx.rotate(-Math.PI/2);mtx.translate( 0*32, 1*32);}

        var ct:ColorTransform = new ColorTransform(0.3, 0.3, 0.3);

        bmd.draw(s_BitmapData_Arrow, mtx, ct, BlendMode.ADD);

        return bmd;
    }

    //Init : Collision
    override public function CreateCircleDef():b2CircleDef{
        var shapeDef:b2CircleDef;
        {
            shapeDef = super.CreateCircleDef();
            //shapeDef.density = 0;//Fix
            shapeDef.friction = 0;
        }

        return shapeDef;
    }

    //Update
    override public function Update(in_DeltaTime:Number):void{
/*
        var rot_vel:Number = BallSwap.IMAGE_to_PHYS(100);
        m_Body.SetAngularVelocity(m_IsRotRight? rot_vel: -rot_vel);
//*/
    }
}



//
class GameObject_Box extends GameObject
{
    //==Var==

    public var m_W:Number;
    public var m_H:Number;


    //==Function==

    //Init
    public function GameObject_Box(in_W:Number, in_H:Number, in_Ang:Number){
        //Param
        {
            m_W = in_W;
            m_H = in_H;
        }

        //グラフィック
        {
            //Anim
            {
                var bmd_ori:BitmapData = new BitmapData(in_W, in_H, true, 0xFF888888);

                m_AnimList[0] = bmd_ori;
            }

            //m_Bitmap
            {
                m_Bitmap.x = -in_W/2;
                m_Bitmap.y = -in_H/2;
                SetAnimIndex(0);
            }
        }

        //コリジョン
        {
            //Shape Def
            var shapeDef:b2ShapeDef = CreateShapeDef();

            //Body Def
            var bodyDef:b2BodyDef;
            {
                bodyDef = new b2BodyDef();
                bodyDef.position.Set(BallSwap.IMAGE_to_PHYS(this.x), BallSwap.IMAGE_to_PHYS(this.y));
                //bodyDef.fixedRotation = true;
                bodyDef.angle = in_Ang * Math.PI/180;
            }

            //Body
            var body:b2Body;
            {
                body = BallSwap.Instance.m_Box2D_World.CreateBody(bodyDef);
                body.CreateShape(shapeDef);
                body.SetMassFromShapes();
                body.m_userData = this;
            }

            m_Body = body;

            SetGravity(0, BallSwap.GRAVITY);
        }
    }

    //Init : Collision Param
    public function CreateShapeDef():b2ShapeDef{
        return CreateBoxDef();
    }
    public function CreateBoxDef():b2PolygonDef{
        //Overrideして必要なものは変更する

        var shapeDef:b2PolygonDef;
        {
            shapeDef = new b2PolygonDef();
            shapeDef.SetAsBox(BallSwap.IMAGE_to_PHYS(m_W/2), BallSwap.IMAGE_to_PHYS(m_H/2));
            shapeDef.density = 0;//fix
            shapeDef.friction = 0;
            shapeDef.restitution = 0.5;
        }

        return shapeDef;
    }
}


//#Goal
class Goal extends GameObject_Ball
{
    //==Var==

    static public var s_BitmapData:BitmapData = new BitmapData(BallSwap.PANEL_LEN, BallSwap.PANEL_LEN, true, 0x00000000);


    //==Function==

    //Init
    public function Goal(){
        Init();

        //Vanish Anim
        {
            var ct:ColorTransform = new ColorTransform();
            for(var i:int = 0; i < ANIM_NUM; ++i){
                var bmd:BitmapData = m_AnimList[i];

                var alpha:Number = Math.max(1 - 2*i/ANIM_NUM, 0);
                ct.alphaMultiplier = alpha;
                bmd.colorTransform(bmd.rect, ct);
            }
        }
    }

    //Init : Graphic
    override public function GetOriBitmapData():BitmapData{
        return s_BitmapData;
    }

    //Init : Collision
    override public function CreateCircleDef():b2CircleDef{
        var shapeDef:b2CircleDef;
        {
            shapeDef = super.CreateCircleDef();
            shapeDef.density = 0;//Fix
        }

        return shapeDef;
    }
}


class b2Vec2_ForGravity extends b2Vec2
{
    public function b2Vec2_ForGravity(x_:Number=0, y_:Number=0) : void {super(x_, y_)};
    //物理エンジン内でのリセットを無効化することで、forceを重力相当として扱う
    override public function SetZero() : void {}
}



class Util
{
    //Lerp
    static public function Lerp(in_Src:Number, in_Dst:Number, in_Ratio:Number):Number{
        return (in_Src * (1 - in_Ratio)) + (in_Dst * in_Ratio);
    }
}