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

白黒迷図 -Monochrome Maze-

スマホを傾けて白黒世界のゴールを目指すパズルゲーム
・シロクロ×ダイバーのスマホ用Ball&Maze版

操作方法(How to Play)
・PC版
 ・中心に対するマウス位置(Mouse Position)
  ・移動(Move)
・スマホ版(Smart Phone)
 ・本体を傾ける(Tilt)
  ・移動(Move)

リンク
・次回作とかの情報はTwitterなどでお知らせ中
 ・https://twitter.com/o_healer
・Android版
 ・https://play.google.com/store/apps/details?id=air.showohealer.game.works
Get Adobe Flash player
by o_healer 03 Feb 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/u3IG
 */

/*
 「白黒迷図 -Monochrome Maze-」
 ・スマホを傾けて白黒世界のゴールを目指すパズルゲーム
  ・シロクロ×ダイバーのスマホ用Ball&Maze版

 操作方法(How to Play)
 ・PC版
  ・中心に対するマウス位置(Mouse Position)
   ・移動(Move)
 ・スマホ版(Smart Phone)
  ・本体を傾ける(Tilt)
   ・移動(Move)

 リンク
 ・次回作とかの情報はTwitterなどでお知らせ中
  ・https://twitter.com/o_healer
 ・Android版
  ・https://play.google.com/store/apps/details?id=air.showohealer.game.works

 メモ
 ・monochrollのAir版
  ・monochrollのコード(Java)を移植
 ・ステージ選定
  ・wonderfl版&無料体験版は「マウスでもクリアできる」「ステージが正方形に近い」「表示があまり潰れない」ステージ
   ・「マウスでもクリアできる」=「微調整を要しない」「慣性を使わない」
 ・wmodeを設定すること
*/

package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;
    import flash.ui.*;
    import flash.utils.*;
    import flash.media.*;
    import flash.sensors.*;
    import flash.desktop.*;

    //3D
    import com.adobe.utils.AGALMiniAssembler;
    import flash.display3D.*;
    import flash.display3D.textures.*;
 
    [SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
//    [SWF(width="800", height="480", frameRate="30", backgroundColor="0x000000")]//Galaxy S, Galaxy S2
//    [SWF(width="1280", height="720", frameRate="30", backgroundColor="0x000000")]//Galaxy S3, Xperia Acro HD, SC-03E, SH02E
//    [SWF(width="1280", height="800", frameRate="30", backgroundColor="0x000000")]//Asus Nexus 7
//    [SWF(width="480", height="320", frameRate="30", backgroundColor="0x000000")]//iPhone 3G
//    [SWF(width="960", height="640", frameRate="30", backgroundColor="0x000000")]//iPhone 4
//    [SWF(width="1024", height="768", frameRate="30", backgroundColor="0x000000")]//iPad
//    [SWF(width="2048", height="1536", frameRate="30", backgroundColor="0x000000")]//Retina
    public class Monochroll_Wonderfl extends Sprite {

        //=File==
//*
        static public const BITMAP_URL:String = "http://assets.wonderfl.net/images/related_images/1/19/193c/193ccd1f7ed2c7e7ba40ed9017ab48589986cdda";
/*/
        [Embed(source='graphics.png')] private static var Bitmap_Graphic: Class;
//*/

        //==Const==

        //表示サイズ
        static public const VIEW_W:int = 465;
        static public const VIEW_H:int = 465;
        //実際の表示サイズ
        public function GetTotalW():int{
            //return Capabilities.screenResolutionX;
            return stage.stageWidth;
        }
        public function GetTotalH():int{
            //return Capabilities.screenResolutionY;
            return stage.stageHeight;
        }

        //3D
        static public const DEPTH_BLACK:Number = 0.4;
        static public const DEPTH_WHITE:Number = 0.6;
        static public const DEPTH_BALL :Number = 0.5;
        static public const COLOR_BLACK_RATIO:Number = 0.15;
        static public const COLOR_WHITE_RATIO:Number = 0.85;

        //一マスの大きさ
        static public const PANEL_W_SHIFT:int = 4;
        static public const PANEL_W:int = (1 << PANEL_W_SHIFT);

        //セット可能な物理OBJの総数(ボールも含む)
        static public const DYNAMIC_OBJ_NUM_MAX:int = 16;

        //ゲートの最大数
        //- 実際には2つ表示するので設置可能数は半分になる
        static public const GATE_NUM_MAX:int = 64;

        //連結可能なブロック数
        static public const BLOCK_CONNECT_NUM_MAX:int = 32;

        //重力
        static public const MOVE_POW:Number = 200.0;

        //ゴール演出用パラメータ
        static public const GOAL_FADE_TIME:Number = 1.0;
        static public const GOAL_SCL_MAX:Number = 2.0;

        //マップで指定可能な最大要素数
        //- スクリーンショットの準備などのため
        static public const MAP_NUM_MAX_X:int = 32;
        static public const MAP_NUM_MAX_Y:int = 32;

        //マップ要素
        static public const O:int = 0;//白地形
        //白地形(0)+1:上、2:下、4:左、8:右のゲートフラグで1~15までは埋まる
        static public const MAP_FLAG_GATE_U:int = (1 << 0);
        static public const MAP_FLAG_GATE_D:int = (1 << 1);
        static public const MAP_FLAG_GATE_L:int = (1 << 2);
        static public const MAP_FLAG_GATE_R:int = (1 << 3);
        static public const W:int = 16;//黒地形
        //一応黒地形の方も空けてはおく
        static public const P:int = 32;//プレイヤー(黒球:白地形)
        static public const Q:int = 33;//プレイヤー(白球:黒地形)
        static public const G:int = 34;//ゴール(白地形)
        static public const H:int = 35;//ゴール(黒地形)
        static public const B:int = 36;//連結ブロック(黒ブロック:白地形)
        static public const A:int = 37;//連結ブロック(白ブロック:黒地形)

        //マップ
        static public var MAP_TERRAIN:Vector.<Vector.<int> >;
        static public const MAP:Array = [
            {
                name:"Block",
                map:[
                [W,O,O,O,O,O,O,O,W],
                [W,O,O,O,A,O,O,O,W],
                [W,O,O,O,A,O,O,2,W],
                [O,Q,W,W,W,W,W,W,O],
                [O,O,O,O,O,O,O,O,O],
                [O,O,O,O,G,O,O,O,O],
                [O,O,O,O,O,O,O,O,O],
                ]
            },
            {
                name:"Waiting",
                map:[
                [W,W,W,W,W,W,W,O,W,W,W,W,W,W],
                [O,O,O,O,O,W,W,O,O,O,O,O,O,O],
                [P,O,O,O,W,W,W,A,A,A,O,O,O,G],
                [O,O,O,O,O,O,O,W,W,O,O,O,O,O],
                [W,W,W,W,W,W,O,W,W,W,W,W,W,W],
                ]
            },
            {//easy
                name:"Checkered",
                map:[
                [O,O,W,W,O,O,W,W,O,O],
                [O,O,W,W,O,O,W,W,O,O],
                [W,W,P,O,W,W,O,O,W,W],
                [W,W,O,O,W,W,O,O,W,W],
                [O,O,W,W,A,A,W,W,O,O],
                [O,O,W,W,A,A,W,W,O,O],
                [W,W,O,O,W,W,O,O,W,W],
                [W,W,O,O,W,W,O,G,W,W],
                [O,O,W,W,O,O,W,W,O,O],
                [O,O,W,W,O,O,W,W,O,O],
                ]
            },
            {//easy heavy?
                name:"Sync",
                map:[
                [P,O,W,O,O,O,W,O,O,O,W,O,G],
                [O,W,A,W,O,W,O,W,O,W,A,W,O],
                [W,A,A,A,W,O,O,O,W,A,A,A,W],
                [O,W,A,W,O,W,O,W,O,W,A,W,O],
                [O,O,W,O,O,O,W,O,O,O,W,O,O],
                [O,W,A,W,O,W,A,W,O,W,A,W,O],
                [W,A,A,A,W,A,A,A,W,A,A,A,W],
                [O,W,A,W,O,W,A,W,O,W,A,W,O],
                [O,O,W,O,O,O,W,O,O,O,W,O,O],
                ]
            },
            {//easy
                name:"Long",
                map:[
                [W,W,W,P,W,W,W,W,W,W,W],
                [A,W,W,W,O,W,W,W,W,W,W],
                [A,A,A,A,A,A,A,A,A,A,A],
                [W,W,W,W,W,W,O,W,W,W,A],
                [W,W,W,W,W,W,W,G,W,W,W],
                ]
            },
            {//easy
                name:"LL",
                map:[
                [W,W,W,W,W,W,W,W,W],
                [O,O,O,O,O,O,O,O,O],
                [P,O,O,B,O,B,O,O,G],
                [W,W,W,B,W,B,W,W,W],
                [B,B,O,B,W,B,O,B,B],
                [W,W,B,B,W,B,B,W,W],
                ]
            },
            {//easy
                name:"Transport",
                map:[
                [W,W,O,O,O,O,W,W,W,W,W],
                [W,W,O,P,O,O,W,W,W,W,W],
                [W,W,O,O,O,W,O,O,O,O,G],
                [W,W,O,W,W,W,W,W,O,O,O],
                [W,W,O,W,W,W,W,W,O,O,O],
                [O,O,W,W,W,A,W,W,W,O,O],
                [O,O,O,W,W,W,W,W,O,W,W],
                [O,O,O,W,W,W,W,W,O,W,W],
                [O,O,O,O,O,W,O,O,O,W,W],
                [W,W,W,W,W,O,O,O,O,W,W],
                [W,W,W,W,W,O,O,O,O,W,W],
                ]
            },
            {//easy
                name:"Waiting 2",
                map:[
                [O,O,O,W,O,O,O,O,O,O,O,W,O,O,O],
                [O,W,W,O,W,W,W,W,W,W,W,O,W,W,O],
                [W,O,O,O,B,B,O,O,O,O,O,O,O,O,W],
                [W,P,O,W,B,B,O,O,O,O,O,W,O,O,W],
                [W,O,O,O,B,B,O,O,O,O,O,O,O,2,W],
                [O,W,W,O,W,W,W,O,W,W,W,O,W,W,O],
                [O,W,W,W,W,H,W,O,W,W,W,W,W,W,O],
                [O,O,O,O,O,O,O,W,O,O,O,O,O,O,O],
                ]
            },
            {//easy
                name:"Vortex",
                map:[
                [W,W,O,O,O,O,O,W,W],
                [W,O,O,W,W,W,O,O,W],
                [O,O,W,W,O,W,W,O,O],
                [O,W,W,O,W,O,W,W,O],
                [O,W,O,W,P,W,O,W,O],
                [O,W,W,W,W,O,W,W,O],
                [O,O,W,O,O,W,W,O,O],
                [W,O,O,W,W,W,O,O,W],
                [W,W,O,O,A,O,O,W,W],
                [W,W,W,W,G,W,W,W,W],
                ]
            },
            {//easy
                name:"Container",
                map:[
                [W,W,W,O,O,O,O,O,O,O,O,O,W,W,W],
                [W,W,W,O,O,O,O,O,O,O,O,O,W,W,W],
                [W,O,W,O,O,O,O,O,O,O,O,O,W,G,W],
                [O,O,O,O,O,O,W,W,W,O,O,O,B,B,B],
                [O,O,O,O,O,O,W,W,W,O,O,O,B,B,B],
                [O,O,O,O,O,O,W,W,W,O,O,O,B,O,B],
                [W,P,W,W,W,W,W,W,W,W,W,W,W,O,W],
                ]
            },
            {//easy
                name:"Shift",
                map:[
                [W,W,W,W,W,W,W,W,W,W,W],
                [W,B,B,B,B,B,O,O,B,B,B],
                [W,B,O,B,O,B,O,O,W,W,O],
                [W,W,P,W,O,W,O,W,W,W,O],
                [W,W,W,W,W,W,W,W,W,W,G],
                ]
            },
            {//easy
                name:"Claw",
                map:[
                [W,W,O,O,O,O,O,O,O,O,W,W],
                [O,O,W,W,W,W,W,W,W,W,O,G],
                [O,O,W,W,W,W,W,W,W,W,O,O],
                [O,O,W,A,A,A,A,A,W,W,O,O],
                [O,O,W,A,O,P,W,A,W,W,O,O],
                [O,W,W,W,W,O,W,A,W,W,W,O],
                [O,W,W,A,W,W,W,A,W,W,W,O],
                [8,W,W,A,A,A,A,A,W,W,W,4],
                [W,O,O,O,O,O,O,O,O,O,O,W],
                ]
            },
            {//easy-mid
                name:"Stopper 1",
                map:[
                [W,W,W,W,W,W,O,O,O,O,O,O],
                [W,W,W,B,W,W,O,O,O,O,O,O],
                [W,W,W,B,W,W,O,O,O,O,O,O],
                [W,P,O,O,O,O,W,W,W,A,A,G],
                [W,W,W,W,W,W,O,O,A,O,O,O],
                [W,W,W,W,W,W,O,O,A,O,O,O],
                [W,W,W,W,W,W,O,O,O,O,O,O],
                ]
            },
            {//easy-mid heavy?
                name:"Connect",
                map:[
                [O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O],
                [O,Q,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O],
                [O,O,B,B,B,B,B,B,O,O,O,B,B,B,B,B,O,O,O],
                [O,O,B,O,O,O,W,B,O,O,O,B,O,O,W,B,O,O,O],
                [O,O,B,O,B,B,O,B,O,O,O,B,B,B,O,B,O,O,O],
                [O,O,B,B,B,B,B,B,O,O,O,O,O,B,B,B,O,O,H],
                [O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O],
                ]
            },
            {//easy-mid
                name:"Key",
                map:[
                [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W],
                [W,O,O,A,O,O,O,A,O,A,W,A,A,O,O,W,W],
                [W,O,O,A,O,O,O,A,O,O,O,A,W,O,O,W,W],
                [W,O,O,A,O,O,O,A,O,O,O,A,W,O,O,W,W],
                [W,O,O,A,O,O,O,A,O,O,O,A,O,O,O,W,W],
                [O,A,W,W,W,W,W,W,W,W,W,W,W,W,O,W,P],
                [O,A,A,A,A,W,W,W,W,W,W,W,W,W,W,W,W],
                [O,A,W,W,W,W,W,W,W,W,W,W,W,W,O,W,G],
                [W,O,O,O,O,A,O,O,O,A,O,O,O,O,O,W,W],
                [W,O,O,O,O,A,O,O,O,A,W,O,O,O,O,W,W],
                [W,O,O,O,O,A,O,O,O,A,W,O,O,O,O,W,W],
                [W,O,O,O,O,A,O,A,W,A,A,O,O,O,O,W,W],
                [W,O,O,O,O,O,O,O,O,O,O,O,O,O,O,W,W],
                ]
            },
            {//easy-mid
                name:"SF",
                map:[
                [W,O,O,O,O,O,O,O,W],
                [O,W,W,W,A,W,W,W,O],
                [O,W,A,W,A,W,O,O,O],
                [O,W,A,A,A,W,O,O,O],
                [O,O,W,A,A,W,W,O,O],
                [O,O,O,W,A,W,O,O,O],
                [O,W,O,W,A,W,O,O,O],
                [P,W,W,W,A,W,O,O,G],
                [W,O,O,O,O,O,O,O,W],
                ]
            },
            {
                name:"Control",
                map:[
                [W,O,O,O,O,P,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],
                [O,W,W,W,W,W,W,W,W,W,O],
                [O,A,W,W,W,W,W,W,O,O,W],
                [O,A,W,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,G,O,O,O,O,W],
                ]
            },
            {//mid
                name:"Stopper 2",
                map:[
                [O,O,W,W,W,W,W,O,O],
                [O,Q,O,O,O,O,8,W,O],
                [O,W,O,A,A,A,O,W,O],
                [O,W,O,A,W,A,O,W,O],
                [O,W,W,W,W,W,A,A,O],
                [O,O,O,O,O,O,O,O,O],
                [W,W,W,O,G,O,W,W,W],
                ]
            },
            {//difficult
                name:"Riding",
                map:[
                [P,W,W,W,O,O,O,W,W,W,G],
                [B,W,W,W,O,W,O,W,W,W,O],
                [O,W,W,W,O,W,O,W,B,W,O],
                [O,W,W,W,O,W,O,W,B,W,O],
                [O,O,O,O,O,W,O,O,B,B,O],
                [O,O,O,O,O,W,O,O,O,O,O],
                ]
            },
            {//insane
                name:"Progressive",
                map:[
                [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,O,O,W,W,O,B,O,B,B,O,O,O,O,O],
                [P,O,O,W,W,O,B,O,O,B,O,W,O,O,G],
                [O,O,O,O,O,O,B,B,O,B,O,W,O,O,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,O,W,W,W,W],
                ]
            },
        ];

        //Util
        static public const VIEW_RECT:Rectangle = new Rectangle(0,0,VIEW_W,VIEW_H);
        static public const POS_ZERO:Point = new Point(0,0);
        static public const s_Mtx_PanelLen:Matrix = new Matrix(PANEL_W,0,0,PANEL_W, 0,0);


        //==Var==

        //Pseudo Singleton
        static public var Instance:Monochroll_Wonderfl = null;

        //選択中のマップ
        public var m_MapIndex:int = 0;//50;//16;

        //レイヤー
        public var m_Layer_UI:Sprite                        = new Sprite();

        //3D
        //- Common
        public var m_Stage3D:Stage3D;
        public var m_Context3D:Context3D;
        public var m_Matrix3D:Matrix3D;
        //- Program
        public var m_ProgramPair:Program3D;
        public var m_ProgramPair_BG:Program3D;
        public var m_ProgramPair_Goal:Program3D;
        public var m_VertexAssembly:AGALMiniAssembler;
        public var m_FragmentAssembly:AGALMiniAssembler;
        public var m_FragmentAssembly_BG:AGALMiniAssembler;
        public var m_FragmentAssembly_Goal:AGALMiniAssembler;
        //- Vertices
        public var m_Vertices_White:VertexBuffer3D;
        public var m_Vertices_Black:VertexBuffer3D;
        public var m_Vertices_Ball:VertexBuffer3D;
        //- Indices
        public var m_Indices:IndexBuffer3D;
        //- Texture
        //-- Map
        public var m_BitmapData_Map:BitmapData;
        public var m_Texture_Map:Texture;
        //-- Block
        public var m_BitmapData_Block_White:BitmapData;
        public var m_BitmapData_Block_Black:BitmapData;
        public var m_Texture_Block_White:Texture;
        public var m_Texture_Block_Black:Texture;
        //-- Ball
        public var m_BitmapData_Ball_White:BitmapData;
        public var m_BitmapData_Ball_Black:BitmapData;
        public var m_Texture_Ball_White:Texture;
        public var m_Texture_Ball_Black:Texture;
        //-- Goal
        public var m_BitmapData_Goal_White:BitmapData;
        public var m_BitmapData_Goal_Black:BitmapData;
        public var m_Texture_Goal_White:Texture;
        public var m_Texture_Goal_Black:Texture;
        //-- Gate
        public var m_BitmapData_Gate:BitmapData;
        public var m_Texture_Gate:Texture;
        //- Shader
        //-- Vertex
        private const VERTEX_SHADER:String =
            "m44 op, va0, vc0                    \n" +
            "mov v0, va1";
        //-- Fragment
        private const FRAGMENT_SHADER_BG:String =
            "tex ft0, v0, fs0 <2d,nearest,clamp>    \n" +    //ft0にテクスチャ参照の結果を入れる
            "sub ft1.w, ft0.w, fc0.x                \n" +    //αを-1してKilチェック準備
            "kil ft1.w                                \n" +    //αが0の時は表示を飛ばす(深度を更新しない)
            "mov oc, ft0                            ";        //表示
        private const FRAGMENT_SHADER:String =
            "tex ft0, v0, fs0 <2d,linear,clamp>        \n" +    //ft0にテクスチャ参照の結果を入れる
            "sub ft1.w, ft0.w, fc0.x                \n" +    //αを-1してKilチェック準備
            "kil ft1.w                                \n" +    //αが0の時は表示を飛ばす(深度を更新しない)
            "mov oc, ft0                            ";        //表示
        private const FRAGMENT_SHADER_GOAL:String =
            "tex ft0, v0, fs0 <2d,linear,clamp>        \n" +    //ft0にテクスチャ参照の結果を入れる
            "mul ft0.w, ft0.w, fc0.y                \n" +    //αに定数をかける(フェード処理)
            "sub ft1.w, ft0.w, fc0.x                \n" +    //αを-1してKilチェック準備
            "kil ft1.w                                \n" +    //αが0の時は表示を飛ばす(深度を更新しない)
            "mov oc, ft0                            ";        //表示

        //Dialog
        public var m_PopupStack:Vector.<Popup> = new Vector.<Popup>();
        public var m_TopPopup:Popup = null;

        //物理OBJ
        public var m_PhysList:Vector.<DynamicBody> = new Vector.<DynamicBody>(DYNAMIC_OBJ_NUM_MAX);
        //移動用
        public var m_MoveInfo:Vector.<MoveInfo> = new Vector.<MoveInfo>(DYNAMIC_OBJ_NUM_MAX);

        //ゴール
        public var m_Goal:Goal;
        public var m_GoalFadeTimer:Number = 0;

        //ゲート
        public var m_Gate:Vector.<Gate>;

        //重力の取り扱い
        public var m_Accel:Accelerometer = null;
        //重力方向
        public var m_Gravity:Vector3D = new Vector3D(0,0);
        //重力の可視化
        public var m_Sprite_Gravity:Sprite = null;

        //作業用
        public var m_BlockConnectCount:int = 0;
        public var m_BlockInfo:Vector.<Vector.<int> >;
        public var m_HitTrgVX:Number = 0;//本当は返り値とかで渡したいのだが
        public var m_HitTrgVY:Number = 0;
        public var m_HitNextVX:Number = 0;
        public var m_HitNextVY:Number = 0;

        //デバッグ用
        public var m_DebugText:TextField;

        //フラグ
        public var m_ClearFlag:Boolean = false;



        //==Function==

        //=Init&Finish=

        //Init
        public function Monochroll_Wonderfl(){
            Instance = this;

//*
            //wonderfl用:Bitmapを外部からロードする場合

            //Load
            {
                var loader:Loader = new Loader();
                loader.load(new URLRequest(BITMAP_URL), new LoaderContext(true));//画像のロードを開始して
                loader.contentLoaderInfo.addEventListener(
                    Event.COMPLETE,//ロードが完了したら
                    function(e:Event):void{
                        ImageManager.Init(loader.content);//それを保持した後

                        InitStage();//初期化に入る
                    }
                );
            }

            //キャプチャのタイミング指定
            Wonderfl.capture_delay(30);//30秒後に実行
/*/
            //ローカル用:Bitmapを事前ロードできる場合

            //ブロック画像のセット(&その他初期化)
            ImageManager.Init(new Bitmap_Graphic());

            //本体の初期化
            addEventListener(Event.ADDED_TO_STAGE, InitStage);
//*/
        }
        public function InitStage(e:Event=null):void
        {
            //Settings
            {
/*
                //画面幅に合わせ、長い方が画面にフィットするように拡大
                //- 短い方は画面にフィットせず、もともと画面外だったものが内部表示されるかも
                stage.scaleMode = StageScaleMode.SHOW_ALL;
/*/
                //自前で計算することにした
                stage.scaleMode = StageScaleMode.NO_SCALE;
                stage.align = StageAlign.TOP_LEFT; 
//*/
            }

            //3D
            {
                m_Stage3D = stage.stage3Ds[0];
                m_Stage3D.addEventListener(Event.CONTEXT3D_CREATE, Init);
                m_Stage3D.requestContext3D(Context3DRenderMode.AUTO);
            }
        }
        public function Init(e:Event):void
        {
            var i:int;

            //3D
            {
                m_Context3D = Stage3D(e.target).context3D;
                //m_Context3D.enableErrorChecking = true;
                m_Context3D.configureBackBuffer(GetTotalW(), GetTotalH(), 0, true);

                m_Matrix3D = new Matrix3D();

                m_ProgramPair = m_Context3D.createProgram();
                m_ProgramPair_BG = m_Context3D.createProgram();
                m_ProgramPair_Goal = m_Context3D.createProgram();

                m_VertexAssembly = new AGALMiniAssembler();
                m_VertexAssembly.assemble(Context3DProgramType.VERTEX, VERTEX_SHADER);

                m_FragmentAssembly = new AGALMiniAssembler();
                m_FragmentAssembly.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER);

                m_FragmentAssembly_BG = new AGALMiniAssembler();
                m_FragmentAssembly_BG.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER_BG);

                m_FragmentAssembly_Goal = new AGALMiniAssembler();
                m_FragmentAssembly_Goal.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER_GOAL);

                m_ProgramPair.upload(m_VertexAssembly.agalcode, m_FragmentAssembly.agalcode);
                m_ProgramPair_BG.upload(m_VertexAssembly.agalcode, m_FragmentAssembly_BG.agalcode);
                m_ProgramPair_Goal.upload(m_VertexAssembly.agalcode, m_FragmentAssembly_Goal.agalcode);

                //- 頂点データ
                const VERTEX_DATA_WHITE:Vector.<Number> = Vector.<Number>([
                     0,-1,DEPTH_WHITE, 0,1,  // x,y,z, u,v のフォーマット
                     0, 0,DEPTH_WHITE, 0,0,
                     1, 0,DEPTH_WHITE, 1,0,
                     1,-1,DEPTH_WHITE, 1,1
                ]);
                const VERTEX_DATA_BLACK:Vector.<Number> = Vector.<Number>([
                     0,-1,DEPTH_BLACK, 0,1,  // x,y,z, u,v のフォーマット
                     0, 0,DEPTH_BLACK, 0,0,
                     1, 0,DEPTH_BLACK, 1,0,
                     1,-1,DEPTH_BLACK, 1,1
                ]);
                const VERTEX_DATA_BALL:Vector.<Number> = Vector.<Number>([
                     0,-1,DEPTH_BALL, 0,1,  // x,y,z, u,v のフォーマット
                     0, 0,DEPTH_BALL, 0,0,
                     1, 0,DEPTH_BALL, 1,0,
                     1,-1,DEPTH_BALL, 1,1
                ]);
                m_Vertices_White = m_Context3D.createVertexBuffer(4,5);
                m_Vertices_Black = m_Context3D.createVertexBuffer(4,5);
                m_Vertices_Ball  = m_Context3D.createVertexBuffer(4,5);
                m_Vertices_White.uploadFromVector(VERTEX_DATA_WHITE, 0, 4);
                m_Vertices_Black.uploadFromVector(VERTEX_DATA_BLACK, 0, 4);
                m_Vertices_Ball.uploadFromVector(VERTEX_DATA_BALL, 0, 4);

                //- Indexデータ
                const INDEX_DATA:Vector.<uint> = Vector.<uint>([
                    0, 1, 2,
                    2, 3, 0,
                ]);
                m_Indices = m_Context3D.createIndexBuffer(6);
                m_Indices.uploadFromVector(INDEX_DATA, 0, 6);

                //テクスチャの設定
                //- 地形ブロック
//                m_BitmapData_Map = new BitmapData(128, 128, true, 0x00000000);
                m_BitmapData_Map = new BitmapData(MAP_NUM_MAX_X, MAP_NUM_MAX_Y, true, 0x00000000);
                m_Texture_Map = m_Context3D.createTexture(m_BitmapData_Map.width, m_BitmapData_Map.height, Context3DTextureFormat.BGRA, false);
                //- ブロック
                m_BitmapData_Block_White = ImageManager.GetBitmapData(ImageManager.GRAPHIC_BLOCK_WHITE);
                m_BitmapData_Block_Black = ImageManager.GetBitmapData(ImageManager.GRAPHIC_BLOCK_BLACK);
                m_Texture_Block_White = m_Context3D.createTexture(m_BitmapData_Block_White.width, m_BitmapData_Block_White.height, Context3DTextureFormat.BGRA, false);
                m_Texture_Block_Black = m_Context3D.createTexture(m_BitmapData_Block_Black.width, m_BitmapData_Block_Black.height, Context3DTextureFormat.BGRA, false);
                m_Texture_Block_White.uploadFromBitmapData(m_BitmapData_Block_White);
                m_Texture_Block_Black.uploadFromBitmapData(m_BitmapData_Block_Black);
                //- ボール
                m_BitmapData_Ball_White = ImageManager.GetBitmapData(ImageManager.GRAPHIC_BALL_WHITE);
                m_BitmapData_Ball_Black = ImageManager.GetBitmapData(ImageManager.GRAPHIC_BALL_BLACK);
                m_Texture_Ball_White = m_Context3D.createTexture(m_BitmapData_Ball_White.width, m_BitmapData_Ball_White.height, Context3DTextureFormat.BGRA, false);
                m_Texture_Ball_Black = m_Context3D.createTexture(m_BitmapData_Ball_Black.width, m_BitmapData_Ball_Black.height, Context3DTextureFormat.BGRA, false);
                m_Texture_Ball_White.uploadFromBitmapData(m_BitmapData_Ball_White);
                m_Texture_Ball_Black.uploadFromBitmapData(m_BitmapData_Ball_Black);
                //- ゴール
                m_BitmapData_Goal_White = ImageManager.GetBitmapData(ImageManager.GRAPHIC_GOAL_WHITE);
                m_BitmapData_Goal_Black = ImageManager.GetBitmapData(ImageManager.GRAPHIC_GOAL_BLACK);
                m_Texture_Goal_White = m_Context3D.createTexture(m_BitmapData_Goal_White.width, m_BitmapData_Goal_White.height, Context3DTextureFormat.BGRA, false);
                m_Texture_Goal_Black = m_Context3D.createTexture(m_BitmapData_Goal_Black.width, m_BitmapData_Goal_Black.height, Context3DTextureFormat.BGRA, false);
                m_Texture_Goal_White.uploadFromBitmapData(m_BitmapData_Goal_White);
                m_Texture_Goal_Black.uploadFromBitmapData(m_BitmapData_Goal_Black);
                //- ゲート
                m_BitmapData_Gate = ImageManager.GetBitmapData(ImageManager.GRAPHIC_GATE);
                m_Texture_Gate = m_Context3D.createTexture(m_BitmapData_Gate.width, m_BitmapData_Gate.height, Context3DTextureFormat.BGRA, false);
                m_Texture_Gate.uploadFromBitmapData(m_BitmapData_Gate);
            }

            //Param
            {
                m_BlockInfo = new Vector.<Vector.<int> >(BLOCK_CONNECT_NUM_MAX);
                for(i = 0; i < BLOCK_CONNECT_NUM_MAX; ++i){
                    m_BlockInfo[i] = new Vector.<int>(3);
                }
            }

            //レイヤー
            {
                addChild(m_Layer_UI);
                //ゲームパートはStage3Dで描くので、この手のレイヤーはUIだけ
            }

            //加速度センサー
            {
                if(Accelerometer.isSupported){
                    m_Accel = new Accelerometer();
                    m_Accel.setRequestedUpdateInterval(100);
                    m_Accel.addEventListener(AccelerometerEvent.UPDATE, SetGravity_Listener);
                }else{
                    //可視化準備もここで行う
                    m_Sprite_Gravity = new Sprite();
                    m_Sprite_Gravity.x = GetTotalW()/2;
                    m_Sprite_Gravity.y = GetTotalH()/2;
                    m_Sprite_Gravity.addChild(ImageManager.GetBitmap_GravityArrow());
                    m_Layer_UI.addChild(m_Sprite_Gravity);
                }
            }

            //Touch
            {
                //Listener
                stage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
                stage.addEventListener(MouseEvent.MOUSE_MOVE, OnMouseMove);
                stage.addEventListener(MouseEvent.MOUSE_UP,   OnMouseUp);
            }
            //Key
            {
                stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
            }

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

            //OnEnd
            {
                addEventListener(Event.REMOVED_FROM_STAGE, Finish);
            }

            //Rest
            {
                Reset();
            }

            //Debug
            {
                m_DebugText = new TextField();
                m_DebugText.selectable = false;
                m_DebugText.autoSize = TextFieldAutoSize.LEFT;
                m_DebugText.defaultTextFormat = new TextFormat('Verdana', 16, 0xFFFF00, true);
                m_DebugText.text = "";
                addChild(m_DebugText);
            }

            //タイトルから開始
            {
                PushPopup(new Popup_Title());
            }
        }

        //Reset
        public function Reset():void{
            var i:int;
            var x_:int;
            var y_:int;

            //Alias
            var MAP_NUM_X:int = GetMapNumX();
            var MAP_NUM_Y:int = GetMapNumY();

            //Param
            {
                m_ClearFlag = false;
                m_GoalFadeTimer = 0;

                m_Gate = new Vector.<Gate>(GATE_NUM_MAX);
                for(i = 0; i < GATE_NUM_MAX; ++i){
                    m_Gate[i] = null;
                }
            }

            //m_PhysList
            {
                for(i = 0; i < DYNAMIC_OBJ_NUM_MAX; ++i)
                {
                    //Delete Old
                    if(m_PhysList[i] != null)
                    {
                        m_PhysList[i].Finish();
                        m_PhysList[i] = null;
                    }
                }
            }

            {
                //MAP_TERRAINを作成しつつ各種情報を抜き出す
                var PlayerX:int = 0;
                var PlayerY:int = 0;
                var PlayerColorFlag:int = DynamicDot.FLAG_BLACK;
                var GoalX:int = 0;
                var GoalY:int = 0;
                var GoalAddDrawFlag:Boolean = false;
                {
                    var GateIter:int = 0;
                    var BlockIter:int = 0;

                    //まずは普通にコピー
                    MAP_TERRAIN = new Vector.<Vector.<int> >(MAP_NUM_Y);
                    for(y_ = 0; y_ < MAP_NUM_Y; ++y_){
                        MAP_TERRAIN[y_] = new Vector.<int>(MAP_NUM_X);
                        for(x_ = 0; x_ < MAP_NUM_X; ++x_){
                            MAP_TERRAIN[y_][x_] = GetMapVal_Ori(x_, y_);
                        }
                    }

                    var rect:Rectangle = new Rectangle(0,0,PANEL_W,PANEL_W);
                    var mtx:Matrix = new Matrix();

                    //地形に置き換えつつ情報取得
                    for(y_ = 0; y_ < MAP_NUM_Y; ++y_){
                        rect.y = y_ * PANEL_W;
                        var PosY:int = Util.FloorInt((y_ + 0.5) * PANEL_W);
                        for(x_ = 0; x_ < MAP_NUM_X; ++x_){
                            rect.x = x_ * PANEL_W;
                            var PosX:int = Util.FloorInt((x_ + 0.5) * PANEL_W);

                            var MapVal:int = MAP_TERRAIN[y_][x_];

                            //デフォルトは白置き換え
                            MAP_TERRAIN[y_][x_] = O;

                            switch(MapVal){
                            case W://黒地形
                                MAP_TERRAIN[y_][x_] = W;//黒地形
                                break;
                            case Q://プレイヤー(黒地形)
                                PlayerColorFlag = DynamicDot.FLAG_WHITE;
                                MAP_TERRAIN[y_][x_] = W;//黒地形
                                //no break
                            case P://プレイヤー(白地形)
                                PlayerX = PosX;
                                PlayerY = PosY;
                                break;
                            case H://ゴール(黒地形)
                                MAP_TERRAIN[y_][x_] = W;//黒地形
                                GoalAddDrawFlag = true;
                                //no break
                            case G://ゴール(白地形)
                                //GoalX = 
                                GoalX = PosX;
                                GoalY = PosY;
                                break;
                            case A://白連結ブロック(黒地形)
                                MAP_TERRAIN[y_][x_] = W;//黒地形
                                break;
                            }
                            //ブロック部分の置き換えは別途行う

                            //Gate
                            if(1 <= MapVal && MapVal <= 15){
                                var AddDrawFlag:Boolean = ((MAP_TERRAIN[y][x] & 1) == W);
                                var rot_offset:Number = AddDrawFlag? 0: 180;
                                if((MapVal & MAP_FLAG_GATE_U) != 0){
                                    m_Gate[GateIter++] = new Gate(PosX, PosY - PANEL_W/2,   0 + rot_offset);
                                }
                                if((MapVal & MAP_FLAG_GATE_D) != 0){
                                    m_Gate[GateIter++] = new Gate(PosX, PosY + PANEL_W/2, 180 + rot_offset);
                                }
                                if((MapVal & MAP_FLAG_GATE_L) != 0){
                                    m_Gate[GateIter++] = new Gate(PosX - PANEL_W/2, PosY,  90 + rot_offset);
                                }
                                if((MapVal & MAP_FLAG_GATE_R) != 0){
                                    m_Gate[GateIter++] = new Gate(PosX + PANEL_W/2, PosY, 270 + rot_offset);
                                }
                            }

                            //Block
                            {
                                if(MapVal == B){//連結ブロック:黒
                                    CreateBlock(x_, y_, MapVal, BlockIter+1);

                                    ++BlockIter;
                                }
                                if(MapVal == A){//連結ブロック:白
                                    CreateBlock(x_, y_, MapVal, BlockIter+1);

                                    ++BlockIter;
                                }
                            }
                        }
                    }
                }
            }

            //Player
            {
                var ball:Ball = new Ball();
                ball.Init(this, PlayerX, PlayerY, PlayerColorFlag);

                m_PhysList[0] = ball;
            }

            //Goal
            {
                m_Goal = new Goal(this, GoalX, GoalY, GoalAddDrawFlag);
            }

            //3D
            {
                const white_val:uint = 0xFF * COLOR_WHITE_RATIO;
                const color_white:uint = 0xFF000000 | (white_val << 16) | (white_val << 8) | (white_val << 0);

                var map_num_x:int = GetMapNumX();
                var map_num_y:int = GetMapNumY();
                m_BitmapData_Map.fillRect(m_BitmapData_Map.rect, 0x00000000);
                for(var yy:int = 0; yy< map_num_y; ++yy){
                    for(var xx:int = 0; xx < map_num_x; ++xx){
                        var color:uint = (GetMapVal_WorO(xx, yy) == W)? 0x00000000: color_white;
                        m_BitmapData_Map.setPixel32(xx, yy, color);
                    }
                }
                m_Texture_Map.uploadFromBitmapData(m_BitmapData_Map);
            }
        }

        public function CreateBlock(in_X:int, in_Y:int, in_MapVal:int, in_Iter:int):void
        {
            //Search
            {
                m_BlockConnectCount = 0;
                CreateBlock_Recursive(in_X, in_Y, in_MapVal);
            }

            //Check : Connect
            {
                //再帰だけでは不十分な場合があるので、全てできあがってからチェック
                var Num:int = m_BlockConnectCount;
                for(var i:int = 0; i < Num; ++i){
                    var X_I:int = m_BlockInfo[i][0];
                    var Y_I:int = m_BlockInfo[i][1];

                    for(var j:int = i+1; j < Num; ++j){
                        var X_J:int = m_BlockInfo[j][0];
                        var Y_J:int = m_BlockInfo[j][1];

                        if(X_I == X_J){
                            //縦並び
                            if(Y_I - PANEL_W == Y_J){
                                //Iの上がJ
                                m_BlockInfo[i][2] |= Block.FLAG_CONNECT_U;
                                m_BlockInfo[j][2] |= Block.FLAG_CONNECT_D;
                                continue;
                            }
                            if(Y_I + PANEL_W == Y_J){
                                //Jの下がI
                                m_BlockInfo[i][2] |= Block.FLAG_CONNECT_D;
                                m_BlockInfo[j][2] |= Block.FLAG_CONNECT_U;
                                continue;
                            }
                        }

                        if(Y_I == Y_J){
                            //横並び
                            if(X_I - PANEL_W == X_J){
                                //Iの左がJ
                                m_BlockInfo[i][2] |= Block.FLAG_CONNECT_L;
                                m_BlockInfo[j][2] |= Block.FLAG_CONNECT_R;
                                continue;
                            }
                            if(X_I + PANEL_W == X_J){
                                //Jの右がI
                                m_BlockInfo[i][2] |= Block.FLAG_CONNECT_R;
                                m_BlockInfo[j][2] |= Block.FLAG_CONNECT_L;
                                continue;
                            }
                        }
                    }
                }
            }

            //Create
            {
                var ColorFlag:int = (in_MapVal == B)? DynamicDot.FLAG_BLACK: DynamicDot.FLAG_WHITE;
                var block:Block = new Block();
                block.Init(this, ColorFlag, m_BlockInfo, m_BlockConnectCount);
                m_PhysList[in_Iter] = block;
            }
        }
        public function CreateBlock_Recursive(in_X:int, in_Y:int, in_MapVal:int):void
        {
            //Add Info
            {
                m_BlockInfo[m_BlockConnectCount][0] = in_X * PANEL_W;
                m_BlockInfo[m_BlockConnectCount][1] = in_Y * PANEL_W;
                m_BlockInfo[m_BlockConnectCount][2] = 0;//Flags
                ++m_BlockConnectCount;
            }

            //Replace
            {
                if(in_MapVal == B){
                    //黒ブロックがあるのは白地形
                    MAP_TERRAIN[in_Y][in_X] = O;
                }else{
                    //白ブロックがあるのは黒地形
                    MAP_TERRAIN[in_Y][in_X] = W;
                }
            }

            //Recursive
            {
                //L
                if(0 < in_X){
                    if(MAP_TERRAIN[in_Y][in_X-1] == in_MapVal){
                        CreateBlock_Recursive(in_X-1, in_Y, in_MapVal);
                    }
                }
                //R
                if(in_X < GetMapNumX()-1){
                    if(MAP_TERRAIN[in_Y][in_X+1] == in_MapVal){
                        CreateBlock_Recursive(in_X+1, in_Y, in_MapVal);
                    }
                }
                //U
                if(0 < in_Y){
                    if(MAP_TERRAIN[in_Y-1][in_X] == in_MapVal){
                        CreateBlock_Recursive(in_X, in_Y-1, in_MapVal);
                    }
                }
                //D
                if(in_Y < GetMapNumY()-1){
                    if(MAP_TERRAIN[in_Y+1][in_X] == in_MapVal){
                        CreateBlock_Recursive(in_X, in_Y+1, in_MapVal);
                    }
                }
            }
        }

        //Finish
        public function Finish(e:Event):void{
            removeEventListener(Event.ADDED_TO_STAGE, InitStage);
            removeEventListener(Event.ENTER_FRAME, Update);
            removeEventListener(Event.REMOVED_FROM_STAGE, Finish);
        }


        //=Map=

        static public const MAP_NUM:int = MAP.length;
        //実質定数(選択しているMAPによって変わる)
        public function GetMapNumX():int{return MAP[m_MapIndex].map[0].length;}
        public function GetMapNumY():int{return MAP[m_MapIndex].map.length;}
        public function GetMapW():int{return PANEL_W * GetMapNumX();}
        public function GetMapH():int{return PANEL_W * GetMapNumY();}
        public function GetMapVal_Ori(in_IndexX:int, in_IndexY:int):int{return MAP[m_MapIndex].map[in_IndexY][in_IndexX];}
        public function GetMapVal(in_IndexX:int, in_IndexY:int):int{
            //範囲外は黒として扱う
            if(in_IndexX < 0){return W;}
            if(GetMapNumX() <= in_IndexX){return W;}
            if(in_IndexY < 0){return W;}
            if(GetMapNumY() <= in_IndexY){return W;}
            return MAP[m_MapIndex].map[in_IndexY][in_IndexX];
        }
        public function GetMapVal_WorO(in_IndexX:int, in_IndexY:int):int{//黒地形か白地形かだけを表す地形情報
            var Val:int = O;
            switch(GetMapVal(in_IndexX, in_IndexY)){
            case W://黒地形
            case Q://プレイヤー(白球:黒地形)
            case H://ゴール(黒地形)
            case A://白ブロック(黒地形)
                Val = W;
                break;
            }
            return Val;
        }
        public function GetMapVal_Terrain(in_IndexX:int, in_IndexY:int):int{//ゲート情報を含む地形情報
            if(in_IndexX < 0){return W;}
            if(GetMapNumX() <= in_IndexX){return W;}
            if(in_IndexY < 0){return W;}
            if(GetMapNumY() <= in_IndexY){return W;}

            var Val:int = MAP[m_MapIndex].map[in_IndexY][in_IndexX];
            switch(Val){
            case P://プレイヤー(黒球:白地形)
                Val = O; break;
            case Q://プレイヤー(白球:黒地形)
                Val = W; break;
            case G://ゴール(白地形)
                Val = O; break;
            case H://ゴール(黒地形)
                Val = W; break;
            case B://黒ブロック(白地形)
                Val = O; break;
            case A://白ブロック(黒地形)
                Val = W; break;
            }
            return Val;
        }


        //=Touch=
        //- Down
        public function OnMouseDown(e:Event):void{
            if(m_TopPopup != null){
                m_TopPopup.OnMouseDown();
                return;
            }
        }
        //- Move
        public function OnMouseMove(e:Event):void{
            if(m_TopPopup != null){
                m_TopPopup.OnMouseMove();
                return;
            }

            //Gravity Arrowは序盤だけの表示にしてみる
            if(m_Sprite_Gravity != null){
                m_Sprite_Gravity.alpha -= 0.0001;
                if(m_Sprite_Gravity.alpha <= 0){
                    m_Sprite_Gravity.parent.removeChild(m_Sprite_Gravity);
                    m_Sprite_Gravity = null;
                }
            }
        }
        //- Up
        public function OnMouseUp(e:Event):void{
            if(m_TopPopup != null){
                m_TopPopup.OnMouseUp();
                return;
            }

            //Popupがない
            //=ゲーム中のタッチ
            //→メニューを出す
            var is_clear:Boolean = false;
            PushPopup(new Popup_Menu(is_clear));
        }

        //=Key=
        private function OnKeyDown(event:KeyboardEvent):void{
            switch(event.keyCode){
            case Keyboard.BACK://バックキー
//            case Keyboard.ESCAPE://PC動作チェック用
                if(m_TopPopup != null){
                    m_TopPopup.OnBack();
                }else{
                    //終了
                    //NativeApplication.nativeApplication.exit();
                }
                break;
            }
        }

        //=Popup=
        //- Push
        public function PushPopup(in_Popup:Popup):void{
            //Push Stack
            m_PopupStack.push(in_Popup);

            //Latest
            m_TopPopup = in_Popup;

            //Register View
            m_Layer_UI.addChild(in_Popup);
        }
        //- Pop
        public function PopPopup():void{
            //Remove Old
            var next_popup:Popup;
            {
                var popup:Popup = m_PopupStack.pop();
                next_popup = popup.GetNextPopup();
                popup.parent.removeChild(popup);
            }

            //Remember Top
            {
                var length:int = m_PopupStack.length;
                if(0 < length){
                    m_TopPopup = m_PopupStack[length - 1];
                }else{
                    m_TopPopup = null;
                }
            }

            if(next_popup != null){
                PushPopup(next_popup);
            }
        }

        //=Update=

        //Update
        public function Update(e:Event=null):void{
            var DeltaTime:Number = 1.0 / stage.frameRate;

            Update_CPU(DeltaTime);
            Update_GPU();
        }
        //Update : CPU
        public function Update_CPU(in_DeltaTime:Number):void{
            if(m_TopPopup != null){
                m_TopPopup.Update(in_DeltaTime);
                if(m_TopPopup.IsEnd()){
                    PopPopup();
                }
                return;//ダイアログ表示中
            }

            if(m_ClearFlag){
                if(m_GoalFadeTimer < GOAL_FADE_TIME){
                    m_GoalFadeTimer += in_DeltaTime;
                    if(GOAL_FADE_TIME <= m_GoalFadeTimer){
                        //セーブデータ更新
                        var is_first_all_clear:Boolean;
                        {
                            var is_all_clear_old:Boolean = IsAllClear();

                            SetClear(m_MapIndex);

                            var is_all_clear_new:Boolean = IsAllClear();

                            is_first_all_clear = (!is_all_clear_old && is_all_clear_new);
                        }

                        if(! is_first_all_clear){
                            //普通のクリアリザルト
                            var is_clear:Boolean = true;
                            PushPopup(new Popup_Menu(is_clear));
                        }else{
                            //コングラッチュレーション
                            PushPopup(new Popup_Congratulation());
                        }
                    }
                }

                return;
            }

            Update_Phys(in_DeltaTime);

            Check_Goal();

            //Debug
            //m_DebugText.text = "y:" + m_PhysList[1].y;
        }
        //Update : GPU
        public function Update_GPU():void{
            //Stage3Dを使うので毎フレーム必ず呼ぶ
            Update_Draw();
        }

        //Update : Physics
        public function Update_Phys(in_DeltaTime:Number):void{
            //擬似タイミング調整
            //- 全てのOBJを1ドットずつ進ませることで擬似的にスケジューリング

            var i:int;
            var j:int;
            var db:DynamicBody;
            var DotList:Vector.<DynamicDot>;
            var DotNum:int;
            var dd:DynamicDot;
            var info:MoveInfo;
            var AddX:int;
            var AddY:int;
            var IntSrcX:int;
            var IntSrcY:int;
            var IntDstX:int;
            var IntDstY:int;
            var HitDotIter:int;
            var Flags:int;
            var NrmX:Number;
            var NrmY:Number;
            var NegDot:Number;

            var DeltaTime:Number = in_DeltaTime;

            var Gravity:Vector3D = GetGravity();

            //Init
            {
                for(i = 0; i < DYNAMIC_OBJ_NUM_MAX; ++i){
                    db = m_PhysList[i];

                    if(db == null){//空が来たら
                        break;//そこで終了(以降には何も詰められてないものとする)
                    }

                    //Alias
                    DotList = db.m_DotList;
                    DotNum = DotList.length;

                    var SrcX:Number = db.m_X;
                    var SrcY:Number = db.m_Y;
                    var DstX:Number = (SrcX) + (db.m_VX * DeltaTime) + (0.5 * Gravity.x * DeltaTime * DeltaTime);
                    var DstY:Number = (SrcY) + (db.m_VY * DeltaTime) + (0.5 * Gravity.y * DeltaTime * DeltaTime);

                    IntSrcX = Util.FloorInt(SrcX);
                    IntSrcY = Util.FloorInt(SrcY);
                    IntDstX = Util.FloorInt(DstX);
                    IntDstY = Util.FloorInt(DstY);

                    AddX = (IntSrcX < IntDstX)? 1: -1;
                    AddY = (IntSrcY < IntDstY)? 1: -1;

                    if(m_MoveInfo[i] == null){
                        m_MoveInfo[i] = new MoveInfo();
                    }

                    info = m_MoveInfo[i];

                    info.IntSrcX = IntSrcX;
                    info.IntSrcY = IntSrcY;
                    info.IntDstX = IntDstX;
                    info.IntDstY = IntDstY;
                    info.IterX = IntSrcX;
                    info.IterY = IntSrcY;
                    info.AddX = AddX;
                    info.AddY = AddY;

                    info.DstX = DstX;
                    info.DstY = DstY;

                    //事前移動
                    //- マスをまたがない場合、すぐに移動させてしまう
                    if(IntSrcX == IntDstX){
                        db.m_X = DstX;
                        db.m_VX += Gravity.x * DeltaTime;
                    }
                    if(IntSrcY == IntDstY){
                        db.m_Y = DstY;
                        db.m_VY += Gravity.y * DeltaTime;
                    }
                }
            }

            //Move Loop
            {
    //            const REFLECT_RATIO:Number = 0.1;
                const REFLECT_RATIO:Number = 0;
                const Epsilon:Number = 0.01;//境界線からこの距離だけ離れる

                var AllDoneFlag:Boolean = false;
                for(var t:int = 0; !AllDoneFlag; t++){
                    AllDoneFlag = true;

                    for(i = 0; i < DYNAMIC_OBJ_NUM_MAX; ++i){
                        info = m_MoveInfo[i];

                        //全てのOBJを見たらそこで終了
                        if(info == null){
                            break;
                        }

                        //Alias
                        var IterX:int = info.IterX;
                        var IterY:int = info.IterY;
                        AddX = info.AddX;
                        AddY = info.AddY;
                        IntSrcX = info.IntSrcX;
                        IntSrcY = info.IntSrcY;
                        IntDstX = info.IntDstX;
                        IntDstY = info.IntDstY;

                        //こいつの分の移動が終わっているならこいつはスキップ
                        if(IterX == IntDstX && IterY == IntDstY){
                            continue;
                        }


                        //==移動処理==


                        //こいつの移動処理が残っているのでループはまだ回すようにしておく
                        AllDoneFlag = false;


                        db = m_PhysList[i];

                        if(db == null){//大丈夫だとは思うが念のためチェック
                            break;
                        }

                        //Alias
                        DotList = db.m_DotList;
                        DotNum = DotList.length;

                        //X
                        if(IterX != IntDstX){
                            HitDotIter = -1;
                            for(j = 0; j < DotNum; ++j){
                                dd = DotList[j];

                                if(dd == null){
                                    continue;
                                }

                                Flags = dd.m_Flags;

                                //移動方向と合っているドットのみチェック
                                if(AddX < 0){//左移動時は
                                    if((Flags & DynamicDot.FLAG_L) == 0){//左からぶつかるドットしかチェックしない
                                        continue;
                                    }
                                }else{//右移動時は
                                    if((Flags & DynamicDot.FLAG_R) == 0){//右からぶつかるドットしかチェックしない
                                        continue;
                                    }
                                }
                                if(IsHitElse(Flags, IterX+AddX + dd.m_RelX, IntSrcY + dd.m_RelY, IterX + dd.m_RelX, IntSrcY + dd.m_RelY, db)){
                                    HitDotIter = j;
                                    db.m_HitState |= DynamicBody.AXIS_X;
                                    break;
                                }
                            }


                            if(0 <= HitDotIter){
                                //横方向にぶつかったので、移動を止めつつ反射処理
                                if(IntSrcX < IntDstX){
                                    db.m_X = IterX+1 - Epsilon;
                                }else{
                                    db.m_X = IterX + Epsilon;
                                }

                                dd = DotList[HitDotIter];//ヒットしたドットの位置を元に法線を求めて反射する

                                if(i == 0){
                                    //ボール
                                    //→反射
                                    {
                                        NrmX = 1.0*dd.m_RelX/Ball.PHYS_RAD;
                                        if(NrmX < -1){NrmX = -1;}
                                        if( 1 < NrmX){NrmX =  1;}

                                        NrmY = Math.sqrt(1 - NrmX*NrmX);
                                        if(dd.m_RelY < 0){NrmY = -NrmY;}
                                    }

                                    NegDot = -(NrmX * db.m_VX + NrmY * db.m_VY);

                                    if(NegDot < 0){
                                        if(m_HitTrgVX != 0){
                                            db.m_VX = m_HitTrgVX;
                                        }else{
                                            db.m_VX += NrmX * (NegDot * (1 + REFLECT_RATIO));
                                        }
                                        db.m_VY += NrmY * (NegDot * (1 + REFLECT_RATIO));
                                    }else{
                                        //ゲートのでっぱりなどで起こる
    //                                    db.m_VX += db.m_AX * DeltaTime;
                                        db.m_VX = 0;
                                    }
                                }else{
                                    //連結ブロック
                                    //→固定
                                    //db.m_VX = 0;
                                    db.m_VX = m_HitTrgVX;
                                }

                                //もう処理しないようにしておく
                                info.IterX = IntDstX;
                            }else{
                                //今回の分の移動
                                info.IterX += info.AddX;

                                if(info.IterX == IntDstX){//最後までぶつからずに到達した
                                    //ぶつからなかったらそのまま移動
                                    db.m_X = info.DstX;
                                    db.m_VX += Gravity.x * DeltaTime;
                                }else{//途中なら他との衝突判定のための仮座標だけ入れておく
                                    db.m_X = info.IterX;
                                }

                                db.m_MoveState |= DynamicBody.AXIS_X;
                            }

                            //Yの移動はXの移動が終わってからにしてみる
                            continue;
                        }

                        //Replace
                        //IterX = info.IterX;
                        var BaseX:int = Util.FloorInt(db.m_X);

                        //Y
                        if(IterY != IntDstY){
                            HitDotIter = -1;
                            for(j = 0; j < DotNum; ++j){
                                dd = DotList[j];

                                if(dd == null){
                                    continue;
                                }

                                Flags = dd.m_Flags;

                                //移動方向と合っているドットのみチェック
                                if(AddY < 0){//上移動時は
                                    if((Flags & DynamicDot.FLAG_U) == 0){//上からぶつかるドットしかチェックしない
                                        continue;
                                    }
                                }else{//下移動時は
                                    if((Flags & DynamicDot.FLAG_D) == 0){//下からぶつかるドットしかチェックしない
                                        continue;
                                    }
                                }

                                if(IsHitElse(Flags, BaseX + dd.m_RelX, IterY+AddY + dd.m_RelY, BaseX + dd.m_RelX, IterY + dd.m_RelY, db)){
                                    HitDotIter = j;
                                    db.m_HitState |= DynamicBody.AXIS_Y;
                                    break;
                                }
                            }


                            if(0 <= HitDotIter){
                                //縦方向にぶつかったので、移動を止めつつ反射処理
                                if(IntSrcY < IntDstY){
                                    db.m_Y = IterY+1 - Epsilon;
                                }else{
                                    db.m_Y = IterY + Epsilon;
                                }

                                dd = DotList[HitDotIter];

                                if(i == 0){
                                    //ボール
                                    //→反射
                                    {
                                        NrmY = 1.0*dd.m_RelY/Ball.PHYS_RAD;
                                        if(NrmY < -1){NrmY = -1;}
                                        if( 1 < NrmY){NrmY =  1;}

                                        NrmX = Math.sqrt(1 - NrmY*NrmY);
                                        if(dd.m_RelX < 0){NrmX = -NrmX;}
                                    }

                                    NegDot = -(NrmX * db.m_VX + NrmY * db.m_VY);

                                    if(NegDot < 0){
                                        db.m_VX += NrmX * (NegDot * (1 + REFLECT_RATIO));
                                        if(m_HitTrgVY != 0){
                                            db.m_VY = m_HitTrgVY;
                                        }else{
                                            db.m_VY += NrmY * (NegDot * (1 + REFLECT_RATIO));
                                        }
                                    }else{
    //                                    db.m_VY += db.m_AY * DeltaTime;
                                        db.m_VY = 0;
                                    }
                                }else{
                                    //連結ブロック
                                    //→固定
                                    //db.m_VY = 0;
                                    db.m_VY = m_HitTrgVY;
                                }

                                //もう処理しないようにしておく
                                info.IterY = IntDstY;
                            }else{
                                //今回の分の移動
                                info.IterY += info.AddY;

                                if(info.IterY == IntDstY){//最後までぶつからずに到達した
                                    //ぶつからなかったらそのまま移動
                                    db.m_Y = info.DstY;
                                    db.m_VY += Gravity.y * DeltaTime;
                                }else{//途中なら他との衝突判定のための仮座標だけ入れておく
                                    db.m_Y = info.IterY;
                                }

                                db.m_MoveState |= DynamicBody.AXIS_Y;
                            }
                        }
                    }
                }
            }

            //SE
            {
                for(i = 0; i < DYNAMIC_OBJ_NUM_MAX; ++i){
                    db = m_PhysList[i];

                    if(db == null){//空が来たら
                        break;//そこで終了(以降には何も詰められてないものとする)
                    }

                    if(db.m_HitState != 0){//このフレームで衝突していて
                        if((db.m_HitState & db.m_MoveState) != 0){//衝突方向に事前に動いていたら
                            //ヒットSEを鳴らす
                            var IsWhite:Boolean;
                            {
                                if((db.m_MoveState & DynamicBody.AXIS_X) != 0 && (db.m_HitState & DynamicBody.AXIS_X) != 0){
                                    IsWhite = (db.m_HitColorX == DynamicDot.FLAG_WHITE);
                                }else{
                                    IsWhite = (db.m_HitColorY == DynamicDot.FLAG_WHITE);
                                }
                            }

//                            if(IsWhite){
//                                PlaySE(m_SoundID_Hit_W);
//                            }else{
//                                PlaySE(m_SoundID_Hit_B);
//                            }

                            //軽く振動させる
                            //int vib_msec = 15;
                            //Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
                            //vibrator.vibrate(vib_msec);
                        }

                        //衝突したら情報をリセット
                        //- このまま再び壁にぶつかっても、MoveStateの方が0のままなので鳴らないはず
                        db.m_MoveState &= ~db.m_HitState;//今回の衝突方向の移動はリセット
                        db.m_HitState = 0;
                    }
                }
            }
        }

        //
        public function IsHitElse(in_Flags:int, in_NextX:int, in_NextY:int, in_PrevX:int, in_PrevY:int, in_Own:DynamicBody):Boolean{
            //in_Ownのin_ColorFlag色のドットが(in_PrevX, in_PrevY)から(in_NextX, in_NextY)に移動しようとする時、地形や他のOBJにぶつかるか、のチェック
            var IsSousai:Boolean;

            m_HitTrgVX = 0;
            m_HitTrgVY = 0;

            var Flags_Prev:int = 0;
            var Flags_Next:int = 0;

            //ゲートからの侵入は不可(相殺向こう)
            var IsPrevGate:Boolean;

            //まずは地形のチェック
            //- この時点でぶつかっても、他のブロックが隣接していて境界線がなくなっている可能性もあるため、判断はまだ保留
            {
                var IsCheckTerrain:Boolean = ((in_Flags & DynamicDot.FLAG_NOHIT_TERRAIN) == 0);

                Flags_Prev = GetTerrainFlag(in_PrevX, in_PrevY, in_Own, IsCheckTerrain, false);

                IsPrevGate = ((Flags_Prev & DynamicDot.FLAG_GATE) != 0);

                m_HitNextVX = 0;
                m_HitNextVY = 0;
                Flags_Next = GetTerrainFlag(in_NextX, in_NextY, in_Own, IsCheckTerrain, IsPrevGate);
            }

            //この段階でヒット時の音色は決めてしまう
            {
                if(in_Own == m_PhysList[0]){
                    //ボール
                    //- 移動先の色と同じ色としてぶつかる
    //                in_Own.m_HitColor = Flags_Next & 1;//画面外の処理が面倒なので、Prevの方の判定にする
                    if(in_NextX != in_PrevX){
                        in_Own.m_HitColorX = Flags_Next & 1;
                    }else{
                        in_Own.m_HitColorY = Flags_Next & 1;
                    }
                }else{
                    //連結ブロック
                    //- 基本はブロックの色だが、外枠の場合球とぶつかるので反対色として扱う
                    if(in_NextX != in_PrevX){
                        in_Own.m_HitColorX = in_Flags & 1;
                    }else{
                        in_Own.m_HitColorY = in_Flags & 1;
                    }
                }
            }

            //基本的に移動先の情報を元に通過可能かを決める
            //- 移動先が通行不可でも、移動前の位置で無効化されていれば通行可能とする
            {
                var HitCheckFlag:Boolean;
                {
                    HitCheckFlag = ((Flags_Next & 1) == (in_Flags & 1));//同色のみぶつかる

                    if(in_Own == m_PhysList[0]){//ボールに限り
                        //前回の地形の色と、次の地形の色が同じなら通過する(=HitCheckしない)
                        var PrevColor:int = (Flags_Prev & 1);
                        var NextColor:int = (Flags_Next & 1);

                        //ブロックの外枠の色は無視して背景の色にする
    //                    if((Flags_Prev & DynamicDot.FLAG_NOHIT_TERRAIN) != 0){
    //                        PrevColor = (GetMapVal_WorO(in_PrevX >> PANEL_W_SHIFT, in_PrevY >> PANEL_W_SHIFT) == O)? DynamicDot.FLAG_WHITE: DynamicDot.FLAG_BLACK;
    //                    }
    //                    if((Flags_Next & DynamicDot.FLAG_NOHIT_TERRAIN) != 0){
    //                        NextColor = (GetMapVal_WorO(in_NextX >> PANEL_W_SHIFT, in_NextY >> PANEL_W_SHIFT) == O)? DynamicDot.FLAG_WHITE: DynamicDot.FLAG_BLACK;
    //                    }

                        HitCheckFlag = (PrevColor != NextColor);

                        if(IsPrevGate){//ゲートからの侵入は色に関係なくヒットする
                            HitCheckFlag = true;
                        }

                        if((Flags_Next & DynamicDot.FLAG_GATE) != 0){//移動先がゲートであれば
                            HitCheckFlag = false;//問答無用で通過可能(チェック不要)
                        }
                    }else{//ブロックに限り
                        if((in_Flags & DynamicDot.FLAG_NOHIT_TERRAIN) != 0){//さらに外枠に限り
                            if((Flags_Prev & DynamicDot.FLAG_BALL) != 0){//ボールにヒット中であれば
                                if((Flags_Next & DynamicDot.FLAG_BALL) != 0){//次でボールから離脱できるのでもない限り
                                    return true;//移動しない
                                }
                            }

                            if((in_Flags & 1) != (Flags_Next & 1)){//ボールが自分に入っている(=自分と逆の色になっている)ようであれば
                                if((Flags_Next & DynamicDot.FLAG_BALL) != 0){//外枠がボールに当たる場合
                                    m_HitTrgVX = m_PhysList[0].m_VX;
                                    m_HitTrgVY = m_PhysList[0].m_VY;
                                    return true;//移動しない
                                }
                            }

                            //外枠はボール以外には当たらないことにする
                            //- 他のブロックと隣接して離れないことがあった
                            if((Flags_Next & DynamicDot.FLAG_BALL) == 0){
                                return false;
                            }
                        }else{
                            //内枠:せっかくなのでここでも処理
                            if((Flags_Next & DynamicDot.FLAG_BALL) != 0 && ((in_Flags & 1) == (Flags_Next & 1))){//移動先が外にある(=自分と同色の)ボールなら
                                m_HitTrgVX = m_PhysList[0].m_VX;
                                m_HitTrgVY = m_PhysList[0].m_VY;
                                return true;//必ずぶつかる
                            }
                        }
                    }
                }

                var ApplyVelFlag:Boolean;
                {
                    //外枠に触れる場合も、地形接触と同時であれば地形の方を優先する=速度の反映はしない
                    ApplyVelFlag = ((Flags_Next & DynamicDot.FLAG_TERRAIN) == 0);
                }

                if(HitCheckFlag){
                    //右移動
                    if(in_PrevX < in_NextX){
    //                    if((in_Flags & DynamicDot.FLAG_R) != 0){//自分:右への移動でぶつかる
                            if((Flags_Next & DynamicDot.FLAG_L) != 0){//相手:左からの移動にはぶつかる
                                //相殺(同じ色が隣接している場合、境界による遮断はなくなる)
                                IsSousai = ((Flags_Prev & 1) == (Flags_Next & 1) && (Flags_Prev & DynamicDot.FLAG_R) != 0);
                                if(! IsSousai || IsPrevGate){
                                    if(ApplyVelFlag){
                                        m_HitTrgVX = m_HitNextVX;
                                        m_HitTrgVY = m_HitNextVY;
                                    }
                                    return true;
                                }
                            }
    //                    }
                    }
                    //左移動
                    if(in_NextX < in_PrevX){
    //                    if((in_Flags & DynamicDot.FLAG_L) != 0){//自分:左への移動でぶつかる
                            if((Flags_Next & DynamicDot.FLAG_R) != 0){//相手:右からの移動にはぶつかる
                                //相殺(同じ色が隣接している場合、境界による遮断はなくなる)
                                IsSousai = ((Flags_Prev & 1) == (Flags_Next & 1) && (Flags_Prev & DynamicDot.FLAG_L) != 0);
                                if(! IsSousai || IsPrevGate){
                                    if(ApplyVelFlag){
                                        m_HitTrgVX = m_HitNextVX;
                                        m_HitTrgVY = m_HitNextVY;
                                    }
                                    return true;
                                }
                            }
    //                    }
                    }
                    //下移動
                    if(in_PrevY < in_NextY){
    //                    if((in_Flags & DynamicDot.FLAG_D) != 0){//自分:下への移動でぶつかる
                            if((Flags_Next & DynamicDot.FLAG_U) != 0){//相手:上からの移動にはぶつかる
                                //相殺(同じ色が隣接している場合、境界による遮断はなくなる)
                                IsSousai = ((Flags_Prev & 1) == (Flags_Next & 1) && (Flags_Prev & DynamicDot.FLAG_D) != 0);
                                if(! IsSousai || IsPrevGate){
                                    if(ApplyVelFlag){
                                        m_HitTrgVX = m_HitNextVX;
                                        m_HitTrgVY = m_HitNextVY;
                                    }
                                    return true;
                                }
                            }
    //                    }
                    }
                    //上移動
                    if(in_NextY < in_PrevY){
    //                    if((in_Flags & DynamicDot.FLAG_U) != 0){//自分:上への移動でぶつかる
                            if((Flags_Next & DynamicDot.FLAG_D) != 0){//相手:下からの移動にはぶつかる
                                //相殺(同じ色が隣接している場合、境界による遮断はなくなる)
                                IsSousai = ((Flags_Prev & 1) == (Flags_Next & 1) && (Flags_Prev & DynamicDot.FLAG_U) != 0);
                                if(! IsSousai || IsPrevGate){
                                    if(ApplyVelFlag){
                                        m_HitTrgVX = m_HitNextVX;
                                        m_HitTrgVY = m_HitNextVY;
                                    }
                                    return true;
                                }
                            }
    //                    }
                    }
                }
            }

            //チェックにひっかからなければ、何にもヒットしないとする
            return false;
        }

        //
        public function GetTerrainFlag(in_X:int, in_Y:int, in_Own:DynamicBody, in_IsCheckTerrain:Boolean, in_IsPrevGate:Boolean):int{
            var i:int;
            var j:int;
            var db:DynamicBody;
            var BaseX:int;
            var BaseY:int;

            const MASK:int = PANEL_W-1;//PANEL_Wが2の階乗であるという前提

            var IndexX:int = (in_X >> PANEL_W_SHIFT);
            var IndexY:int = (in_Y >> PANEL_W_SHIFT);

            var TerrainVal:int = GetMapVal_Terrain(IndexX, IndexY);
            var WorO:int = GetMapVal_WorO(IndexX, IndexY);
            var TerrainColorFlag:int = (WorO == O)? DynamicDot.FLAG_WHITE: DynamicDot.FLAG_BLACK;

            //返す値
            //- 境界線でなければ、普通に色だけ返す
            //- 境界線であればフラグを追加して返す(角なら2つのフラグが追加されることになる)
            var Flags:int = (WorO == O)? DynamicDot.FLAG_WHITE: DynamicDot.FLAG_BLACK;

            //地形
            if(in_IsCheckTerrain)
            {
                //境界線チェック
                if((in_X & MASK) == 0){
                    //マスの左端
                    //→左のマスから今のマスに入ろうとする場合の当たり判定が存在する

                    if(in_IsPrevGate || WorO != GetMapVal_WorO(IndexX-1, IndexY)){//境界線ができる(=違う色)
                        Flags |= DynamicDot.FLAG_L | DynamicDot.FLAG_TERRAIN;
                    }

                    if(((TerrainVal & MAP_FLAG_GATE_L) != 0) || ((GetMapVal_Terrain(IndexX-1, IndexY) & MAP_FLAG_GATE_R) != 0)){//現在のマスと隣接マスのどちらかがゲート指定していればゲートフラグ
                        Flags |= DynamicDot.FLAG_GATE;
                    }
                }
                if((in_X & MASK) == MASK){
                    //マスの右端
                    //→右のマスから今のマスに入ろうとする場合の当たり判定が存在する

                    if(in_IsPrevGate || WorO != GetMapVal_WorO(IndexX+1, IndexY)){//境界線ができる(=違う色)
                        Flags |= DynamicDot.FLAG_R | DynamicDot.FLAG_TERRAIN;
                    }

                    if(((TerrainVal & MAP_FLAG_GATE_R) != 0) || ((GetMapVal_Terrain(IndexX+1, IndexY) & MAP_FLAG_GATE_L) != 0)){//現在のマスと隣接マスのどちらかがゲート指定していればゲートフラグ
                        Flags |= DynamicDot.FLAG_GATE;
                    }
                }
                if((in_Y & MASK) == 0){
                    //マスの上端
                    //→上のマスから今のマスに入ろうとする場合の当たり判定が存在する

                    if(in_IsPrevGate || WorO != GetMapVal_WorO(IndexX, IndexY-1)){//境界線ができる(=違う色)
                        Flags |= DynamicDot.FLAG_U | DynamicDot.FLAG_TERRAIN;
                    }

                    if(((TerrainVal & MAP_FLAG_GATE_U) != 0) || ((GetMapVal_Terrain(IndexX, IndexY-1) & MAP_FLAG_GATE_D) != 0)){//現在のマスと隣接マスのどちらかがゲート指定していればゲートフラグ
                        Flags |= DynamicDot.FLAG_GATE;
                    }
                }
                if((in_Y & MASK) == MASK){
                    //マスの下端
                    //→下のマスから今のマスに入ろうとする場合の当たり判定が存在する

                    if(in_IsPrevGate || WorO != GetMapVal_WorO(IndexX, IndexY+1)){//境界線ができる(=違う色)
                        Flags |= DynamicDot.FLAG_D | DynamicDot.FLAG_TERRAIN;
                    }

                    if(((TerrainVal & MAP_FLAG_GATE_D) != 0) || ((GetMapVal_Terrain(IndexX, IndexY+1) & MAP_FLAG_GATE_U) != 0)){//現在のマスと隣接マスのどちらかがゲート指定していればゲートフラグ
                        Flags |= DynamicDot.FLAG_GATE;
                    }
                }
            }

            //動的OBJ
            {
                //ブロック
                var BgColorFlag:int = Flags;
                for(i = 1; i < DYNAMIC_OBJ_NUM_MAX; ++i)
                {
                    db = m_PhysList[i];

                    //空ならここで終了
                    if(db == null){
                        break;
                    }

                    //自分自身はスキップ
                    if(db == in_Own){
                        continue;
                    }

                    //範囲外ならスキップ
                    BaseX = (0 <= db.m_X)? int(db.m_X): int(db.m_X)-1;//Util.FloorInt(db.m_X);
                    BaseY = (0 <= db.m_Y)? int(db.m_Y): int(db.m_Y)-1;//Util.FloorInt(db.m_Y);
                    if(in_X < BaseX + db.m_RelAABB_MinX){continue;}
                    if(BaseX + db.m_RelAABB_MaxX < in_X){continue;}
                    if(in_Y < BaseY + db.m_RelAABB_MinY){continue;}
                    if(BaseY + db.m_RelAABB_MaxY < in_Y){continue;}

                    var b:Block = db as Block;
                    var Panel:Vector.<Vector.<int> > = b.m_Panel;
                    var ColorFlag:int = b.m_ColorFlag;

                    //地形と同じ要領で判断する
                    var PanelNum:int = Panel.length;
                    for(j = 0; j < PanelNum; ++j){
                        var p:Vector.<int> = Panel[j];
                        var AbsPanelX:int = BaseX + p[0];
                        var AbsPanelY:int = BaseY + p[1];
                        var PanelFlags:int = p[2];//隣接ブロックがある方向は無視する対応

                        var RelX:int = in_X - AbsPanelX;
                        var RelY:int = in_Y - AbsPanelY;

                        //内枠
                        if(0 <= RelX && RelX < PANEL_W && 0 <= RelY && RelY < PANEL_W)
                        {
                            Flags = ColorFlag;

                            //境界線チェック
                            if((RelX & MASK) == 0 && ((PanelFlags & Block.FLAG_CONNECT_L) == 0)){
                                //マスの左端
                                //→左のマスから今のマスに入ろうとする場合の当たり判定が存在する
                                Flags |= DynamicDot.FLAG_L;
                                m_HitNextVX = db.m_VX;
                                m_HitNextVY = db.m_VY;
                                BgColorFlag &= ~ 1;
                                BgColorFlag |= ColorFlag;
                            }
                            if((RelX & MASK) == MASK && ((PanelFlags & Block.FLAG_CONNECT_R) == 0)){
                                //マスの右端
                                //→右のマスから今のマスに入ろうとする場合の当たり判定が存在する
                                Flags |= DynamicDot.FLAG_R;
                                m_HitNextVX = db.m_VX;
                                m_HitNextVY = db.m_VY;
                                BgColorFlag &= ~ 1;
                                BgColorFlag |= ColorFlag;
                            }
                            if((RelY & MASK) == 0 && ((PanelFlags & Block.FLAG_CONNECT_U) == 0)){
                                //マスの上端
                                //→上のマスから今のマスに入ろうとする場合の当たり判定が存在する
                                Flags |= DynamicDot.FLAG_U;
                                m_HitNextVX = db.m_VX;
                                m_HitNextVY = db.m_VY;
                                BgColorFlag &= ~ 1;
                                BgColorFlag |= ColorFlag;
                            }
                            if((RelY & MASK) == MASK && ((PanelFlags & Block.FLAG_CONNECT_D) == 0)){
                                //マスの下端
                                //→下のマスから今のマスに入ろうとする場合の当たり判定が存在する
                                Flags |= DynamicDot.FLAG_D;
                                m_HitNextVX = db.m_VX;
                                m_HitNextVY = db.m_VY;
                                BgColorFlag &= ~ 1;
                                BgColorFlag |= ColorFlag;
                            }

                            break;//同じ連結ブロックの他のパネルに重なることはありえないのでここで終了
                        }

                        //外枠
                        if(RelX == -1){
                            //左端にあり、右から来るボールを止めるための枠
                            if(0 <= RelY && RelY < PANEL_W && ((PanelFlags & Block.FLAG_CONNECT_L) == 0)){
                                if(TerrainColorFlag != ColorFlag){//相殺していない場合のみ(- ブロックの相殺はこの段階で考慮する)
                                    Flags = BgColorFlag | DynamicDot.FLAG_R;
                                    //凹の形で連結された場合、外枠が重なるためbreakはせず蓄積させる
                                    //break;
                                    BgColorFlag |= DynamicDot.FLAG_R;//やや手抜きだが
                                    m_HitNextVX = db.m_VX;
                                    m_HitNextVY = db.m_VY;
                                }
                            }
                        }
                        if(RelX == PANEL_W){
                            //右端にあり、左から来るボールを止めるための枠
                            if(0 <= RelY && RelY < PANEL_W && ((PanelFlags & Block.FLAG_CONNECT_R) == 0)){
                                if(TerrainColorFlag != ColorFlag){//相殺していない場合のみ(- ブロックの相殺はこの段階で考慮する)
                                    Flags = BgColorFlag | DynamicDot.FLAG_L;
                                    //凹の形で連結された場合、外枠が重なるためbreakはせず蓄積させる
                                    //break;
                                    BgColorFlag |= DynamicDot.FLAG_L;//やや手抜きだが
                                    m_HitNextVX = db.m_VX;
                                    m_HitNextVY = db.m_VY;
                                }
                            }
                        }
                        if(RelY == -1){
                            //上端にあり、下から来るボールを止めるための枠
                            if(0 <= RelX && RelX < PANEL_W && ((PanelFlags & Block.FLAG_CONNECT_U) == 0)){
                                if(TerrainColorFlag != ColorFlag){//相殺していない場合のみ(- ブロックの相殺はこの段階で考慮する)
                                    Flags = BgColorFlag | DynamicDot.FLAG_D;
                                    //凹の形で連結された場合、外枠が重なるためbreakはせず蓄積させる
                                    //break;
                                    BgColorFlag |= DynamicDot.FLAG_D;//やや手抜きだが
                                    m_HitNextVX = db.m_VX;
                                    m_HitNextVY = db.m_VY;
                                }
                            }
                        }
                        if(RelY == PANEL_W){
                            //下端にあり、上から来るボールを止めるための枠
                            if(0 <= RelX && RelX < PANEL_W && ((PanelFlags & Block.FLAG_CONNECT_D) == 0)){
                                if(TerrainColorFlag != ColorFlag){//相殺していない場合のみ(- ブロックの相殺はこの段階で考慮する)
                                    Flags = BgColorFlag | DynamicDot.FLAG_U;
                                    //凹の形で連結された場合、外枠が重なるためbreakはせず蓄積させる
                                    //break;
                                    BgColorFlag |= DynamicDot.FLAG_U;//やや手抜きだが
                                    m_HitNextVX = db.m_VX;
                                    m_HitNextVY = db.m_VY;
                                }
                            }
                        }
                    }
                }

                //ボール
                for(i = 0; i < 1; ++i)
                {
                    db = m_PhysList[i];

                    //空ならここで終了
                    if(db == null){
                        break;
                    }

                    //自分自身はスキップ
                    if(db == in_Own){
                        continue;
                    }

                    //範囲外ならスキップ
                    BaseX = (0 <= db.m_X)? int(db.m_X): int(db.m_X)-1;//Util.FloorInt(db.m_X);
                    BaseY = (0 <= db.m_Y)? int(db.m_Y): int(db.m_Y)-1;//Util.FloorInt(db.m_Y);
                    if(in_X < BaseX + db.m_RelAABB_MinX){continue;}
                    if(BaseX + db.m_RelAABB_MaxX < in_X){continue;}
                    if(in_Y < BaseY + db.m_RelAABB_MinY){continue;}
                    if(BaseY + db.m_RelAABB_MaxY < in_Y){continue;}

                    //動的OBJのドットがこの位置にあれば、地形よりも優先する
                    var DotList:Vector.<DynamicDot> = db.m_DotList;
                    var DotNum:int = DotList.length;
                    for(j = 0; j < DotNum; ++j){
                        var dd:DynamicDot = DotList[j];

                        var DotX:int = BaseX + dd.m_RelX;
                        var DotY:int = BaseY + dd.m_RelY;

                        if(in_X == DotX && in_Y == DotY){
                            //背景色の逆が球の色
                            Flags = 1 - (BgColorFlag & 1);
                            Flags |= dd.m_Flags;
                            //ブロックVSボールの場合、ボールは全方向への当たり判定を持つことにする
                            //- 地形→ブロックの渡り中のブロックの離脱を阻止するため
                            //- ボール自体に持たせると、今度はボールとゲートで問題が発生する
                            Flags |= DynamicDot.FLAG_U | DynamicDot.FLAG_D | DynamicDot.FLAG_L | DynamicDot.FLAG_R;
                            m_HitNextVX = db.m_VX;
                            m_HitNextVY = db.m_VY;
                            break;
                        }
                    }
                }
            }

            return Flags;
        }

        //Update : Draw
        public function Update_Draw():void{
            var i:int, j:int;

            //タイトルが表示されるまでは黒くしておく
            if(m_TopPopup != null && !(m_TopPopup is Popup_StageNameFade)){
                m_Context3D.clear(0,0,0,1, DEPTH_BLACK);
                m_Context3D.present();
                return;
            }

            //物理移動を描画座標に反映
            for(i = 0; i < DYNAMIC_OBJ_NUM_MAX; ++i)
            {
                if(m_PhysList[i] == null){
                    break;
                }

                m_PhysList[i].RefreshGraphicPosition();
            }

            //Alias
            var map_num_x:int = GetMapNumX();
            var map_num_y:int = GetMapNumY();
            var total_w:Number = GetTotalW();
            var total_h:Number = GetTotalH();
            var ball:Ball = m_PhysList[0] as Ball;
            var ball_x:int = ball.x - PANEL_W/2 + 2;
            var ball_y:int = ball.y - PANEL_W/2 + 2;

            var global_scl:Number;
            {
/*
                global_scl = 1;//!!
//*/
/*
                var ori_w:Number = map_num_x * PANEL_W;
                var ori_h:Number = map_num_y * PANEL_W;

                var scl_x:Number = total_w / ori_w;
                var scl_y:Number = total_h / ori_h;

                global_scl = Math.min(scl_x, scl_y);
//*/
//*
                //スケーリング後のブロックの大きさを整数倍に収める
                var scl_x:Number = 1.0 * int(total_w / map_num_x) / PANEL_W;
                var scl_y:Number = 1.0 * int(total_h / map_num_y) / PANEL_W;

                global_scl = Math.min(scl_x, scl_y);
//*/
            }

            //重力の矢印表示
            if(m_Sprite_Gravity != null)
            {
                var grav_gap_x:Number = mouseX - total_w/2;
                var grav_gap_y:Number = mouseY - total_h/2;
                var grav_gap_len:Number = Math.sqrt(grav_gap_x*grav_gap_x + grav_gap_y*grav_gap_y);

                if(1 < grav_gap_len){
                    m_Sprite_Gravity.rotation = Math.atan2(grav_gap_y, grav_gap_x) * 180/Math.PI;
                    m_Sprite_Gravity.scaleX = m_Sprite_Gravity.scaleY = grav_gap_len / 64;
                    m_Sprite_Gravity.visible = true;
                }else{
                    //短すぎるので非表示にしておく
                    m_Sprite_Gravity.visible = false;
                }
            }

            //==Stage3Dによるドット絵表示のための処理==
            //まず、画面全体に表示する場合、Rectで表現するとVerticesは(-1, 1, 2, -2)、実際の表示は(0, 0, total_w, total_h)(ピクセル)になる
            //今回はVerticesを(0, 0, 1, -1)を使いまわすことにしており、このままだと表示は(total_w/2, total_h/2, total_w/2, total_h/2)になる
            //というわけで、実際の表示は以下の流れになる
            //
            //#マップの場合
            //1:実際の表示を2Dでの表示に合わせる
            // ・つまり、表示結果が(0, 0, PANEL_W * MAP_NUM_MAX_X, PANEL_W * MAP_NUM_MAX_Y)になるようにする
            // ・この場合、Verticesは(-1,1, 2 * (PANEL_W * MAP_NUM_MAX_X)/total_w, -2 * (PANEL_W * MAP_NUM_MAX_Y)/total_h)になる
            // ・ということで、最初のVertices(0,0,1,-1)にScl(2 * (PANEL_W * MAP_NUM_MAX_X)/total_w, 2 * (PANEL_W * MAP_NUM_MAX_Y)/total_h, 1), Trans(-1,+1,0)を行う
            //2:センタリングを行う
            // ・この段階での表示は(0, 0, PANEL_W * MAP_NUM_MAX_X, PANEL_W * MAP_NUM_MAX_Y)となっているはず
            // ・これをセンタリングすると(gap_x/2, gap_y/2, PANEL_W * MAP_NUM_MAX_X, PANEL_W * MAP_NUM_MAX_Y)になれば良い
            //  ・gap_x = total_w - PANEL_W * map_num_x、gap_y = total_h - PANEL_W * map_num_y
            // ・VerticesのTransは(gap_x/2 * 2/total_w, gap_y/2 * -2/total_h, 0)
            // ・つまりTrans(1 - PANEL_W * map_num_x / total_w, -1 + PANEL_W * map_num_y / total_h, 0)
            //3:実際の画面幅に合うようにスケーリング
            // ・いまの実際に使ってるマップ部分のサイズは(PANEL_W * map_num_x, PANEL_W * map_num_y)
            // ・画面のサイズは(total_w, total_h)
            // ・なので(total_w / (PANEL_W * map_num_x), total_h / (PANEL_W * map_num_y))のうち小さい方に合わせてスケーリングする
            //
            //#オブジェクトの場合
            //1:実際の表示を2Dでの表示に合わせる
            // ・基本的には表示結果が(x, y, PANEL_W, PANEL_W)になるようにする
            //  ・ボールだけは(x, y, 12, 12)になるようにする
            // ・Verticesは(-1 + x * 2/total_w, 1 - y * 2/total_h, 2 * PANEL_W / total_w, -2 * PANEL_W / total_h)になる
            //  ・ボールは(-1 + x * 2/total_w, 1 - y * 2/total_h, 2 * 12 / total_w, -2 * 12 / total_h)
            // ・つまりScl(PANEL_W / total_w, PANEL_W / total_w, 1), Trans(-1 + x * 2/total_w,+1 - y * 2/total_h,0)
            //  ・ボールはScl(12 / total_w, 12 / total_w, 1), Trans(-1 + x * 2/total_w,+1 - y * 2/total_h,0)
            //2:センタリングを行う
            // ・マップの時と同じだけ移動させる
            //3:実際の画面幅に合うようにスケーリング
            // ・これもマップと同じ

            //

            const epsilon:Number = 0.1;//ラスタライズ用微小オフセット(ドットズレを防ぐ)
            //0.375, 0.375/2

            //背景:黒
            {
                //Clearをかねつつ黒色でリセット
                m_Context3D.clear(COLOR_BLACK_RATIO,COLOR_BLACK_RATIO,COLOR_BLACK_RATIO,1, DEPTH_BLACK);
            }

            //地形:白
            var bmd_map_w:Number = m_BitmapData_Map.width;
            var bmd_map_h:Number = m_BitmapData_Map.height;
            {
                //ブレンドはしない(ピクセルシェーダでαが0なら描画をスキップする)
                m_Context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO);

                //テクスチャの設定
                m_Context3D.setTextureAt(0, m_Texture_Map);

                //va0 : 座標:Float×3
                m_Context3D.setVertexBufferAt(0, m_Vertices_White, 0, Context3DVertexBufferFormat.FLOAT_3);
                //va1 : UV:Float×2
                m_Context3D.setVertexBufferAt(1, m_Vertices_White, 3, Context3DVertexBufferFormat.FLOAT_2);

                //Vertex Param
                //- 初期化
                m_Matrix3D.identity();
                //- 表示を2Dに合わせる
                m_Matrix3D.appendScale(2 * (PANEL_W * MAP_NUM_MAX_X)/total_w, 2 * (PANEL_W * MAP_NUM_MAX_Y)/total_h, 1);
                m_Matrix3D.appendTranslation(-1, +1, 0);
                //- センタリング
                m_Matrix3D.appendTranslation(1 - (PANEL_W * map_num_x + epsilon) / total_w, -1 + (PANEL_W * map_num_y + epsilon) / total_h, 0);
                //- 最終的なスケーリング調整
                m_Matrix3D.appendScale(global_scl, global_scl, 1);
                //- セット
                //-- 転置しないと正常に動作しないので注意
                m_Context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m_Matrix3D, true);

                //Fragment Param
                const alpha_threshold:Number = 1.0 * 0x01/0xFF;
                var goal_alpha:Number = 1 - m_GoalFadeTimer / GOAL_FADE_TIME;//今のうちに一緒にセットしておく
                const frag_param:Vector.<Number> = new <Number>[
                    alpha_threshold,
                    goal_alpha,
                    0,
                    0,
                ];
                m_Context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, frag_param);

                //常時表示
                m_Context3D.setDepthTest(true, Context3DCompareMode.ALWAYS);

                //地形だけ少し特殊なシェーダ
                m_Context3D.setProgram(m_ProgramPair_BG);

                //描画
                m_Context3D.drawTriangles(m_Indices);

                //以降は普通のシェーダ
                m_Context3D.setProgram(m_ProgramPair);
            }

            //連結ブロック
            {
                //ブレンドはしない(透明部分は不使用)
                //- さっきと同じなので省略
                //m_Context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO);

                //
                var map_base_x:Number = -bmd_map_w/(total_w/2);
                var map_base_y:Number =  bmd_map_h/(total_h/2);

                for(i = 1; i < DYNAMIC_OBJ_NUM_MAX; ++i)
                {
                    var db:DynamicBody = m_PhysList[i];

                    if(db == null){
                        break;
                    }

                    var block:Block = db as Block;

                    var vertices_block:VertexBuffer3D;
                    if((block.m_ColorFlag & DynamicDot.FLAG_BLACK) == DynamicDot.FLAG_BLACK){
                        m_Context3D.setTextureAt(0, m_Texture_Block_Black);
                        vertices_block = m_Vertices_Black;
                    }else{
                        m_Context3D.setTextureAt(0, m_Texture_Block_White);
                        vertices_block = m_Vertices_White;
                    }

                    //va0 : 座標:Float×3
                    m_Context3D.setVertexBufferAt(0, vertices_block, 0, Context3DVertexBufferFormat.FLOAT_3);
                    //va1 : UV:Float×2
                    m_Context3D.setVertexBufferAt(1, vertices_block, 3, Context3DVertexBufferFormat.FLOAT_2);

                    var panel_arr:Vector.<Vector.<int> > = block.m_Panel;
                    var panel_num:int = panel_arr.length;
                    for(j = 0; j < panel_num; ++j){
                        var offset_x:int = panel_arr[j][0];
                        var offset_y:int = panel_arr[j][1];

                        var block_lx:Number = db.x + offset_x;
                        var block_uy:Number = db.y + offset_y;

                        //Vertex Param
                        //- 初期化
                        m_Matrix3D.identity();
                        //- 表示を2Dに合わせる
                        m_Matrix3D.appendScale(2 * PANEL_W/total_w, 2 * PANEL_W/total_h, 1);
                        m_Matrix3D.appendTranslation(-1 + block_lx * 2/total_w, +1 - block_uy * 2/total_h, 0);
                        //- センタリング
                        m_Matrix3D.appendTranslation(1 - (PANEL_W * map_num_x + epsilon) / total_w, -1 + (PANEL_W * map_num_y + epsilon) / total_h, 0);
                        //- 最終的なスケーリング調整
                        m_Matrix3D.appendScale(global_scl, global_scl, 1);
                        //- セット
                        //-- 転置しないと正常に動作しないので注意
                        m_Context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m_Matrix3D, true);

                        //常時表示
                        m_Context3D.setDepthTest(true, Context3DCompareMode.ALWAYS);

                        //描画
                        m_Context3D.drawTriangles(m_Indices);
                    }
                }
            }

            //ゴール描画
            {
                //ブレンドを行う
                m_Context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);

                var goal_x:int = m_Goal.m_X - PANEL_W/2;
                var goal_y:int = m_Goal.m_Y - PANEL_W/2;

                //var ratio_alpha:Number = 1 - m_GoalFadeTimer / GOAL_FADE_TIME;
                var ratio_scl:Number = Util.Lerp(1, GOAL_SCL_MAX, m_GoalFadeTimer / GOAL_FADE_TIME);
                var rot:Number = 1*360 * m_GoalFadeTimer;

                //va0 : 座標:Float×3
                m_Context3D.setVertexBufferAt(0, m_Vertices_Ball, 0, Context3DVertexBufferFormat.FLOAT_3);
                //va1 : UV:Float×2
                m_Context3D.setVertexBufferAt(1, m_Vertices_Ball, 3, Context3DVertexBufferFormat.FLOAT_2);
                //→深度更新はしないので、適当にボールのを使いまわす

                //Vertex Param
                //- 初期化
                m_Matrix3D.identity();
                //- 表示を2Dに合わせる
                m_Matrix3D.appendScale(2 * PANEL_W/total_w, 2 * PANEL_W/total_h, 1);
                m_Matrix3D.appendTranslation(-1 + goal_x * 2/total_w, +1 - goal_y * 2/total_h, 0);
                //- センタリング
                m_Matrix3D.appendTranslation(1 - PANEL_W * map_num_x / total_w, -1 + PANEL_W * map_num_y / total_h, 0);
                //- 最終的なスケーリング調整
                m_Matrix3D.appendScale(global_scl, global_scl, 1);
                //- ゴール演出
                m_Matrix3D.prependTranslation(+0.5,-0.5, 0);
                m_Matrix3D.prependRotation(rot, Vector3D.Z_AXIS);
                m_Matrix3D.prependScale(ratio_scl, ratio_scl, 1);
                m_Matrix3D.prependTranslation(-0.5,+0.5, 0);
                //- セット
                //-- 転置しないと正常に動作しないので注意
                m_Context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m_Matrix3D, true);


                //テクスチャの設定
                if(m_Goal.m_IsWhite){
                    m_Context3D.setTextureAt(0, m_Texture_Goal_White);
                }else{
                    m_Context3D.setTextureAt(0, m_Texture_Goal_Black);
                }

                //深度無視表示
                //- 深度チェックはせず、深度更新もしない
                m_Context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);

                //ゴールも少し特殊なシェーダにすることにした
                m_Context3D.setProgram(m_ProgramPair_Goal);

                //描画
                m_Context3D.drawTriangles(m_Indices);

                //以降は普通のシェーダ
                m_Context3D.setProgram(m_ProgramPair);
            }

            //ボール
            {
                const ball_w:int = 12;

                //ブレンドを行う
                m_Context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);

                //va0 : 座標:Float×3
                m_Context3D.setVertexBufferAt(0, m_Vertices_Ball, 0, Context3DVertexBufferFormat.FLOAT_3);
                //va1 : UV:Float×2
                m_Context3D.setVertexBufferAt(1, m_Vertices_Ball, 3, Context3DVertexBufferFormat.FLOAT_2);

                //Vertex Param
                //- 初期化
                m_Matrix3D.identity();
                //- 表示を2Dに合わせる
                m_Matrix3D.appendScale(2 * ball_w/total_w, 2 * ball_w/total_h, 1);
                m_Matrix3D.appendTranslation(-1 + ball_x * 2/total_w, +1 - ball_y * 2/total_h, 0);
                //- センタリング
                m_Matrix3D.appendTranslation(1 - PANEL_W * map_num_x / total_w, -1 + PANEL_W * map_num_y / total_h, 0);
                //- 最終的なスケーリング調整
                m_Matrix3D.appendScale(global_scl, global_scl, 1);
                //- セット
                //-- 転置しないと正常に動作しないので注意
                m_Context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m_Matrix3D, true);


                //White
                {
                    //テクスチャの設定
                    m_Context3D.setTextureAt(0, m_Texture_Ball_White);

                    //逆深度表示
                    m_Context3D.setDepthTest(true, Context3DCompareMode.GREATER);//GREATER

                    //描画
                    m_Context3D.drawTriangles(m_Indices);
                }
                //Black
                {
                    //テクスチャの設定
                    m_Context3D.setTextureAt(0, m_Texture_Ball_Black);

                    //通常表示
                    m_Context3D.setDepthTest(true, Context3DCompareMode.LESS);//LESS

                    //描画
                    m_Context3D.drawTriangles(m_Indices);
                }
            }

            //ゲート
            {
                //テクスチャの設定
                m_Context3D.setTextureAt(0, m_Texture_Gate);

                //常時表示
                //- 一応、深度情報の更新はオフ(現状では特に意味がないが)
                m_Context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);

                for(i = 0; i < GATE_NUM_MAX; ++i){
                    var gate:Gate = m_Gate[i];

                    if(gate == null){
                        break;
                    }

                    var gate_x:int = gate.m_X - PANEL_W/2;
                    var gate_y:int = gate.m_Y - PANEL_W/2;
                    var gate_angle:int = gate.m_Angle;

                    //Vertex Param
                    //- 初期化
                    m_Matrix3D.identity();
                    //- Rotation
                    m_Matrix3D.appendTranslation(-0.5, +0.5, 0);
                    m_Matrix3D.appendRotation(gate_angle, Vector3D.Z_AXIS);
                    m_Matrix3D.appendTranslation(+0.5, -0.5, 0);
                    //- 表示を2Dに合わせる
                    m_Matrix3D.appendScale(2 * PANEL_W/total_w, 2 * PANEL_W/total_h, 1);
                    m_Matrix3D.appendTranslation(-1 + gate_x * 2/total_w, +1 - gate_y * 2/total_h, 0);
                    //- センタリング
                    m_Matrix3D.appendTranslation(1 - PANEL_W * map_num_x / total_w, -1 + PANEL_W * map_num_y / total_h, 0);
                    //- 最終的なスケーリング調整
                    m_Matrix3D.appendScale(global_scl, global_scl, 1);
                    //- セット
                    //-- 転置しないと正常に動作しないので注意
                    m_Context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m_Matrix3D, true);

                    //描画
                    m_Context3D.drawTriangles(m_Indices);
                }
            }


            //反映
            m_Context3D.present();
        }

        //ゴールに触れたか
        public function Check_Goal():void{
            var ball:Ball = m_PhysList[0] as Ball;

            var GapX:Number = ball.m_X - m_Goal.m_X;
            var GapY:Number = ball.m_Y - m_Goal.m_Y;

            var Distance:Number = Math.sqrt(GapX*GapX + GapY*GapY);

            if(Distance < Ball.PHYS_RAD){
                m_ClearFlag = true;
                m_GoalFadeTimer = 0;

/*
                //セーブデータ更新
                var is_first_all_clear:Boolean;
                {
                    var is_all_clear_old:Boolean = IsAllClear();

                    SetClear(m_MapIndex);

                    var is_all_clear_new:Boolean = IsAllClear();

                    is_first_all_clear = (!is_all_clear_old && is_all_clear_new);
                }

                if(! is_first_all_clear){
                    //普通のクリアリザルト
                    var is_clear:Boolean = true;
                    PushPopup(new Popup_Menu(is_clear));
                }else{
                    //コングラッチュレーション
                    PushPopup(new Popup_Congratulation());
                }
//*/
            }
        }


        //=重力=

        //重力取得
        public function GetGravity():Vector3D{
            if(m_Accel){
                //加速度センサーを使う
                //→ハンドラで更新されてるはず
            }else{
                //マウスを使う

                const GAP_MIN:Number = 0;//PANEL_W/2;
                const GAP_MAX:Number = VIEW_W/3;//PANEL_W*1.5;

                //マウスの画面中央からの差を求める
                m_Gravity.x = mouseX - GetTotalW()/2;
                m_Gravity.y = mouseY - GetTotalH()/2;

                //長さを制御して、0~1に収める
                var GapLen:Number = m_Gravity.length;
                if(GapLen < GAP_MIN){
                    m_Gravity.x = m_Gravity.y = 0;
                }else{
                    m_Gravity.x /= GapLen;
                    m_Gravity.y /= GapLen;

                    if(GapLen < GAP_MAX){
                        m_Gravity.x *= (GapLen - GAP_MIN) / (GAP_MAX - GAP_MIN);
                        m_Gravity.y *= (GapLen - GAP_MIN) / (GAP_MAX - GAP_MIN);
                    }
                }

                //最大値がMOVE_POWになるようにする
                m_Gravity.x *= MOVE_POW;
                m_Gravity.y *= MOVE_POW;
            }

            return m_Gravity;
        }

        //Accelometorからの重力受け取り
        public function SetGravity_Listener(e:AccelerometerEvent):void{
            m_Gravity.x = MOVE_POW * -e.accelerationX;
            m_Gravity.y = MOVE_POW *  e.accelerationY;
        }


        //=Navigation=
        //- Recommend
        static public function Navigate_Recommend():void{
            navigateToURL(new URLRequest(
                "https://play.google.com/store/apps/details?id=air.showohealer.game.monochromaze"
            ));
        }
        //- Other Works
        static public function Navigate_OtherWorks():void{
            navigateToURL(new URLRequest(
                "https://play.google.com/store/apps/developer?id=o_healer"
            ));
        }
        //- Twitter
        static public function Navigate_Twitter():void{
            navigateToURL(new URLRequest(
                "http://twitter.com/share?" +
                "text=" + escapeMultiByte(" #白黒迷図") +
                "&url=" + escapeMultiByte("http://wonderfl.net/c/u3IG")
            ));
        }

        //=SaveData=

        //Base
        static public var s_SharedObject:SharedObject = null;
        static public function GetSharedObject():SharedObject{
            if(s_SharedObject == null){
                s_SharedObject = SharedObject.getLocal("MonochromeMaze");
            }
            return s_SharedObject;
        }
        static public function GetClearInfo():Array{
            var so:SharedObject = GetSharedObject();

            var i:int;

            var arr:Array = so.data.clear_info;
            if(arr == null){
                //まだ作られていなかったらフラグを全てオフにして作成
                arr = new Array(MAP.length);
                for(i = 0; i < MAP.length; ++i){
                    arr[i] = false;
                }
                so.data.clear_info = arr;
            }else{
                if(arr.length != MAP.length){
                    //前回よりステージ数が増えているようなら、追加されたぶんはフラグをオフにして追加
                    var new_arr:Array = new Array(MAP.length);
                    for(i = 0; i < MAP.length; ++i){
                        if(i < arr.length){
                            new_arr[i] = arr[i];
                        }else{
                            new_arr[i] = false;
                        }
                    }
                    arr = new_arr;
                    so.data.clear_info = arr;
                }
            }

            return arr;
        }

        // Get
        static public function IsClear(in_StageIndex:int):Boolean{
            var arr:Array = GetClearInfo();
            return arr[in_StageIndex];
        }
        static public function IsAllClear():Boolean{
            var flag:Boolean = true;
            {
                var arr:Array = GetClearInfo();
                for(var i:int = 0; i < arr.length; ++i){
                    if(! arr[i]){flag = false; break;}
                }
            }
            return flag;
        }
        static public function GetClearNum():int{
            var result:int = 0;

            var arr:Array = GetClearInfo();
            var num:int = arr.length;
            for(var i:int = 0; i < num; ++i){
                if(arr[i]){
                    ++result;
                }
            }
            return result;
        }

        //Set
        static public function SetClear(in_StageIndex:int):void{
            var arr:Array = GetClearInfo();
            arr[in_StageIndex] = true;

            var so:SharedObject = GetSharedObject();
            so.data.clear_info = arr;

            so.flush();
        }

        //=Util=

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

        private function roundUpPower2(x:int):int{
            x = x - 1;
            x = x | (x >> 1);
            x = x | (x >> 2);
            x = x | (x >> 4);
            x = x | (x >> 8);
            x = x | (x >>16);
            return x + 1;
        }
    }
}


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

//移動管理用
class MoveInfo
{
    public var IntSrcX:int;
    public var IntSrcY:int;
    public var IntDstX:int;
    public var IntDstY:int;
    public var IterX:int;
    public var IterY:int;
    public var AddX:int;
    public var AddY:int;

    public var DstX:Number;
    public var DstY:Number;
}

//コリジョンドット
class DynamicDot
{
    //==Const==

    //白の判定
    static public const FLAG_WHITE:int = 0;
    //黒の判定
    static public const FLAG_BLACK:int = 1;

    //ゲートフラグ
    static public const FLAG_GATE:int = (1 << 1);

    //上から来る相手にのみヒットする
    static public const FLAG_U:int = (1 << 2);
    //下から来る相手にのみヒットする
    static public const FLAG_D:int = (1 << 3);
    //左から来る相手にのみヒットする
    static public const FLAG_L:int = (1 << 4);
    //右から来る相手にのみヒットする
    static public const FLAG_R:int = (1 << 5);

    //地形にはヒットしないフラグ
    //- 外枠は地形に埋まる可能性があり、そうすると抜け出せなくなるので外枠に使う
    static public const FLAG_NOHIT_TERRAIN:int = (1 << 6);

    //ボールか否かを判断する必要が出てきたのでそのフラグ
    static public const FLAG_BALL:int = (1 << 7);

    //地形も同様
    static public const FLAG_TERRAIN:int = (1 << 8);


    //==Var==

    //Bodyに対する相対座標
    public var m_RelX:int = 0;
    public var m_RelY:int = 0;

    //Flags
    public var m_Flags:int = 0;


    //==Function==

    //Init
    public function DynamicDot(in_RelX:int, in_RelY:int, in_ColorFlag:int)
    {
        m_RelX = in_RelX;
        m_RelY = in_RelY;

        m_Flags = in_ColorFlag;
    }
}

//物理OBJ(ボールやブロックなどの移動OBJの基底クラス)
class DynamicBody extends Sprite
{
    //==Const==

    //ヒットSE用
    static public const AXIS_X:int = (1 << 0);
    static public const AXIS_Y:int = (1 << 1);


    //==Var==

    //#Coord

    //位置
    public var m_X:Number = 0;
    public var m_Y:Number = 0;

    //速度
    public var m_VX:Number = 0;
    public var m_VY:Number = 0;

    //#Collision

    //構成要素
    public var m_DotList:Vector.<DynamicDot> = new Vector.<DynamicDot>();

    //構成要素の範囲
    public var m_RelAABB_MinX:int = 0;
    public var m_RelAABB_MaxX:int = 0;
    public var m_RelAABB_MinY:int = 0;
    public var m_RelAABB_MaxY:int = 0;

    //ヒットSE用
    public var m_MoveState:int = 0;
    public var m_HitState:int = 0;
    public var m_HitColorX:int = 0;
    public var m_HitColorY:int = 0;


    //==Function==

    //Init
    public function Init_Common(in_Game:Monochroll_Wonderfl, in_X:int, in_Y:int):void{
        m_X = in_X;
        m_Y = in_Y;
        RefreshGraphicPosition();
    }

    //Finish
    virtual public function Finish():void{
        if(parent != null)
        {
            parent.removeChild(this);
        }
    }

    //PhysPos => Graphic Pos
    virtual public function RefreshGraphicPosition():void{
        this.x = Util.FloorInt(m_X);
        this.y = Util.FloorInt(m_Y);
    }
}

//ボール
class Ball extends DynamicBody
{
    //==Const==

    //
    static public const PHYS_DIAMETER:int = Monochroll_Wonderfl.PANEL_W - 3;
    static public const PHYS_RAD:int = (PHYS_DIAMETER - 1) / 2;


    //==Var==

    //ボール画像
    public var m_BitmapData_White:BitmapData = new BitmapData(64, 64, true, 0x00000000);
    public var m_BitmapData_Black:BitmapData = new BitmapData(64, 64, true, 0x00000000);
    public var m_Bitmap_White:Bitmap = new Bitmap(m_BitmapData_White);
    public var m_Bitmap_Black:Bitmap = new Bitmap(m_BitmapData_Black);


    //==Function==

    //Init
    public function Init(in_Game:Monochroll_Wonderfl, in_X:int, in_Y:int, in_ColorFlag:int):void{
        //Super
        {
            Init_Common(in_Game, in_X, in_Y);
        }

        //コリジョン
        {
            //当たり判定(m_DotList)
            {
                var BaseFlag:int = DynamicDot.FLAG_BALL;
                //- 色は今居る場所のの反対を使うようにしたので、ドット自体は保持不要

                //上下左右用の当たり判定をDIAMETERの数だけ作成する
                m_DotList = new Vector.<DynamicDot>(4 * PHYS_DIAMETER);

                //まずは上用の判定を作成
                {//[0*RAD]~[1*RAD - 1]
                    var CenterX:Number = PHYS_DIAMETER * 0.5;
                    var CenterY:Number = PHYS_DIAMETER * 0.5;

                    var Rad:Number = PHYS_DIAMETER * 0.5;

                    var OffsetX:int = -(PHYS_DIAMETER-1)/2;
                    var OffsetY:int = -(PHYS_DIAMETER-1)/2;

                    //一つのxにつき一点だけ作成
                    for(var x_:int = 0; x_ < PHYS_DIAMETER; ++x_){
                        var TrgX:Number = x_ + 0.5;

                        //範囲内のうち、一番上のものを採用する
                        for(var y_:int = 0; y_ < PHYS_DIAMETER; ++y_){
                            var TrgY:Number = y_ + 0.5;

                            var GapX:Number = TrgX - CenterX;
                            var GapY:Number = TrgY - CenterY;
                            var Distance:Number = Math.sqrt(GapX*GapX + GapY*GapY);

                            if(Distance < Rad){
                                m_DotList[x_] = new DynamicDot(x_ + OffsetX, y_ + OffsetY, BaseFlag | DynamicDot.FLAG_U);
                                break;
                            }
                        }

                        //求まらないことはないはずだが、気になる場合は以下でチェック
                        //if(m_DotList[x] == null){err}
                    }
                }

                //それを各方向にコピーする
                //- ヒット方向だけ変わる
                {
                    for(var i:int = 0; i < PHYS_DIAMETER; ++i){
                        var d:DynamicDot = m_DotList[i];
                        m_DotList[i + 1*PHYS_DIAMETER] = new DynamicDot( d.m_RelX, -d.m_RelY, BaseFlag | DynamicDot.FLAG_D);
                        m_DotList[i + 2*PHYS_DIAMETER] = new DynamicDot( d.m_RelY,  d.m_RelX, BaseFlag | DynamicDot.FLAG_L);
                        m_DotList[i + 3*PHYS_DIAMETER] = new DynamicDot(-d.m_RelY,  d.m_RelX, BaseFlag | DynamicDot.FLAG_R);
                    }
                }
            }

            //AABB
            {
                m_RelAABB_MinX = -(PHYS_DIAMETER+1)/2;
                m_RelAABB_MaxX =  (PHYS_DIAMETER+1)/2;
                m_RelAABB_MinY = -(PHYS_DIAMETER+1)/2;
                m_RelAABB_MaxY =  (PHYS_DIAMETER+1)/2;
            }
        }

        //
        {
            RefreshGraphicPosition();
        }
    }

    //PhysPos => Graphic Pos
    override public function RefreshGraphicPosition():void{
        this.x = Round(m_X);
        this.y = Round(m_Y);

        m_Bitmap_White.x = m_Bitmap_Black.x = this.x - Monochroll_Wonderfl.PANEL_W/2;
        m_Bitmap_White.y = m_Bitmap_Black.y = this.y - Monochroll_Wonderfl.PANEL_W/2;
    }
    static public function Round(val:Number):int{
        return int(val + 0.5);
    }
}

//ブロック(移動)
class Block extends DynamicBody
{
    //==Const==

    //隣接パネルの方向
    static public const FLAG_CONNECT_U:int = (1 << 0);
    static public const FLAG_CONNECT_D:int = (1 << 1);
    static public const FLAG_CONNECT_L:int = (1 << 2);
    static public const FLAG_CONNECT_R:int = (1 << 3);

    //==Var==

    public var m_ColorFlag:int = 0;
    public var m_Panel:Vector.<Vector.<int> >;


    //==Function==

    //Init
    public function Init(in_Game:Monochroll_Wonderfl, in_BaseColorFlag:int, in_PanelInfo:Vector.<Vector.<int> >, in_PanelNum:int):void
    {
        //Super
        {
            Init_Common(in_Game, 0, 0);
        }

        //Init
        {
            m_ColorFlag = in_BaseColorFlag;
            m_Panel = new Vector.<Vector.<int> >(in_PanelNum);
        }

        //コリジョン
        {
            CreateCollision(in_Game, in_BaseColorFlag, in_PanelInfo, in_PanelNum);
        }
    }

    //PhysPos => Graphic Pos
    override public function RefreshGraphicPosition():void{
//        this.x = Round(m_X);
//        this.y = Round(m_Y);
        this.x = Util.FloorInt(m_X);
        this.y = Util.FloorInt(m_Y);
    }
    static public function Round(val:Number):int{
        return int(val - 0.5);
    }

    //Init  : Collision
    public function CreateCollision(in_Game:Monochroll_Wonderfl, in_BaseColorFlag:int, in_PanelInfo:Vector.<Vector.<int> >, in_PanelNum:int):void{
        var PanelNum:int = in_PanelNum;

        var dd:DynamicDot;

        //AABB : Reset
        {
            m_RelAABB_MinX = 99999999;
            m_RelAABB_MaxX = 0;
            m_RelAABB_MinY = 99999999;
            m_RelAABB_MaxY = 0;
        }

        //当たり判定(m_DotList)
        {
            //パネルの数だけ「外枠ドット」と「内枠ドット」を用意
            //- 枠ドットは4辺の長さと同じ数
            m_DotList = new Vector.<DynamicDot>(PanelNum * 4*Monochroll_Wonderfl.PANEL_W * 2);
            //m_DotList = new DynamicDot[PanelNum * 4*Monochroll_Wonderfl.PANEL_W];//Outerはドットではなく相対座標から求めることにしたので不要

            var BaseFlag_Inner:int;
            var BaseFlag_Outer:int;
            {
                if(in_BaseColorFlag == DynamicDot.FLAG_WHITE){
                    BaseFlag_Inner = DynamicDot.FLAG_WHITE;
                    BaseFlag_Outer = DynamicDot.FLAG_BLACK | DynamicDot.FLAG_NOHIT_TERRAIN;
                }else{
                    BaseFlag_Inner = DynamicDot.FLAG_BLACK;
                    BaseFlag_Outer = DynamicDot.FLAG_WHITE | DynamicDot.FLAG_NOHIT_TERRAIN;
                }
            }

            for(var i:int = 0; i < PanelNum; ++i){
                var panel_info:Vector.<int> = in_PanelInfo[i];
                var BaseRelX:int = panel_info[0];
                var BaseRelY:int = panel_info[1];
                var Flags:int    = panel_info[2];

                var BaseIndex:int = i*Monochroll_Wonderfl.PANEL_W*8;

                var UseU:Boolean = true;
                var UseD:Boolean = true;
                var UseL:Boolean = true;
                var UseR:Boolean = true;
                for(var ii:int = 0; ii < PanelNum; ++ii){
                    if(i == ii){continue;}

                    var panel_info_another:Vector.<int> = in_PanelInfo[ii];
                    var AnotherRelX:int = panel_info_another[0];
                    var AnotherRelY:int = panel_info_another[1];
                    if(AnotherRelX == BaseRelX-1){UseL = false;}
                    if(AnotherRelX == BaseRelX+1){UseR = false;}
                    if(AnotherRelY == BaseRelY-1){UseU = false;}
                    if(AnotherRelY == BaseRelY+1){UseD = false;}
                }

                for(var j:int = 0; j < Monochroll_Wonderfl.PANEL_W; ++j){
                    var AddIndex:int = j*8;

                    //Inner
                    {
                        //U
                        if(UseU){
                            dd = new DynamicDot(
                                BaseRelX + j,                BaseRelY,                    ((Flags & FLAG_CONNECT_U) != 0)? BaseFlag_Inner: (BaseFlag_Inner | DynamicDot.FLAG_U)
                            );
                        }else{
                            dd = null;
                        }
                        m_DotList[BaseIndex + AddIndex + 0] = dd;
                        //D
                        if(UseD){
                            dd = new DynamicDot(
                                BaseRelX + j,                BaseRelY+Monochroll_Wonderfl.PANEL_W-1,    ((Flags & FLAG_CONNECT_D) != 0)? BaseFlag_Inner: (BaseFlag_Inner | DynamicDot.FLAG_D)
                            );
                        }else{
                            dd = null;
                        }
                        m_DotList[BaseIndex + AddIndex + 1] = dd;
                        //L
                        if(UseL){
                            dd = new DynamicDot(
                                BaseRelX,                    BaseRelY+j,                    ((Flags & FLAG_CONNECT_L) != 0)? BaseFlag_Inner: (BaseFlag_Inner | DynamicDot.FLAG_L)
                            );
                        }else{
                            dd = null;
                        }
                        m_DotList[BaseIndex + AddIndex + 2] = dd;
                        //R
                        if(UseR){
                            dd = new DynamicDot(
                                BaseRelX+Monochroll_Wonderfl.PANEL_W-1,    BaseRelY+j,                    ((Flags & FLAG_CONNECT_R) != 0)? BaseFlag_Inner: (BaseFlag_Inner | DynamicDot.FLAG_R)
                            );
                        }else{
                            dd = null;
                        }
                        m_DotList[BaseIndex + AddIndex + 3] = dd;
                    }

                    //Outer
                    {
                        //U
                        if(UseU){
                            dd = new DynamicDot(
                                BaseRelX + j,                BaseRelY-1,                    ((Flags & FLAG_CONNECT_U) != 0)? BaseFlag_Outer: (BaseFlag_Outer | DynamicDot.FLAG_D)
                            );
                        }else{
                            dd = null;
                        }
                        m_DotList[BaseIndex + AddIndex + 4] = dd;
                        //D
                        if(UseD){
                            dd = new DynamicDot(
                                BaseRelX + j,                BaseRelY+Monochroll_Wonderfl.PANEL_W,        ((Flags & FLAG_CONNECT_D) != 0)? BaseFlag_Outer: (BaseFlag_Outer | DynamicDot.FLAG_U)
                            );
                        }else{
                            dd = null;
                        }
                        m_DotList[BaseIndex + AddIndex + 5] = dd;
                        //L
                        if(UseL){
                            dd = new DynamicDot(
                                BaseRelX-1,                    BaseRelY+j,                    ((Flags & FLAG_CONNECT_L) != 0)? BaseFlag_Outer: (BaseFlag_Outer | DynamicDot.FLAG_R)
                            );
                        }else{
                            dd = null;
                        }
                        m_DotList[BaseIndex + AddIndex + 6] = dd;
                        //R
                        if(UseR){
                            dd = new DynamicDot(
                                BaseRelX+Monochroll_Wonderfl.PANEL_W,        BaseRelY+j,                    ((Flags & FLAG_CONNECT_R) != 0)? BaseFlag_Outer: (BaseFlag_Outer | DynamicDot.FLAG_L)
                            );
                        }else{
                            dd = null;
                        }
                        m_DotList[BaseIndex + AddIndex + 7] = dd;
                    }
                }

                //Panel
                {
                    m_Panel[i] = new Vector.<int>(3);
                    m_Panel[i][0] = BaseRelX;
                    m_Panel[i][1] = BaseRelY;
                    m_Panel[i][2] = Flags;
                }

                //AABB
                {
                    //外枠相当の処理も行うので、ひとまわり大きくしておく
                    var MinX:int = BaseRelX-2;
                    var MaxX:int = BaseRelX+Monochroll_Wonderfl.PANEL_W+1;
                    var MinY:int = BaseRelY-2;
                    var MaxY:int = BaseRelY+Monochroll_Wonderfl.PANEL_W+1;

                    if(MinX < m_RelAABB_MinX){m_RelAABB_MinX = MinX;}
                    if(m_RelAABB_MaxX < MaxX){m_RelAABB_MaxX = MaxX;}
                    if(MinY < m_RelAABB_MinY){m_RelAABB_MinY = MinY;}
                    if(m_RelAABB_MaxY < MaxY){m_RelAABB_MaxY = MaxY;}
                }
            }
        }
    }
}

class Goal
{
    //=Var=
    public var m_X:int = 0;
    public var m_Y:int = 0;
    public var m_IsWhite:Boolean = true;

    //=Function=
    public function Goal(in_Game:Monochroll_Wonderfl, in_X:int, in_Y:int, in_IsWhite:Boolean)
    {
        m_X = in_X;
        m_Y = in_Y;
        m_IsWhite = in_IsWhite;
    }
}


class Gate
{
    //=Var=
    public var m_X:int = 0;
    public var m_Y:int = 0;
    public var m_Angle:int = 0;

    //=function=
    public function Gate(in_X:int, in_Y:int, in_Angle:int){
        m_X = in_X;
        m_Y = in_Y;
        m_Angle = in_Angle;
    }
}



//Base : Popup
class Popup extends Sprite
{
    //==Static==

    //全てPopするためのフラグ
    static public var s_AllEndFlag:Boolean = false;


    //==Const==

    //プレートの高さ(押しやすいようにする)
    static public const PLATE_H:int = 64;
    //ついでに幅も
    static public const PLATE_W:int = 512;


    //==Var==

    //次のポップアップ
    public var m_NextPopup:Popup = null;

    //Flag
    protected var m_EndFlag:Boolean = false;


    //==Function==

    //Init
    public function Popup(){
        s_AllEndFlag = false;
    }

    //Refresh
    public function Refresh():void{
        //Override
    }

    //Update
    public function Update(in_DeltaTime:Number):void{
        //Override
    }

    //Touch
    public function OnMouseDown():void{
        //Override
    }
    public function OnMouseMove():void{
        //Override
    }
    public function OnMouseUp():void{
        //Override
    }


    //Next Popup
    public function GetNextPopup():Popup{
        return m_NextPopup;
    }
    public function ClearNextPopup():void{
        m_NextPopup = null;
    }

    //On Back
    public function OnBack():void{
        //Override
    }

    //Flag
    public function IsEnd():Boolean{
        return m_EndFlag || s_AllEndFlag;
    }
}


//Popup : Stage Select
class Popup_StageSelect extends Popup
{
    //==Static==

    //毎回生成するのは高コストなので、一度生成したら保持しておく
    //- BG
    static public var s_Bitmap_BG:Bitmap = null;
    //- Label
    static public var s_Sprite_Label:Sprite = null;
    static public var s_BitmapData_Label:BitmapData = null;
    //- Button : L
    static public var s_NinePatch_Button_L:NinePatch = null;
    //- Button : R
    static public var s_NinePatch_Button_R:NinePatch = null;
    //- Button : Bottom
    static public var s_NinePatch_Button_Bottom:NinePatch = null;
    //- SS
    static public var s_Bitmap_SS:Bitmap = null;
    static public var s_BitmapData_SS:BitmapData = null;
    static public var s_Sprite_SS:Sprite = null;

    //
    static public var s_ButtonIter:int = 0;
    static public const BUTTON_L:int        = s_ButtonIter++;
    static public const BUTTON_R:int        = s_ButtonIter++;
    static public const BUTTON_BOTTOM:int    = s_ButtonIter++;
    static public const BUTTON_NUM:int        = s_ButtonIter;


    //==Var==

    //Layer
    public var m_Layer_BG:Sprite = new Sprite();
    public var m_Layer_Content:Sprite = new Sprite();

    //ボタン
    public var m_Button_L:Button = null;
    public var m_Button_R:Button = null;
    public var m_Button_Bottom:Button = null;
    public var m_Graphics_L:Graphics;
    public var m_Graphics_R:Graphics;
    public var m_Bitmap_BottomLabel:Bitmap;
    public var m_ButtonManager:ButtonManager = new ButtonManager();

    //SS用パラメータ
    public var m_MapW:int = 32;
    public var m_MapH:int = 32;

    //Flag
    public var m_RedrawFlag:Boolean = true;


    //==Function==

    //Init
    public function Popup_StageSelect(){
        super();

        var shape:Shape;

        //Layer
        {
            addChild(m_Layer_BG);
            addChild(m_Layer_Content);
        }

        //BG
        {
            if(s_Bitmap_BG == null){
                s_Bitmap_BG = new Bitmap(new BitmapData(1, 1, false, 0x000000));
            }

            m_Layer_BG.addChild(s_Bitmap_BG);
        }

        //Label
        {
            if(s_Sprite_Label == null){
                s_BitmapData_Label = new BitmapData(456, 64, true, 0x00000000);

                var bmp_label:Bitmap = new Bitmap(s_BitmapData_Label);
                bmp_label.x = -bmp_label.width/2;
                bmp_label.y = -bmp_label.height/2;
                bmp_label.smoothing = true;

                s_Sprite_Label = new Sprite();
                s_Sprite_Label.addChild(bmp_label);
            }

            m_Layer_Content.addChild(s_Sprite_Label);
        }

        //Button : L
        {
            if(s_NinePatch_Button_L == null){
                s_NinePatch_Button_L = NinePatch.Create();
            }

            m_Button_L = new Button(s_NinePatch_Button_L);
            m_Layer_Content.addChild(m_Button_L);
            m_ButtonManager.AddButton(m_Button_L);

            shape = new Shape();
            m_Button_L.addChild(shape);
            m_Graphics_L = shape.graphics;
        }

        //Button : R
        {
            if(s_NinePatch_Button_R == null){
                s_NinePatch_Button_R = NinePatch.Create();
            }

            m_Button_R = new Button(s_NinePatch_Button_R);
            m_Layer_Content.addChild(m_Button_R);
            m_ButtonManager.AddButton(m_Button_R);

            shape = new Shape();
            m_Button_R.addChild(shape);
            m_Graphics_R = shape.graphics;
        }

        //Button : Bottom
        {
            if(s_NinePatch_Button_Bottom == null){
                s_NinePatch_Button_Bottom = NinePatch.Create();
            }

            m_Button_Bottom = new Button(s_NinePatch_Button_Bottom);
            m_Layer_Content.addChild(m_Button_Bottom);
            m_ButtonManager.AddButton(m_Button_Bottom);

            m_Bitmap_BottomLabel = new Bitmap();
            m_Button_Bottom.addChild(m_Bitmap_BottomLabel);
        }

        //SS
        {
            if(s_Sprite_SS == null){
                s_BitmapData_SS = new BitmapData(Monochroll_Wonderfl.MAP_NUM_MAX_X, Monochroll_Wonderfl.MAP_NUM_MAX_Y, true, 0x00000000);

                s_Bitmap_SS = new Bitmap(s_BitmapData_SS);
                s_Bitmap_SS.x = -s_Bitmap_SS.width/2;
                s_Bitmap_SS.y = -s_Bitmap_SS.height/2;

                s_Sprite_SS = new Sprite();
                s_Sprite_SS.addChild(s_Bitmap_SS);
            }

            m_Layer_Content.addChild(s_Sprite_SS);
        }

        //位置と画像の初期化
        {
            Redraw();//m_MapWなどの更新を兼ねる
            Resize();
        }
    }

    //Resize
    public function Resize():void{
        var g:Graphics;

        var total_w:int = Monochroll_Wonderfl.Instance.GetTotalW();
        var total_h:int = Monochroll_Wonderfl.Instance.GetTotalH();

        var label_w:int            = total_w;
        var label_h:int            = total_h * 20/100;
        var button_bottom_area_w:int    = total_w;
        var button_bottom_area_h:int    = total_h * 20/100;
        var button_bottom_w:int    = button_bottom_area_w * 0.9;
        var button_bottom_h:int    = button_bottom_area_h * 0.9;
        var button_lr_area_h:int= total_h - label_h - button_bottom_area_h;
        var button_lr_area_w:int= button_bottom_area_h;
        var button_lr_h:int        = button_lr_area_h * 0.9;
        var button_lr_w:int        = button_lr_area_w * 0.9;
        var ss_w:int            = total_w - 2*button_lr_w;
        var ss_h:int            = button_lr_h;

        {//BG
            s_Bitmap_BG.scaleX = total_w;
            s_Bitmap_BG.scaleY = total_h;
        }
        {//Label
            s_Sprite_Label.x = total_w/2;
            s_Sprite_Label.y = label_h/2;
            s_Sprite_Label.scaleX = s_Sprite_Label.scaleY = Math.min(label_w/s_BitmapData_Label.width, label_h/s_BitmapData_Label.height);
        }
        {//ButtonL, ButtonR
            s_NinePatch_Button_L.Resize(button_lr_w, button_lr_h);
            m_Button_L.x = button_lr_area_w/2 - button_lr_w/2;
            m_Button_L.y = label_h + button_lr_area_h/2 - button_lr_h/2;
            g = m_Graphics_L;
            g.clear();
            g.lineStyle(4,0xFFFFFF,1.0);
            g.beginFill(0xFFFFFF, 1.0);
            g.moveTo(button_lr_w*20/100, button_lr_h/2);
            g.lineTo(button_lr_w*80/100, button_lr_h/2 + button_lr_w*60/100);
            g.lineTo(button_lr_w*80/100, button_lr_h/2 - button_lr_w*60/100);
            g.lineTo(button_lr_w*20/100, button_lr_h/2);
            g.endFill();

            s_NinePatch_Button_R.Resize(button_lr_w, button_lr_h);
            m_Button_R.x = total_w - button_lr_area_w/2 - button_lr_w/2;
            m_Button_R.y = label_h + button_lr_area_h/2 - button_lr_h/2;
            g = m_Graphics_R;
            g.clear();
            g.lineStyle(4,0xFFFFFF,1.0);
            g.beginFill(0xFFFFFF, 1.0);
            g.moveTo(button_lr_w*80/100, button_lr_h/2);
            g.lineTo(button_lr_w*20/100, button_lr_h/2 + button_lr_w*60/100);
            g.lineTo(button_lr_w*20/100, button_lr_h/2 - button_lr_w*60/100);
            g.lineTo(button_lr_w*80/100, button_lr_h/2);
            g.endFill();
        }
        {//ButtonBottom
            s_NinePatch_Button_Bottom.Resize(button_bottom_w, button_bottom_h);
            m_Button_Bottom.x = button_bottom_area_w/2 - button_bottom_w/2;
            m_Button_Bottom.y = total_h - button_bottom_area_h/2 - button_bottom_h/2;

            var bmd:BitmapData = new BitmapData(button_bottom_w, button_bottom_h, true, 0x00000000);
            FontText.DrawText(bmd, "PLAY", bmd.width/2, bmd.height/2, bmd.height*80/100, 0xFFFFFF);
            m_Bitmap_BottomLabel.bitmapData = bmd;
        }
        {//SS
            var ss_scl_x:Number = 0.9 * ss_w / m_MapW;
            var ss_scl_y:Number = 0.9 * ss_h / m_MapH;

            s_Sprite_SS.x = total_w/2;
            s_Sprite_SS.y = total_h/2;
            s_Sprite_SS.scaleX = s_Sprite_SS.scaleY = Math.max(1, Math.min(ss_scl_x, ss_scl_y));
        }
    }

    //Redraw
    public function Redraw():void{
        var bmd:BitmapData;
        var color:uint;

        var map_index:int = Monochroll_Wonderfl.Instance.m_MapIndex;
        var map_info:* = Monochroll_Wonderfl.MAP[map_index];

        //s_BitmapData_Label
        {
            var title:String = "No." + (map_index+1) + "  "+ map_info.name;

            bmd = s_BitmapData_Label;
            bmd.fillRect(bmd.rect, 0x00000000);
            color = Monochroll_Wonderfl.IsClear(Monochroll_Wonderfl.Instance.m_MapIndex)? 0xFFEE00: 0xFFFFFF;
            FontText.DrawText(bmd, title, bmd.width/2, bmd.height/2, bmd.height*80/100, color);
        }

        //s_BitmapData_SS
        {
            const white_val:uint = 0xFF * Monochroll_Wonderfl.COLOR_WHITE_RATIO;
            const black_val:uint = 0xFF * Monochroll_Wonderfl.COLOR_BLACK_RATIO;

            const color_bg_white:uint        = 0xFF000000 | (white_val << 16) | (white_val << 8) | (white_val << 0);
            const color_bg_black:uint        = 0xFF000000 | (black_val << 16) | (black_val << 8) | (black_val << 0);
            const color_player_white:uint    = color_bg_black;
            const color_player_black:uint    = color_bg_white;
            const color_goal_white:uint        = color_bg_black;
            const color_goal_black:uint        = color_bg_white;
            const color_block_white:uint    = 0xFFFFFFFF;
            const color_block_black:uint    = 0xFF000000;

            var map:Array = map_info.map;

            var map_num_x:int = map[0].length;
            var map_num_y:int = map.length;

            m_MapW = map_num_x;
            m_MapH = map_num_y;
            s_Bitmap_SS.x = -m_MapW/2;
            s_Bitmap_SS.y = -m_MapH/2;

            bmd = s_BitmapData_SS;
            bmd.fillRect(bmd.rect, 0x00000000);
            for(var yy:int = 0; yy < map_num_y; ++yy){
                for(var xx:int = 0; xx < map_num_x; ++xx){
                    var map_val:int = map[yy][xx];
                    if(map_val < 16){
                        map_val = Monochroll_Wonderfl.O;//ゲートはひとまずムシ
                    }

                    color = 0xFF888888;
                    switch(map_val){
                    case Monochroll_Wonderfl.O: color = color_bg_white;        break;
                    case Monochroll_Wonderfl.W: color = color_bg_black;        break;
                    case Monochroll_Wonderfl.P: color = color_player_black;    break;
                    case Monochroll_Wonderfl.Q: color = color_player_white;    break;
                    case Monochroll_Wonderfl.G: color = color_goal_black;    break;
                    case Monochroll_Wonderfl.H: color = color_goal_white;    break;
                    case Monochroll_Wonderfl.B: color = color_block_black;    break;
                    case Monochroll_Wonderfl.A: color = color_block_white;    break;
                    }

                    bmd.setPixel32(xx, yy, color);
                }
            }
        }

        m_RedrawFlag = false;
    }

    //Update
    override public function Update(in_DeltaTime:Number):void{
        if(m_RedrawFlag){
            Redraw();
            Resize();
        }

        m_ButtonManager.Update(in_DeltaTime);
    }

    //Touch
    override public function OnMouseDown():void{
        m_ButtonManager.OnMouseDown();
    }
    override public function OnMouseMove():void{
        m_ButtonManager.OnMouseMove();
    }
    override public function OnMouseUp():void{
        var index:int = m_ButtonManager.OnMouseUp();

        if(index < 0){//No Select
            return;
        }

        OnSelect(index);
    }
    protected function OnSelect(in_Index:int):void{
        switch(in_Index){
        case BUTTON_L:
            --Monochroll_Wonderfl.Instance.m_MapIndex;
            if(Monochroll_Wonderfl.Instance.m_MapIndex < 0){
                Monochroll_Wonderfl.Instance.m_MapIndex = Monochroll_Wonderfl.MAP.length-1;
            }
            m_RedrawFlag = true;
            break;
        case BUTTON_R:
            ++Monochroll_Wonderfl.Instance.m_MapIndex;
            if(Monochroll_Wonderfl.MAP.length <= Monochroll_Wonderfl.Instance.m_MapIndex){
                Monochroll_Wonderfl.Instance.m_MapIndex = 0;
            }
            m_RedrawFlag = true;
            break;
        case BUTTON_BOTTOM:
            //Play
            Monochroll_Wonderfl.Instance.Reset();
            m_NextPopup = new Popup_StageNameFade();
            m_EndFlag = true;
            break;
        }
    }

    //On Back
    override public function OnBack():void{
        m_NextPopup = new Popup_Title();
        m_EndFlag = true;
    }
}


//Popup : Menu
class Popup_Menu extends Popup
{
    //==Static==

    //毎回生成するのは高コストなので、一度生成したら保持しておく
    //- BG
    static public var s_Bitmap_BG:Bitmap = null;
    //- Button
    static public var s_NinePatch_Button:Vector.<NinePatch> = null;
    static public var s_Bitmap_BtnLabel:Vector.<Vector.<Bitmap> >;
    //- Label
    static public var s_Bitmap_Label:Vector.<Bitmap> = null;

    //Button
    static public var s_ButtonIter:int = 0;
    static public const BUTTON_CONTINUE:int        = s_ButtonIter++;
    static public const BUTTON_RESTART:int        = s_ButtonIter++;
    static public const BUTTON_STAGESELECT:int    = s_ButtonIter++;
    static public const BUTTON_NUM:int            = s_ButtonIter;
    static public const BUTTON_LABEL:Vector.<Vector.<String> > = new <Vector.<String> >[
        new <String>["CONTINUE",    "RESTART",    "SELECT\nSTAGE"],
        new <String>["NEXT",        "REPLAY",    "SELECT\nSTAGE"],
    ];

    //Label
    static public var s_LabelIter:int = 0;
    static public const LABEL_STAGENUMBER:int    = s_LabelIter++;
    static public const LABEL_STAGENAME:int        = s_LabelIter++;
    static public const LABEL_DUMMY1:int        = s_LabelIter++;
    static public const LABEL_DUMMY2:int        = s_LabelIter++;
    static public const LABEL_CLEARNUM:int        = s_LabelIter++;
    static public const LABEL_NUM:int            = s_LabelIter;

    //ラベルのために内部で確保するビットマップの大きさ
    static public const LABEL_DEFAULT_W:int = 320;
    static public const LABEL_DEFAULT_H:int = 64;


    //==Var==

    //Layer
    public var m_Layer_BG:Sprite = new Sprite();
    public var m_Layer_Content:Sprite = new Sprite();

    //ボタン
    public var m_Button:Vector.<Button> = null;
    public var m_ButtonManager:ButtonManager = new ButtonManager();

    //Flag
    public var m_IsClear:Boolean;


    //==Function==

    //Init
    public function Popup_Menu(in_IsClear:Boolean){
        super();

        var i:int, c:int;
        var bmd:BitmapData;

        //Param
        {
            m_IsClear = in_IsClear;
        }

        //Layer
        {
            addChild(m_Layer_BG);
            addChild(m_Layer_Content);
        }

        //BG
        {
            if(s_Bitmap_BG == null){
                s_Bitmap_BG = new Bitmap(new BitmapData(1, 1, false, 0x000000));
            }

            m_Layer_BG.addChild(s_Bitmap_BG);
        }

        //Button
        if(s_NinePatch_Button == null){
            s_NinePatch_Button = new Vector.<NinePatch>(BUTTON_NUM);
            for(i = 0; i < BUTTON_NUM; ++i){
                s_NinePatch_Button[i] = NinePatch.Create();
            }
        }
        if(s_Bitmap_BtnLabel == null){
            var button_w:int = Monochroll_Wonderfl.Instance.GetTotalW()/2;
            var button_h:int = Math.min(Monochroll_Wonderfl.Instance.GetTotalH()/BUTTON_NUM, button_w*30/100);
            s_Bitmap_BtnLabel = new Vector.<Vector.<Bitmap> >(2);
            s_Bitmap_BtnLabel[0] = new Vector.<Bitmap>(BUTTON_NUM);
            s_Bitmap_BtnLabel[1] = new Vector.<Bitmap>(BUTTON_NUM);
            for(i = 0; i < BUTTON_NUM; ++i){
                for(c = 0; c < 2; ++c){
                    bmd = new BitmapData(button_w, button_h, true, 0x00000000);
                    FontText.DrawText(bmd, BUTTON_LABEL[c][i], bmd.width/2, bmd.height/2, bmd.height*40/100, 0xFFFFFF);

                    s_Bitmap_BtnLabel[c][i] = new Bitmap(bmd);
                }
            }
        }
        var clear_index:int = in_IsClear? 1: 0;
        m_Button = new Vector.<Button>(BUTTON_NUM);
        for(i = 0; i < BUTTON_NUM; ++i){
            m_Button[i] = new Button(s_NinePatch_Button[i]);
            m_Layer_Content.addChild(m_Button[i]);
            m_ButtonManager.AddButton(m_Button[i]);

            m_Button[i].addChild(s_Bitmap_BtnLabel[clear_index][i]);
        }

        //Label
        {
            if(s_Bitmap_Label == null){
                s_Bitmap_Label = new Vector.<Bitmap>(LABEL_NUM);
                for(i = 0; i < LABEL_NUM; ++i){
                    s_Bitmap_Label[i] = new Bitmap(new BitmapData(LABEL_DEFAULT_W, LABEL_DEFAULT_H, true, 0x00000000));
                }
            }

            for(i = 0; i < LABEL_NUM; ++i){
                m_Layer_Content.addChild(s_Bitmap_Label[i]);
            }
        }

        //位置と画像の初期化
        {
            Redraw();
            Resize();
        }
    }

    //Resize
    public function Resize():void{
        var i:int;
        var bmp:Bitmap;

        var total_w:int = Monochroll_Wonderfl.Instance.GetTotalW();
        var total_h:int = Monochroll_Wonderfl.Instance.GetTotalH();

        var button_rect_w:int = total_w/2;
        var button_rect_h:int = total_h/BUTTON_NUM;
        var button_w:int = button_rect_w * 0.8;
        var button_h:int = button_rect_h * 0.8;
        var label_w:int = total_w - button_rect_w;
        var label_h:int = total_h / 6;//LABEL_NUM;

        var label_scl:Number = Math.min(label_w / LABEL_DEFAULT_W, label_h / LABEL_DEFAULT_H);

        {//BG
            s_Bitmap_BG.scaleX = total_w;
            s_Bitmap_BG.scaleY = total_h;
        }
        {//Button
            for(i = 0; i < BUTTON_NUM; ++i){
                s_NinePatch_Button[i].Resize(button_w, button_h);
                m_Button[i].x = button_rect_w/2 - button_w/2;
                m_Button[i].y = (i + 0.5) * button_rect_h - 0.5 * button_h;

                for(var c:int = 0; c < 2; ++c){
                    bmp = s_Bitmap_BtnLabel[c][i];
                    bmp.x = button_w/2 - bmp.width/2;
                    bmp.y = button_h/2 - bmp.height/2;
                }
            }
        }
        {//Label
            for(i = 0; i < LABEL_NUM; ++i){
                bmp = s_Bitmap_Label[i];
                bmp.x = button_rect_w + label_w/2 - LABEL_DEFAULT_W*label_scl/2;
                bmp.y = i * label_h;
                bmp.scaleX = bmp.scaleY = label_scl;
            }
        }
    }

    //Redraw
    public function Redraw():void{
        var bmd:BitmapData;
        var color:uint;

        var map_info:* = Monochroll_Wonderfl.MAP[Monochroll_Wonderfl.Instance.m_MapIndex];

        //Label
        {
            color = Monochroll_Wonderfl.IsClear(Monochroll_Wonderfl.Instance.m_MapIndex)? 0xFFEE00: 0xFFFFFF;

            var str_number:String = "No." + (Monochroll_Wonderfl.Instance.m_MapIndex + 1);
            bmd = s_Bitmap_Label[LABEL_STAGENUMBER].bitmapData;
            bmd.fillRect(bmd.rect, 0x00000000);
            FontText.DrawText(bmd, str_number, bmd.width/2, bmd.height/2, bmd.height*80/100, color);

            var title:String = " " + map_info.name;
            bmd = s_Bitmap_Label[LABEL_STAGENAME].bitmapData;
            bmd.fillRect(bmd.rect, 0x00000000);
            FontText.DrawText(bmd, title, bmd.width/2, bmd.height/2, bmd.height*80/100, color);

            color = Monochroll_Wonderfl.IsAllClear()? 0xFFEE00: 0xFFFFFF;

            var str_clear:String = "Clear:" + Monochroll_Wonderfl.GetClearNum() + "/" + Monochroll_Wonderfl.MAP.length;
            bmd = s_Bitmap_Label[LABEL_CLEARNUM].bitmapData;
            bmd.fillRect(bmd.rect, 0x00000000);
            FontText.DrawText(bmd, str_clear, bmd.width/2, bmd.height/2, bmd.height*80/100, color);
        }
    }

    //Update
    override public function Update(in_DeltaTime:Number):void{
        m_ButtonManager.Update(in_DeltaTime);
    }

    //Touch
    override public function OnMouseDown():void{
        m_ButtonManager.OnMouseDown();
    }
    override public function OnMouseMove():void{
        m_ButtonManager.OnMouseMove();
    }
    override public function OnMouseUp():void{
        var index:int = m_ButtonManager.OnMouseUp();

        if(index < 0){//No Select
            return;
        }

        if(m_IsClear){
            OnSelect_Result(index);
        }else{
            OnSelect_Menu(index);
        }
    }
    protected function OnSelect_Result(in_Index:int):void{
        switch(in_Index){
        case BUTTON_CONTINUE://次へ
            //普通に次へ
            ++Monochroll_Wonderfl.Instance.m_MapIndex;
            if(Monochroll_Wonderfl.MAP.length <= Monochroll_Wonderfl.Instance.m_MapIndex){
                Monochroll_Wonderfl.Instance.m_MapIndex = 0;
            }

            Monochroll_Wonderfl.Instance.Reset();

            m_NextPopup = new Popup_StageNameFade();

            m_EndFlag = true;
            break;
        case BUTTON_RESTART://もう一度
            //Resetかけつつ終了
            Monochroll_Wonderfl.Instance.Reset();
            m_EndFlag = true;
            break;
        case BUTTON_STAGESELECT:
            //次のPopupを指定しつつ終了
            m_NextPopup = new Popup_StageSelect();
            m_EndFlag = true;
            break;
        }
    }
    protected function OnSelect_Menu(in_Index:int):void{
        switch(in_Index){
        case BUTTON_CONTINUE://続行
            //何もせず終了
            m_EndFlag = true;
            break;
        case BUTTON_RESTART://やり直し
            //Resetかけつつ終了
            Monochroll_Wonderfl.Instance.Reset();
            m_EndFlag = true;
            break;
        case BUTTON_STAGESELECT:
            //次のPopupを指定しつつ終了
            m_NextPopup = new Popup_StageSelect();
            m_EndFlag = true;
            break;
        }
    }

    //On Back
    override public function OnBack():void{
        if(m_IsClear){
            m_NextPopup = new Popup_StageSelect();
        }else{
            //ゲーム画面に戻るため自分をPopするだけ
            //m_NextPopup = null;
        }
        m_EndFlag = true;
    }
}


//Popup : StageNameFade
class Popup_StageNameFade extends Popup
{
    //==Const==

    //フェードにかかる時間
    static public const FADE_WAIT_TIME:Number = 1.5;
    static public const FADE_OUT_TIME:Number = 0.5;


    //==Var==

    //フェード用タイマー
    public var m_Timer:Number = 0;


    //==Function==

    //Init
    public function Popup_StageNameFade(){
        super();

        //BG
        {
            var index:int = Monochroll_Wonderfl.Instance.m_MapIndex;
            var map_info:* = Monochroll_Wonderfl.MAP[index];
            var str_no:String = "No." + (index + 1);
            var str_name:String = map_info.name;

            //フェード中の動的なサイズ変更に対応できないがまぁ良いか
            var bmd:BitmapData = new BitmapData(Monochroll_Wonderfl.Instance.GetTotalW(), Monochroll_Wonderfl.Instance.GetTotalH(), false, 0x000000);
            var color:uint = Monochroll_Wonderfl.IsClear(Monochroll_Wonderfl.Instance.m_MapIndex)? 0xFFEE00: 0xFFFFFF;
            FontText.DrawText(bmd, str_no, bmd.width/2, bmd.height*1/4, bmd.height*20/100, color);
            FontText.DrawText(bmd, str_name, bmd.width/2, bmd.height*3/4, bmd.height*20/100, color);

            var bmp:Bitmap = new Bitmap(bmd);
            addChild(bmp);
        }
    }
    //Update
    override public function Update(in_DeltaTime:Number):void{
        m_Timer += in_DeltaTime;
        var t:Number = m_Timer;

        if(t < FADE_WAIT_TIME){
            return;
        }
        t -= FADE_WAIT_TIME

        if(t < FADE_OUT_TIME){
            this.alpha = 1 - t/FADE_OUT_TIME;
            return;
        }
        t -= FADE_OUT_TIME;

        m_EndFlag = true;
    }

    //Touch
    override public function OnMouseDown():void{
    }
    override public function OnMouseMove():void{
    }
    override public function OnMouseUp():void{
    }
}


//Popup : Title
class Popup_Title extends Popup
{
    //==Static==

    //毎回生成するのは高コストなので、一度生成したら保持しておく
    //- BG
    static public var s_Bitmap_BG:Bitmap = null;
    //- Icon
    static public var s_Bitmap_Icon:Bitmap = null;
    static public var s_Sprite_Icon:Sprite = null;
    //- Button
    static public var s_NinePatch_Button:Vector.<NinePatch> = null;
    static public var s_Button:Vector.<Button> = null;
    static public var s_Bitmap_BtnLabel:Vector.<Bitmap>;

    //Button
    static public var s_ButtonIter:int = 0;
    static public const BUTTON_STAGESELECT:int    = s_ButtonIter++;
//    static public const BUTTON_RECOMMEND:int    = s_ButtonIter++;
//    static public const BUTTON_OTHERWORKS:int    = s_ButtonIter++;
    static public const BUTTON_TWITTER:int        = s_ButtonIter++;
    static public const BUTTON_NUM:int            = s_ButtonIter;
    static public const BUTTON_LABEL:Vector.<String> = new <String>[
        "START",
//        "RATE THIS GAME",
//        "OTHER WORKS",
        "TWEET",
    ];
    static public const BUTTON_LABEL_SCL:Vector.<Number> = new <Number>[
        0.4,
//        0.3,
//        0.3,
        0.4,
    ];


    //==Var==

    //Layer
    public var m_Layer_BG:Sprite = new Sprite();
    public var m_Layer_Content:Sprite = new Sprite();

    //ボタン
    public var m_ButtonManager:ButtonManager = new ButtonManager();


    //==Function==

    //Init
    public function Popup_Title(){
        super();

        var i:int;

        //Layer
        {
            addChild(m_Layer_BG);
            addChild(m_Layer_Content);
        }

        //BG
        {
            if(s_Bitmap_BG == null){
                s_Bitmap_BG = new Bitmap(new BitmapData(1, 1, false, 0x000000));
            }

            m_Layer_BG.addChild(s_Bitmap_BG);
        }

        //Icon
        {
            if(s_Bitmap_Icon == null){
                var bmd_icon:BitmapData = new BitmapData(256, 256, true, 0x00000000);
                bmd_icon.draw(ImageManager.GetBitmapData_Ori(), new Matrix(1,0,0,1, -256, 0));
                s_Bitmap_Icon = new Bitmap(bmd_icon);
                s_Bitmap_Icon.x = -s_Bitmap_Icon.width/2;
                s_Bitmap_Icon.y = -s_Bitmap_Icon.height/2;
                s_Bitmap_Icon.smoothing = true;

                s_Sprite_Icon = new Sprite();
                s_Sprite_Icon.addChild(s_Bitmap_Icon);
            }

            m_Layer_Content.addChild(s_Sprite_Icon);
        }

        //Button
        if(s_NinePatch_Button == null){
            s_NinePatch_Button = new Vector.<NinePatch>(BUTTON_NUM);
            s_Button = new Vector.<Button>(BUTTON_NUM);
            for(i = 0; i < BUTTON_NUM; ++i){
                s_NinePatch_Button[i] = NinePatch.Create();
                s_Button[i] = new Button(s_NinePatch_Button[i]);
            }
        }
        if(s_Bitmap_BtnLabel == null){
            var button_w:int = Monochroll_Wonderfl.Instance.GetTotalW()/2;
            var button_h:int = Math.min(Monochroll_Wonderfl.Instance.GetTotalH()/BUTTON_NUM, button_w*30/100);
            s_Bitmap_BtnLabel = new Vector.<Bitmap>(BUTTON_NUM);
            for(i = 0; i < BUTTON_NUM; ++i){
                var bmd:BitmapData = new BitmapData(button_w, button_h, true, 0x00000000);

                FontText.DrawText(bmd, BUTTON_LABEL[i], bmd.width/2, bmd.height/2, bmd.height * BUTTON_LABEL_SCL[i], 0xFFFFFF);
                s_Bitmap_BtnLabel[i] = new Bitmap(bmd);
            }
        }
        for(i = 0; i < BUTTON_NUM; ++i){
            m_Layer_Content.addChild(s_Button[i]);
            m_ButtonManager.AddButton(s_Button[i]);

            s_Button[i].addChild(s_Bitmap_BtnLabel[i]);
        }

        //位置と画像の初期化
        {
            Redraw();
            Resize();
        }
    }

    //Resize
    public function Resize():void{
        var i:int;
        var bmp:Bitmap;

        var total_w:int = Monochroll_Wonderfl.Instance.GetTotalW();
        var total_h:int = Monochroll_Wonderfl.Instance.GetTotalH();

        var button_rect_w:int = total_w/2;
        var button_rect_h:int = Math.min(total_h, total_w/2)/BUTTON_NUM;
        var button_w:int = button_rect_w * 0.9;
        var button_h:int = button_rect_h * 0.9;

        {//BG
            s_Bitmap_BG.scaleX = total_w;
            s_Bitmap_BG.scaleY = total_h;
        }
        {//Icon
            s_Sprite_Icon.scaleX = s_Sprite_Icon.scaleY = Math.min(total_w/2 / s_Bitmap_Icon.width, total_h / s_Bitmap_Icon.height) * 0.95;
            s_Sprite_Icon.x = total_w*3/4;
            s_Sprite_Icon.y = total_h*1/2;
        }
        {//Button
            for(i = 0; i < BUTTON_NUM; ++i){
                s_NinePatch_Button[i].Resize(button_w, button_h);
                s_Button[i].x = button_rect_w/2 - button_w/2;
                s_Button[i].y = total_h/2 + (i - BUTTON_NUM/2 + 0.5) * button_rect_h - 0.5 * button_h;

                bmp = s_Bitmap_BtnLabel[i];
                bmp.x = button_w/2 - bmp.width/2;
                bmp.y = button_h/2 - bmp.height/2;
            }
        }
    }

    //Redraw
    public function Redraw():void{
    }

    //Update
    override public function Update(in_DeltaTime:Number):void{
        m_ButtonManager.Update(in_DeltaTime);
    }

    //Touch
    override public function OnMouseDown():void{
        m_ButtonManager.OnMouseDown();
    }
    override public function OnMouseMove():void{
        m_ButtonManager.OnMouseMove();
    }
    override public function OnMouseUp():void{
        var index:int = m_ButtonManager.OnMouseUp();

        if(index < 0){//No Select
            return;
        }

        OnSelect(index);
    }
    protected function OnSelect(in_Index:int):void{
        switch(in_Index){
        case BUTTON_STAGESELECT:
            //次のPopupを指定しつつ終了
            m_NextPopup = new Popup_StageSelect();
            m_EndFlag = true;
            break;
//        case BUTTON_RECOMMEND:
//            Monochroll_Wonderfl.Navigate_Recommend();
//            break;
//        case BUTTON_OTHERWORKS:
//            Monochroll_Wonderfl.Navigate_OtherWorks();
//            break;
        case BUTTON_TWITTER:
            Monochroll_Wonderfl.Navigate_Twitter();
            break;
        }
    }

    //On Back
    override public function OnBack():void{
        //終了
        //NativeApplication.nativeApplication.exit();
    }
}


//Popup : Congratulation
class Popup_Congratulation extends Popup
{
  //・有料:コングラッチュレーション&評価依頼   &他作品への導線&Twitterへの導線&ステージセレクトボタン
  //・無料:コングラッチュレーション&有料版への導線&他作品への導線&Twitterへの導線&ステージセレクトボタン

    //==Static==

    //毎回生成するのは高コストなので、一度生成したら保持しておく
    //- BG
    static public var s_Bitmap_BG:Bitmap = null;
    //- Icon
    static public var s_Bitmap_Icon:Bitmap = null;
    static public var s_Sprite_Icon:Sprite = null;
    //- Button
    static public var s_NinePatch_Button:Vector.<NinePatch> = null;
    static public var s_Button:Vector.<Button> = null;
    static public var s_Bitmap_BtnLabel:Vector.<Bitmap>;

    //Button
    static public var s_ButtonIter:int = 0;
    static public const BUTTON_STAGESELECT:int    = s_ButtonIter++;
//    static public const BUTTON_RECOMMEND:int    = s_ButtonIter++;
//    static public const BUTTON_OTHERWORKS:int    = s_ButtonIter++;
    static public const BUTTON_TWITTER:int        = s_ButtonIter++;
    static public const BUTTON_NUM:int            = s_ButtonIter;
    static public const BUTTON_LABEL:Vector.<String> = new <String>[
        "STAGE\nSELECT",
//        "RATE THIS GAME",
//        "OTHER WORKS",
        "TWEET",
    ];
    static public const BUTTON_LABEL_SCL:Vector.<Number> = new <Number>[
        0.4,
        0.3,
        0.3,
        0.4,
    ];


    //==Var==

    //Layer
    public var m_Layer_BG:Sprite = new Sprite();
    public var m_Layer_Content:Sprite = new Sprite();

    //ボタン
    public var m_ButtonManager:ButtonManager = new ButtonManager();


    //==Function==

    //Init
    public function Popup_Congratulation(){
        super();

        var i:int;

        //Layer
        {
            addChild(m_Layer_BG);
            addChild(m_Layer_Content);
        }

        //BG
        {
            if(s_Bitmap_BG == null){
                s_Bitmap_BG = new Bitmap(new BitmapData(1, 1, false, 0x000000));
            }

            m_Layer_BG.addChild(s_Bitmap_BG);
        }

        //Icon
        {
            if(s_Bitmap_Icon == null){
                var bmd_icon:BitmapData = new BitmapData(256, 256, true, 0x00000000);
                bmd_icon.draw(ImageManager.GetBitmapData_Ori(), new Matrix(1,0,0,1, -256, -256));
                s_Bitmap_Icon = new Bitmap(bmd_icon);
                s_Bitmap_Icon.x = -s_Bitmap_Icon.width/2;
                s_Bitmap_Icon.y = -s_Bitmap_Icon.height/2;
                s_Bitmap_Icon.smoothing = true;

                s_Sprite_Icon = new Sprite();
                s_Sprite_Icon.addChild(s_Bitmap_Icon);
            }

            m_Layer_Content.addChild(s_Sprite_Icon);
        }

        //Button
        if(s_NinePatch_Button == null){
            s_NinePatch_Button = new Vector.<NinePatch>(BUTTON_NUM);
            s_Button = new Vector.<Button>(BUTTON_NUM);
            for(i = 0; i < BUTTON_NUM; ++i){
                s_NinePatch_Button[i] = NinePatch.Create();
                s_Button[i] = new Button(s_NinePatch_Button[i]);
            }
        }
        if(s_Bitmap_BtnLabel == null){
            var button_w:int = Monochroll_Wonderfl.Instance.GetTotalW()/2;
            var button_h:int = Math.min(Monochroll_Wonderfl.Instance.GetTotalH()/BUTTON_NUM, button_w*30/100);
            s_Bitmap_BtnLabel = new Vector.<Bitmap>(BUTTON_NUM);
            for(i = 0; i < BUTTON_NUM; ++i){
                var bmd:BitmapData = new BitmapData(button_w, button_h, true, 0x00000000);

                FontText.DrawText(bmd, BUTTON_LABEL[i], bmd.width/2, bmd.height/2, bmd.height * BUTTON_LABEL_SCL[i], 0xFFEE00);
                s_Bitmap_BtnLabel[i] = new Bitmap(bmd);
            }
        }
        for(i = 0; i < BUTTON_NUM; ++i){
            m_Layer_Content.addChild(s_Button[i]);
            m_ButtonManager.AddButton(s_Button[i]);

            s_Button[i].addChild(s_Bitmap_BtnLabel[i]);
        }

        //位置と画像の初期化
        {
            Redraw();
            Resize();
        }
    }

    //Resize
    public function Resize():void{
        var i:int;
        var bmp:Bitmap;

        var total_w:int = Monochroll_Wonderfl.Instance.GetTotalW();
        var total_h:int = Monochroll_Wonderfl.Instance.GetTotalH();

        var button_rect_w:int = total_w/2;
        var button_rect_h:int = Math.min(total_h, total_w/2)/BUTTON_NUM;
        var button_w:int = button_rect_w * 0.8;
        var button_h:int = button_rect_h * 0.8;

        {//BG
            s_Bitmap_BG.scaleX = total_w;
            s_Bitmap_BG.scaleY = total_h;
        }
        {//Icon
            s_Sprite_Icon.scaleX = s_Sprite_Icon.scaleY = Math.min(total_w/2 / s_Bitmap_Icon.width, total_h / s_Bitmap_Icon.height) * 0.95;
            s_Sprite_Icon.x = total_w*3/4;
            s_Sprite_Icon.y = total_h*1/2;
        }
        {//Button
            for(i = 0; i < BUTTON_NUM; ++i){
                s_NinePatch_Button[i].Resize(button_w, button_h);
                s_Button[i].x = button_rect_w/2 - button_w/2;
                s_Button[i].y = total_h/2 + (i - BUTTON_NUM/2 + 0.5) * button_rect_h - 0.5 * button_h;

                bmp = s_Bitmap_BtnLabel[i];
                bmp.x = button_w/2 - bmp.width/2;
                bmp.y = button_h/2 - bmp.height/2;
            }
        }
    }

    //Redraw
    public function Redraw():void{
    }

    //Update
    override public function Update(in_DeltaTime:Number):void{
        m_ButtonManager.Update(in_DeltaTime);
    }

    //Touch
    override public function OnMouseDown():void{
        m_ButtonManager.OnMouseDown();
    }
    override public function OnMouseMove():void{
        m_ButtonManager.OnMouseMove();
    }
    override public function OnMouseUp():void{
        var index:int = m_ButtonManager.OnMouseUp();

        if(index < 0){//No Select
            return;
        }

        OnSelect(index);
    }
    protected function OnSelect(in_Index:int):void{
        switch(in_Index){
        case BUTTON_STAGESELECT:
            //次のPopupを指定しつつ終了
            m_NextPopup = new Popup_StageSelect();
            m_EndFlag = true;
            break;
//        case BUTTON_RECOMMEND:
//            Monochroll_Wonderfl.Navigate_Recommend();
//            break;
//        case BUTTON_OTHERWORKS:
//            Monochroll_Wonderfl.Navigate_OtherWorks();
//            break;
        case BUTTON_TWITTER:
            Monochroll_Wonderfl.Navigate_Twitter();
            break;
        }
    }

    //On Back
    override public function OnBack():void{
        m_NextPopup = new Popup_StageSelect();
        m_EndFlag = true;
    }
}


class ImageManager
{
    //==Const==

    static public var s_GraphicIter:int = 0;
    static public const GRAPHIC_BALL_WHITE        :int = s_GraphicIter++;
    static public const GRAPHIC_BALL_BLACK        :int = s_GraphicIter++;
    static public const GRAPHIC_BLOCK_WHITE        :int = s_GraphicIter++;
    static public const GRAPHIC_BLOCK_BLACK        :int = s_GraphicIter++;
    static public const GRAPHIC_GOAL_WHITE        :int = s_GraphicIter++;
    static public const GRAPHIC_GOAL_BLACK        :int = s_GraphicIter++;
    static public const GRAPHIC_GATE            :int = s_GraphicIter++;
    static public const GRAPHIC_GRAVITY_ARROW    :int = s_GraphicIter++;
    static public const GRAPHIC_NUM                :int = s_GraphicIter;

    //==Var==

    static public var s_BitmapData_Ori:BitmapData;
    static public var s_BitmapData:Vector.<BitmapData>;
    static public var s_Bitmap_GravityArrow:Bitmap;

    //==Function==

    //Init
    static public function Init(in_Graphic:DisplayObject):void{
        var i:int;
        var bmd:BitmapData;
        var bmp:Bitmap;
        var mtx:Matrix = new Matrix();

        //s_BitmapData_Ori
        {
            s_BitmapData_Ori = new BitmapData(512, 512, true, 0x00000000);
            s_BitmapData_Ori.draw(in_Graphic);
        }

        //s_BitmapData
        {
            s_BitmapData = new Vector.<BitmapData>(GRAPHIC_NUM);
            for(i = 0; i < GRAPHIC_NUM; ++i){
                bmd = new BitmapData(64, 64, true, 0x00000000);

                mtx.tx = -64 * int(i % 4);
                mtx.ty = -64 * int(i / 4);
                bmd.draw(in_Graphic, mtx);

                s_BitmapData[i] = bmd;
            }
        }

        //s_Bitmap_GravityArrow
        {
            bmp = new Bitmap(s_BitmapData[GRAPHIC_GRAVITY_ARROW]);
            bmp.y = -bmp.height/2;

            s_Bitmap_GravityArrow = bmp;
        }
    }

    //Get Ori
    static public function GetBitmapData_Ori():BitmapData{
        return s_BitmapData_Ori;
    }

    //Get Graphic
    static public function GetBitmapData(in_Index:int):BitmapData{
        return s_BitmapData[in_Index];
    }

    //Get GravityArrow
    static public function GetBitmap_GravityArrow():Bitmap{
        return s_Bitmap_GravityArrow;
    }
}


class NinePatch extends Sprite
{
    //==Const==

    static public var s_PartIter:int = 0;
    static public const PART_C:int    = s_PartIter++;
    static public const PART_L:int    = s_PartIter++;
    static public const PART_R:int    = s_PartIter++;
    static public const PART_U:int    = s_PartIter++;
    static public const PART_D:int    = s_PartIter++;
    static public const PART_UL:int    = s_PartIter++;
    static public const PART_UR:int    = s_PartIter++;
    static public const PART_DL:int    = s_PartIter++;
    static public const PART_DR:int    = s_PartIter++;
    static public const PART_NUM:int= s_PartIter;

    static public const BASE_W:int = 64/4;
    static public const BASE_H:int = 64/4;


    //==Var==

    public var m_W:int = 1;
    public var m_H:int = 1;

    static public var s_BitmapData:Vector.<BitmapData> = null;
    public var m_Bitmap:Bitmap;
    public var m_BitmapData:BitmapData;


    //==Function==

    //Create
    static public function Create():NinePatch{
        if(s_BitmapData == null){
            s_BitmapData = new Vector.<BitmapData>(PART_NUM);

            var bmd_ori:BitmapData = ImageManager.GetBitmapData_Ori();

            var bmd:BitmapData;
            var mtx:Matrix = new Matrix();

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*1;
            mtx.ty = -16*1 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_C]    = bmd;

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*0;
            mtx.ty = -16*1 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_L]    = bmd;

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*3;
            mtx.ty = -16*1 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_R]    = bmd;

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*1;
            mtx.ty = -16*0 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_U]    = bmd;

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*1;
            mtx.ty = -16*3 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_D]    = bmd;

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*0;
            mtx.ty = -16*0 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_UL]    = bmd;

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*3;
            mtx.ty = -16*0 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_UR]    = bmd;

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*0;
            mtx.ty = -16*3 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_DL]    = bmd;

            bmd = new BitmapData(BASE_W, BASE_H, true, 0x00000000);
            mtx.tx = -16*3;
            mtx.ty = -16*3 - 128;
            bmd.draw(bmd_ori, mtx);
            s_BitmapData[PART_DR]    = bmd;
        }

        return new NinePatch();
    }
    public function NinePatch(){
        var bmp:Bitmap = new Bitmap();
        m_Bitmap = bmp;
        addChild(bmp);

        Resize(32, 32);//適当にパラメータを設定してみる
    }

    //Resize
    public function Resize(in_W:int, in_H:int):void{
/*
        var bmp:Bitmap;

        if(m_W == in_W && m_H == in_H){
            return;
        }
        m_W = in_W;
        m_H = in_H;

        bmp = m_Bitmap[PART_UL];
        bmp.x = 0;
        bmp.y = 0;

        bmp = m_Bitmap[PART_UR];
        bmp.x = in_W - BASE_W;
        bmp.y = 0;

        bmp = m_Bitmap[PART_DL];
        bmp.x = 0;
        bmp.y = in_H - BASE_H;

        bmp = m_Bitmap[PART_DR];
        bmp.x = in_W - BASE_W;
        bmp.y = in_H - BASE_H;

        bmp = m_Bitmap[PART_L];
        bmp.x = 0;
        bmp.y = BASE_H;
        bmp.scaleY = (in_H - 2*BASE_H)/BASE_H;

        bmp = m_Bitmap[PART_R];
        bmp.x = in_W - BASE_W;
        bmp.y = BASE_H;
        bmp.scaleY = (in_H - 2*BASE_H)/BASE_H;

        bmp = m_Bitmap[PART_U];
        bmp.x = BASE_W;
        bmp.y = 0;
        bmp.scaleX = (in_W - 2*BASE_W)/BASE_W;

        bmp = m_Bitmap[PART_D];
        bmp.x = BASE_W;
        bmp.y = in_H - BASE_H;
        bmp.scaleX = (in_W - 2*BASE_W)/BASE_W;

        bmp = m_Bitmap[PART_C];
        bmp.x = BASE_W;
        bmp.y = BASE_H;
        bmp.scaleX = (in_W - 2*BASE_W)/BASE_W;
        bmp.scaleY = (in_H - 2*BASE_H)/BASE_H;
/*/
        if(m_W == in_W && m_H == in_H){
            return;
        }
        m_W = in_W;
        m_H = in_H;

        var bmd:BitmapData = new BitmapData(in_W, in_H, true, 0x00000000);
        m_BitmapData = bmd;

        var src_rect:Rectangle = new Rectangle(0,0,BASE_W,BASE_H);
        var dst_pos:Point = new Point(0,0);
        var offset_x:int;
        var offset_y:int;

        //Corner
        {
            //- LU
            dst_pos.x = 0;
            dst_pos.y = 0;
            bmd.copyPixels(s_BitmapData[PART_UL], src_rect, dst_pos);
            //- RU
            dst_pos.x = in_W - BASE_W;
            dst_pos.y = 0;
            bmd.copyPixels(s_BitmapData[PART_UR], src_rect, dst_pos);
            //- LD
            dst_pos.x = 0;
            dst_pos.y = in_H - BASE_H;
            bmd.copyPixels(s_BitmapData[PART_DL], src_rect, dst_pos);
            //- RD
            dst_pos.x = in_W - BASE_W;
            dst_pos.y = in_H - BASE_H;
            bmd.copyPixels(s_BitmapData[PART_DR], src_rect, dst_pos);
        }

        //Edge
        {
            //UD
            src_rect.width = BASE_W;
            src_rect.height = BASE_H;
            for(offset_x = BASE_W; offset_x < in_W - BASE_W; offset_x += BASE_W){
                dst_pos.x = offset_x;
                if(in_W - BASE_W < offset_x + BASE_W){
                    src_rect.width = (in_W - BASE_W) - offset_x;
                }
                //U
                dst_pos.y = 0;
                bmd.copyPixels(s_BitmapData[PART_U], src_rect, dst_pos);
                //D
                dst_pos.y = in_H-BASE_H;
                bmd.copyPixels(s_BitmapData[PART_D], src_rect, dst_pos);
            }

            //LR
            src_rect.width = BASE_W;
            src_rect.height = BASE_H;
            for(offset_y = BASE_H; offset_y < in_H - BASE_H; offset_y += BASE_H){
                dst_pos.y = offset_y;
                if(in_H - BASE_H < offset_y + BASE_H){
                    src_rect.height = (in_H - BASE_H) - offset_y;
                }
                //L
                dst_pos.x = 0;
                bmd.copyPixels(s_BitmapData[PART_L], src_rect, dst_pos);
                //R
                dst_pos.x = in_W-BASE_W;
                bmd.copyPixels(s_BitmapData[PART_R], src_rect, dst_pos);
            }
        }

        //Center
        {
            for(offset_x = BASE_W; offset_x < in_W - BASE_W; offset_x += BASE_W){
                dst_pos.x = offset_x;
                if(in_W - BASE_W < offset_x + BASE_W){
                    src_rect.width = (in_W - BASE_W) - offset_x;
                }else{
                    src_rect.width = BASE_W;
                }

                for(offset_y = BASE_H; offset_y < in_H - BASE_H; offset_y += BASE_H){
                    dst_pos.y = offset_y;
                    if(in_H - BASE_H < offset_y + BASE_H){
                        src_rect.height = (in_H - BASE_H) - offset_y;
                    }else{
                        src_rect.height = BASE_H;
                    }

                    bmd.copyPixels(s_BitmapData[PART_C], src_rect, dst_pos);
                }
            }
        }

        m_Bitmap.bitmapData = m_BitmapData;
//*/
    }
}


class Button extends Sprite
{
    //==Const==

    static public const SCALE_OFF    :Number = 1;
    static public const SCALE_ON    :Number = 1.1;


    //==Var==

    //Graphic
    public var m_Layer_Content:Sprite = new Sprite();
    public var m_Layer_Scale:Sprite = new Sprite();
    public var m_NinePatch:NinePatch;

    //Flag
    public var m_PressFlag:Boolean = false;


    //==Function==

    //Init
    public function Button(in_NinePatch:NinePatch){
        m_Layer_Scale.x = in_NinePatch.m_W/2;
        m_Layer_Scale.y = in_NinePatch.m_H/2;
        addChild(m_Layer_Scale);

        m_Layer_Content.x = -in_NinePatch.m_W/2;
        m_Layer_Content.y = -in_NinePatch.m_H/2;
        m_Layer_Scale.addChild(m_Layer_Content);

        m_Layer_Content.addChild(in_NinePatch);
        m_NinePatch = in_NinePatch;
    }

    //Update
    public function Update(in_DeltaTime:Number):void{
        //Resizeに備える
        {
            m_Layer_Scale.x = m_NinePatch.m_W/2;
            m_Layer_Scale.y = m_NinePatch.m_H/2;
            m_Layer_Content.x = -m_NinePatch.m_W/2;
            m_Layer_Content.y = -m_NinePatch.m_H/2;
        }

        var lerp_ratio:Number = 0.9;
        var scl:Number = Util.Lerp(m_Layer_Scale.scaleX, (m_PressFlag? SCALE_ON: SCALE_OFF), lerp_ratio);
        m_Layer_Scale.scaleX = m_Layer_Scale.scaleY = scl;
    }

    //Range
    public function IsRectIn():Boolean{
        var trg_x:Number = m_NinePatch.mouseX;
        var trg_y:Number = m_NinePatch.mouseY;

        return (0 <= trg_x && trg_x < m_NinePatch.m_W && 0 <= trg_y && trg_y < m_NinePatch.m_H);
    }

    //
    public function SetPressFlag(in_Flag:Boolean):void{
        m_PressFlag = in_Flag;
    }
}


class ButtonManager
{
    //==Var==

    public var m_Button:Vector.<Button> = new Vector.<Button>();

    public var m_TouchIndex:int = -1;


    //==Function==

    //Register
    public function AddButton(in_Button:Button):void{
        m_Button.push(in_Button);
    }

    //Update
    public function Update(in_DeltaTime:Number):void{
        var num:int = m_Button.length;
        for(var i:int = 0; i < num; ++i){
            var button:Button = m_Button[i];
            button.Update(in_DeltaTime);
        }
    }

    //Touch
    public function OnMouseDown():void{
        m_TouchIndex = -1;

        var num:int = m_Button.length;
        for(var i:int = 0; i < num; ++i){
            var button:Button = m_Button[i];
            var parent:DisplayObjectContainer = button.parent;
            if(IsRangeIn(button)){
                m_TouchIndex = i;

                button.SetPressFlag(true);

                break;
            }
        }
    }
    public function OnMouseMove():void{
        if(0 <= m_TouchIndex){
            var button:Button = m_Button[m_TouchIndex];
            if(! button.IsRectIn()){
                button.SetPressFlag(false);
                m_TouchIndex = -1;
            }
        }
    }
    public function OnMouseUp():int{
        var touch_index:int = m_TouchIndex;

        if(0 <= m_TouchIndex){
            var button:Button = m_Button[m_TouchIndex];
            button.SetPressFlag(false);
        }

        m_TouchIndex = -1;

        return touch_index;
    }

    //Check Range
    public function IsRangeIn(in_Button:Button):Boolean{
        //そもそもボタンの範囲外なら反応しない
        if(! in_Button.IsRectIn()){
            return false;
        }

        //親のどこかのScrollRectの範囲外になってたら反応しない(スクロール対応)
        for(var content:DisplayObjectContainer = in_Button.parent; content != null; content = content.parent){
            if(content.scrollRect == null){
                continue;
            }

            if(! content.scrollRect.contains(content.mouseX / content.scaleX, content.mouseY / content.scaleY)){
                return false;
            }
        }

        return true;
    }

    //Cancel
    //- 主にボタンを押しながらのスライド用
    public function Cancel():void{
        if(0 <= m_TouchIndex){
            var button:Button = m_Button[m_TouchIndex];
            button.SetPressFlag(false);
        }

        m_TouchIndex = -1;
    }
}


class FontText
{
    //==Embed==
    //fontNameではなくfontFamily + embedAsCFF=falseにすること
//    [Embed(source="mplus-1c-black.ttf", fontFamily="mplus", embedAsCFF = "false", mimeType='application/x-font')]
//    private var font:Class;

    //==Const==

    //
    static public var s_AlignIter:int = 0;
    static public const ALIGN_CENTER:int = s_AlignIter++;//Default
    static public const ALIGN_LEFT    :int = s_AlignIter++;
    static public const ALIGN_RIGHT    :int = s_AlignIter++;
    static public const ALIGN_UP    :int = ALIGN_LEFT;
    static public const ALIGN_DOWN    :int = ALIGN_DOWN;

    //==Var==

    static public var s_TextField:TextField = null;
    static public var s_TextFormat:TextFormat = new TextFormat();
    static public var s_TextSprite:Sprite = new Sprite();


    //==Function==

    static public function DrawText(out_BMD:BitmapData, in_Text:String, in_X:Number, in_Y:Number, in_Size:int, in_Color:uint, in_AlignX:int = 0, in_AlignY:int = 0):void{
        if(s_TextField == null){
            s_TextField = new TextField();
//            s_TextField.embedFonts = true;
            s_TextField.autoSize = TextFieldAutoSize.LEFT;

            s_TextFormat.font = "mplus";

            s_TextSprite.addChild(s_TextField);
        }

        //Param
        s_TextFormat.size = in_Size;
        s_TextFormat.color = in_Color;
        s_TextFormat.align = TextFormatAlign.CENTER;
        s_TextField.defaultTextFormat = s_TextFormat;
        s_TextField.text = in_Text;

        //Align
        switch(in_AlignX){
        case ALIGN_LEFT:
            s_TextField.x = in_X;
            break;
        case ALIGN_CENTER:
            s_TextField.x = in_X - s_TextField.textWidth/2;
            break;
        case ALIGN_CENTER:
            s_TextField.x = in_X - s_TextField.textWidth;
            break;
        }
        switch(in_AlignY){
        case ALIGN_UP:
            s_TextField.y = in_Y;
            break;
        case ALIGN_CENTER:
            s_TextField.y = in_Y - s_TextField.textHeight/2;
            break;
        case ALIGN_DOWN:
            s_TextField.y = in_Y - s_TextField.textHeight;
            break;
        }

        //Draw
        out_BMD.draw(s_TextSprite);
    }
}


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

    //Clamp
    static public function Clamp(in_Val:Number, in_Min:Number, in_Max:Number):Number{
        if(in_Val < in_Min){return in_Min;}
        if(in_Max < in_Val){return in_Max;}
        return in_Val;
    }
    static public function Clamp01(in_Val:Number):Number{
        if(in_Val < 0){return 0;}
        if(1 < in_Val){return 1;}
        return in_Val;
    }

    //FloorInt
    public static function FloorInt(in_Val:Number):int{
        var Val:int = int(in_Val);
        if(0 <= in_Val){
            return Val;
        }else{
            return Val-1;
        }
    }
}