「試作:設定時間によるゲーム性の変化」

by o_healer
ルール
・概要
 ・100回のタッチで100体の隕石を迎撃するゲーム
  ・「白い円:地球」「青い円:バリア」「赤系の円:隕石」という想定
  ・隕石がバリアの範囲に重なっている時にタッチすると隕石を消せる
  ・隕石が地球に到達するとHPが減少
  ・クリックだけでなくキーボードの入力(どれでも良い)でも可能
  ・101回以上のタッチはできないので、きっちり100回で100個消す必要がある
  ・ただし、1回のタッチで複数の隕石を消すことができれば、その分の余裕はできる
・時間の指定
 ・何秒かけて100個の隕石が登場するかを指定
♥0 | Line 500 | Modified 2012-04-12 13:07:53 | MIT License
play

ActionScript3 source code

/**
 * 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/vrp9
 */

/*
 「試作:設定時間によるゲーム性の変化」
 ・時間指定によるゲーム性の変化を観察するための試作
 ・仮題:百断(100 touch)
 ・「100回しか起動できないバリアで100個の隕石から地球を守れ!」的なグラフィックにしたかったがそこまで対応できなかった

 ルール
 ・概要
  ・100回のタッチで100体の隕石を迎撃するゲーム
   ・「白い円:地球」「青い円:バリア」「赤系の円:隕石」という想定
   ・隕石がバリアの範囲に重なっている時にタッチすると隕石を消せる
   ・隕石が地球に到達するとHPが減少
   ・クリックだけでなくキーボードの入力(どれでも良い)でも可能
   ・101回以上のタッチはできないので、きっちり100回で100個消す必要がある
   ・ただし、1回のタッチで複数の隕石を消すことができれば、その分の余裕はできる
 ・時間の指定
  ・何秒かけて100個の隕石が登場するかを指定
  ・時間が短いと大量に発生するので連打ゲーになる
   ・同時に複数消せるので、多少のミスが許容される
  ・時間が長いと1個ずつ出てくるのでタイミングを図るゲームになる
   ・1タッチで必ず1個消す必要があるので、集中する必要がある

 結論とメモ
 ・ゲーム性自体の変化は確認できた
  ・時間を短くした際の連打速度はエネミーの移動速度に依存する
   ・エネミーの移動速度が遅ければ、どんなに時間を短くしても一定以下の連打速度で間に合ってしまう
  ・遅い時は遅い時で一度に2個消そうとして失敗することがある
   ・理屈的には2回タッチすればOKなのだが、ついつい欲張ってしまう
  ・極端なところではなく中途半端な時間が難しかったりする
   ・60秒とかが意外と忙しくて難しい
*/


/*
ToDo


・ガワの決定
 ・地球に落ちてくる隕石をバリアで撃ち落とす
  ・UFOが変な軌道で来たりとか
 ・爆弾を撃ち落とす
  ・表現的に難しい
 ・ドット絵のキャラ
  ・影が楕円だったりして当たり判定がわかりづらい
 →実験なので今回は対応見送り
  ・対応するのであれば地球に隕石が落ちてきてバリアで迎撃するのがベストか
  ・メイドインワリオシリーズみたいな見た目であればさらに良さそう
*/


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

    import com.bit101.components.*;
 
    [SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
    public class GameMain extends Sprite {

        //==Const==

        //画面の大きさ
        static public const VIEW_W:int = 465;
        static public const VIEW_H:int = 465;

        //相手と自弾の数
        static public const TOUCH_NUM:int = 100;

        //指定できる時間の幅
        static public const TIME_MIN:int = 10;
        static public const TIME_MAX:int = 100;

        //HP
        static public const HP_MAX:int = 3;

        //プレイヤーの当たり判定の半径
        static public const PLAYER_RAD:int = 32;
        //迎撃判定の半径
        static public const ATTACK_RAD:int = 64;
        //エネミーの当たり判定の半径
        static public const ENEMY_RAD:int = 16;

        //シーケンス
        static private var SeqIter:int = 0;
        static public const SEQ_SET_TIME_INIT    :int = SeqIter++;
        static public const SEQ_SET_TIME_WAIT    :int = SeqIter++;
        static public const SEQ_SET_TIME_EXIT    :int = SeqIter++;
        static public const SEQ_GAME            :int = SeqIter++;
        static public const SEQ_GAMEOVER        :int = SeqIter++;


        //==Var==

        //Pseudo Singleton
        static public var Instance:GameMain;

        //レイヤー
        public var m_Layer_Root:Sprite = new Sprite();
        public var  m_Layer_BG:Sprite = new Sprite();
        public var  m_Layer_Game:Sprite = new Sprite();
        public var   m_Layer_Character:Sprite = new Sprite();
        public var   m_Layer_GUI:Sprite = new Sprite();
        public var  m_Layer_Setting:Sprite = new Sprite();
        public var  m_Layer_GameOver:Sprite = new Sprite();

        //画像:プレイヤー
        public var m_BitmapData_Player:BitmapData = new BitmapData(2*PLAYER_RAD, 2*PLAYER_RAD, true, 0x00000000);
        //画像:範囲
        public var m_BitmapData_Range:BitmapData = new BitmapData(2*ATTACK_RAD, 2*ATTACK_RAD, true, 0x00000000);
        //画像:背景
        public var m_BitmapData_BG:BitmapData   = new BitmapData(VIEW_W, VIEW_H, false, 0x000000);

        //エネミー
        public var m_Enemy:Vector.<Enemy> = new Vector.<Enemy>(TOUCH_NUM);
        public var m_RestEnemyCount:int = TOUCH_NUM;

        //テキスト
        public var m_Text_Time:TextField = new TextField();
        public var m_Text_Touch:TextField = new TextField();
        public var m_Text_Enemy:TextField = new TextField();
        public var m_Text_HP:TextField = new TextField();

        //GUI
        public var m_TimeSlider:HSlider;
        public var m_StartButton:PushButton;
        public var m_Text_Info:TextField = new TextField();
        public var m_Text_TimeLimit:TextField = new TextField();

        //GameOver
        public var m_Text_GameOver:TextField = new TextField();
        public var m_RestartButton:PushButton;

        //設定された時間制限(秒)
//        public var m_TimeLimit:int = 100;//集中してタイミングを慎重に図る感じのゲーム
        public var m_TimeLimit:int = 30;//適度な判断と連打の具合を要求されるゲーム
//        public var m_TimeLimit:int = 10;//連打開始のタイミングを図りつつ、あとは適度な連打を維持するゲーム

        //開始してからの時間
        public var m_Timer:Number = 0;

        //実際にタッチされた回数
        public var m_TouchCount:int = 0;

        //タッチ検出用のエッジフラグ
        public var m_TouchEdgeFlag:Boolean = false;

        //HP
        public var m_HP:int = HP_MAX;

        //シーケンス
        public var m_SeqIter:int = 0;//最初から


        //==Function==

        //Init
        public function GameMain():void {
            var i:int;
            var bmp:Bitmap;
            var shape:Shape = new Shape();
            var g:Graphics = shape.graphics;

            //Pseudo Singleton
            {
                Instance = this;
            }

            //Static Init
            {
                Enemy.StaticInit();
            }

            //Layer
            {
                //Root
                addChild(m_Layer_Root);
                    //背景
                    m_Layer_Root.addChild(m_Layer_BG);
                    //ゲーム
                    m_Layer_Root.addChild(m_Layer_Game);
                        //キャラ
                        m_Layer_Game.addChild(m_Layer_Character);
                        //GUI
                        m_Layer_Game.addChild(m_Layer_GUI);
                    //時間設定などの画面
                    m_Layer_Root.addChild(m_Layer_Setting);
                    //ゲームオーバー表示
                    m_Layer_Root.addChild(m_Layer_GameOver);
            }

            //GUI
            {
                //Label
                {
                    m_Text_Info.selectable = false;
                    m_Text_Info.autoSize = TextFieldAutoSize.CENTER;
                    m_Text_Info.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);

                    m_Text_Info.x = VIEW_W/2;
                    m_Text_Info.y = 32;

                    m_Text_Info.text = "時間をスライダーで設定、Startで開始";

                    m_Layer_Setting.addChild(m_Text_Info);
                }

                //Label
                {
                    m_Text_TimeLimit.selectable = false;
                    m_Text_TimeLimit.autoSize = TextFieldAutoSize.CENTER;
                    m_Text_TimeLimit.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);
                    m_Text_TimeLimit.filters = [new GlowFilter(0x88FF00,1.0, 4,4)];

                    m_Text_TimeLimit.x = VIEW_W/2;
                    m_Text_TimeLimit.y = VIEW_H/2 - 96;

                    m_Text_TimeLimit.text = "" + m_TimeLimit + "秒";

                    m_Layer_Setting.addChild(m_Text_TimeLimit);
                }

                //m_TimeSlider
                {
                    m_TimeSlider = new HSlider(m_Layer_Setting, VIEW_W/2-100,VIEW_H/2-55);
                    m_TimeSlider.addEventListener(Event.CHANGE, onSetTime);
                    m_TimeSlider.width = 200;

                    //Default
                    m_TimeSlider.value = 100.0 * (m_TimeLimit - TIME_MIN) / (TIME_MAX - TIME_MIN);
                }

                //m_StartButton
                {
                    m_StartButton = new PushButton(m_Layer_Setting, VIEW_W/2-50,VIEW_H/2+20, "Start", onPushStart);
                    m_StartButton.width = 100;
                }
            }

            //背景
            {
                m_Layer_BG.addChild(new Bitmap(m_BitmapData_BG));
            }

            //プレイヤー
            {
                g.clear();
                g.lineStyle(0,0,0);
                g.beginFill(0xFFFFFF, 1.0);
                g.drawCircle(PLAYER_RAD, PLAYER_RAD, PLAYER_RAD);
                g.endFill();
                m_BitmapData_Player.draw(shape);

                bmp = new Bitmap(m_BitmapData_Player);
                bmp.x = VIEW_W/2 - PLAYER_RAD;
                bmp.y = VIEW_H/2 - PLAYER_RAD;

                m_Layer_Character.addChild(bmp);
            }

            //範囲
            {
                g.clear();
                g.lineStyle(1, 0x00FFFF, 1.0);
                g.drawCircle(ATTACK_RAD, ATTACK_RAD, ATTACK_RAD);
                m_BitmapData_Range.draw(shape);

                bmp = new Bitmap(m_BitmapData_Range);
                bmp.x = VIEW_W/2 - ATTACK_RAD;
                bmp.y = VIEW_H/2 - ATTACK_RAD;

                m_Layer_Character.addChild(bmp);
            }

            //Text
            {
                m_Text_Time.selectable = false;
                m_Text_Time.autoSize = TextFieldAutoSize.LEFT;
                m_Text_Time.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);
                m_Text_Time.filters = [new GlowFilter(0x88FF00,1.0, 4,4)];

                m_Text_Time.x = 0;
                m_Text_Time.y = 0;

                m_Layer_GUI.addChild(m_Text_Time);
            }
            {
                m_Text_Touch.selectable = false;
                m_Text_Touch.autoSize = TextFieldAutoSize.LEFT;
                m_Text_Touch.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);
                m_Text_Touch.filters = [new GlowFilter(0x88FF00,1.0, 4,4)];

                m_Text_Touch.x = 0;
                m_Text_Touch.y = 32;

                m_Layer_GUI.addChild(m_Text_Touch);
            }
            {
                m_Text_Enemy.selectable = false;
                m_Text_Enemy.autoSize = TextFieldAutoSize.LEFT;
                m_Text_Enemy.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);
                m_Text_Enemy.filters = [new GlowFilter(0x88FF00,1.0, 4,4)];

                m_Text_Enemy.x = VIEW_W/2;
                m_Text_Enemy.y = 32;

                m_Layer_GUI.addChild(m_Text_Enemy);
            }
            {
                m_Text_HP.selectable = false;
                m_Text_HP.autoSize = TextFieldAutoSize.LEFT;
                m_Text_HP.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);
                m_Text_HP.filters = [new GlowFilter(0x88FF00,1.0, 4,4)];

                m_Text_HP.x = VIEW_W/2;
                m_Text_HP.y = 0;

                m_Layer_GUI.addChild(m_Text_HP);
            }

            //GameOver
            {
                m_Text_GameOver.selectable = false;
                m_Text_GameOver.autoSize = TextFieldAutoSize.CENTER;
                m_Text_GameOver.defaultTextFormat = new TextFormat('Verdana', 32, 0xFFFFFF, true);
                m_Text_GameOver.filters = [new GlowFilter(0xFF0000,1.0, 4,4)];

                m_Text_GameOver.x = VIEW_W/2;
                m_Text_GameOver.y = VIEW_H/2;

                m_Layer_GameOver.addChild(m_Text_GameOver);
            }
            {//m_RetartButton
                m_RestartButton = new PushButton(m_Layer_GameOver, VIEW_W/2-50,VIEW_H*3/4, "Restart", onPushRestart);
                m_RestartButton.width = 100;
            }

            //Touch
            {
                addEventListener(
                    Event.ADDED_TO_STAGE,//ステージに追加されたら
                    function(e:Event):void{
                        //タッチを見る
                        stage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
                        //キー入力も同じ扱いにする
                        stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
                    }
                );
            }

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

            //Refresh
            {
                Refresh();
            }
        }

        public function Reset():void{
            m_Timer = 0;
            m_HP = HP_MAX;
            m_TouchCount = 0;
            m_RestEnemyCount = TOUCH_NUM;
            m_TouchEdgeFlag = false;

            //エネミー
            {
                var i:int;

                var EnemyStartRad:Number = Math.sqrt(VIEW_W*VIEW_W/4 + VIEW_H*VIEW_H/4) + ENEMY_RAD;
                var EnemyX:int = 0;
                var EnemyY:int = 0;
                var PlayerX:int = VIEW_W/2;
                var PlayerY:int = VIEW_H/2;
                var EnemyType:int = 0;
                var EnemyWaitTimer:Number = 0;

                var EnemyPosRad:Number = 2*Math.PI * Math.random();
                for(i = 0; i < TOUCH_NUM; ++i){
                    EnemyPosRad += 0.1*Math.PI + 1.8*Math.PI * Math.random();
                    if(2*Math.PI <= EnemyPosRad){EnemyPosRad -= 2*Math.PI;}

                    EnemyX = VIEW_W/2 + EnemyStartRad * Math.cos(EnemyPosRad);
                    EnemyY = VIEW_H/2 + EnemyStartRad * Math.sin(EnemyPosRad);

                    EnemyType = (int)(Enemy.TYPE_NUM * Math.random());

                    EnemyWaitTimer = (m_TimeLimit - Enemy.GetMoveTime(EnemyType)) * i / TOUCH_NUM;

                    if(m_Enemy[i] == null)
                    {
                        m_Enemy[i] = new Enemy();

                        m_Layer_Character.addChild(m_Enemy[i]);
                    }

                    m_Enemy[i].Reset(EnemyX, EnemyY, PlayerX, PlayerY, EnemyType, EnemyWaitTimer);
                }
            }
        }

        public function Refresh():void{
            //Text
            m_Text_Time.text = "Time : " + int(m_TimeLimit - m_Timer) + "/" + m_TimeLimit;
            m_Text_Touch.text = "Touch : " + (TOUCH_NUM - m_TouchCount) + "/" + TOUCH_NUM;
            m_Text_Enemy.text = "Enemy : " + m_RestEnemyCount + "/" + TOUCH_NUM;
            m_Text_HP.text = "HP : " + m_HP + "/" + HP_MAX;

            m_Text_TimeLimit.text = "" + m_TimeLimit + "秒";
        }

        public function onSetTime(e:Event):void{
            m_TimeLimit = Lerp(TIME_MIN, TIME_MAX, m_TimeSlider.value/100.0);

            Refresh();
        }

        public function onPushStart(e:Event):void{
            if(m_SeqIter == SEQ_SET_TIME_WAIT)
            {
                ++m_SeqIter;
            }
        }

        public function onPushRestart(e:Event):void{
            if(m_SeqIter == SEQ_GAMEOVER){
                m_Layer_GameOver.visible = false;

                m_SeqIter = SEQ_SET_TIME_INIT;
            }
        }

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

            switch(m_SeqIter){
            case SEQ_SET_TIME_INIT    :
                m_Layer_Setting.visible = true;
                m_Layer_Game.visible = false;
                m_Layer_GameOver.visible = false;
                ++m_SeqIter;
                break;
            case SEQ_SET_TIME_WAIT    :
                break;
            case SEQ_SET_TIME_EXIT    :
                Reset();
                Refresh();
                m_Layer_Setting.visible = false;
                m_Layer_Game.visible = true;
                ++m_SeqIter;
                break;
            case SEQ_GAME            :
                Update_Player();
                Update_Enemy(DeltaTime);
                Refresh();
                break;
            case SEQ_GAMEOVER        :
                break;
            }
        }

        //Update : Player
        public function Update_Player():void{
            var i:int;

            //Check : Touch
            {
                if(! m_TouchEdgeFlag){
                    return;
                }

                m_TouchEdgeFlag = false;
            }

            //Check : Count
            {
                if(TOUCH_NUM <= m_TouchCount){
                    return;
                }

                ++m_TouchCount;
            }

            //Check : Enemy
            {
                for(i = 0; i < TOUCH_NUM; ++i){
                    if(m_Enemy[i].m_State != Enemy.STATE_MOVE){
                        continue;
                    }

                    var GapX:int = m_Enemy[i].x - VIEW_W/2;
                    var GapY:int = m_Enemy[i].y - VIEW_H/2;

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

                    if(Distance <= ATTACK_RAD + ENEMY_RAD){
                        //Hit!

                        //Effect
                        //!!

                        //Score
                        //!!

                        //Remove
                        m_Enemy[i].m_State = Enemy.STATE_DONE;
                    }
                }
            }
        }

        //Update : Enemy
        public function Update_Enemy(in_DeltaTime:Number):void{
            m_RestEnemyCount = 0;
            for(var i:int = 0; i < TOUCH_NUM; ++i){
                m_Enemy[i].Update(in_DeltaTime);

                if(m_Enemy[i].m_State != Enemy.STATE_DONE){
                    ++m_RestEnemyCount;

                    var GapX:int = m_Enemy[i].x - VIEW_W/2;
                    var GapY:int = m_Enemy[i].y - VIEW_H/2;

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

                    if(Distance <= PLAYER_RAD + ENEMY_RAD){
                        //Hit!

                        //HP
                        --m_HP;

                        //Remove
                        m_Enemy[i].m_State = Enemy.STATE_DONE;
                    }
                }
            }

            if(m_HP <= 0){
                //GameOver : Failed
                m_HP = 0;
                OnGameFail();
            }
            if(m_RestEnemyCount <= 0){
                //GameOver : Clear
                OnGameClear();
            }
        }

        //GameOver : Clear
        public function OnGameClear():void{
            m_Text_GameOver.text = "CLEAR!!";

            OnGameOver();
        }

        //GameOver : Fail
        public function OnGameFail():void{
            m_Text_GameOver.text = "FAILED..";

            OnGameOver();
        }

        //
        private function OnGameOver():void{
            //Check
            if(m_SeqIter != SEQ_GAME){
                return;
            }

            m_SeqIter = SEQ_GAMEOVER;
            m_TouchEdgeFlag = false;

            m_Layer_GameOver.visible = true;
        }

        //Touch
        public function OnMouseDown(e:Event):void{
            m_TouchEdgeFlag = true;
        }
        //Key
        public function OnKeyDown(e:Event):void{
            m_TouchEdgeFlag = true;
        }

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


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



class Enemy extends Sprite {
    //==Const==

    //Type
    static private var TypeIter:int = 0;
    static public const TYPE_STRAIGHT    :int = TypeIter++;
    static public const TYPE_STOP        :int = TypeIter++;
    static public const TYPE_HISPEED    :int = TypeIter++;
    static public const TYPE_NUM        :int = TypeIter;

    //State
    static private var StateIter:int = 0;
    static public const STATE_WAIT    :int = StateIter++;
    static public const STATE_MOVE    :int = StateIter++;
    static public const STATE_DONE    :int = StateIter++;

    //Graphic
    static private var GraphicIter:int = 0;
    static public const GRAPHIC_STRAIGHT    :int = GraphicIter++;
    static public const GRAPHIC_STOP        :int = GraphicIter++;
    static public const GRAPHIC_HISPEED        :int = GraphicIter++;
    static public const GRAPHIC_NUM            :int = GraphicIter;


    //Move:Stopで止まってる時間
    static public const MOVE_STOP_STOPTIME:Number = 1.0;
    //Move:Stopで衝突何秒前に止まるか
    static public const MOVE_STOP_POSTTIME:Number = 1.5;


    //==Var==

    //Type
    public var m_Type:int = TYPE_STRAIGHT;

    //State
    public var m_State:int = STATE_WAIT;

    //Static Graphic
    static public var m_BitmapData:Vector.<BitmapData> = new Vector.<BitmapData>(GRAPHIC_NUM);

    //Graphic
    public var m_Bitmap:Bitmap = new Bitmap();

    //Pos
    public var m_SrcX:int = 0;
    public var m_SrcY:int = 0;
    public var m_DstX:int = 0;
    public var m_DstY:int = 0;

    //Timer
    public var m_WaitTimer:Number = 0;
    public var m_MoveTimer:Number = 0;


    //==Function==

    //Static Init
    static public function StaticInit():void{
        var shape:Shape = new Shape();
        var g:Graphics = shape.graphics;

        for(var i:int = 0; i < GRAPHIC_NUM; ++i){
            m_BitmapData[i] = new BitmapData(2*GameMain.ENEMY_RAD, 2*GameMain.ENEMY_RAD, true, 0x00000000);

            switch(i){
            case GRAPHIC_STRAIGHT:
            case GRAPHIC_STOP:
                g.clear();
                g.lineStyle(0,0,0);
                g.beginFill(0xFF0000, 1.0);
                g.drawCircle(GameMain.ENEMY_RAD, GameMain.ENEMY_RAD, GameMain.ENEMY_RAD);
                g.endFill();
                break;
            case GRAPHIC_HISPEED:
                g.clear();
                g.lineStyle(0,0,0);
                g.beginFill(0xFF8800, 1.0);
                g.drawCircle(GameMain.ENEMY_RAD, GameMain.ENEMY_RAD, GameMain.ENEMY_RAD);
                g.endFill();
                break;
            }

            m_BitmapData[i].draw(shape);
        }
    }

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

    //Reset
    public function Reset(in_X:int, in_Y:int, in_PlayerX:int, in_PlayerY:int, in_Type:int, in_WaitTime:Number):void{
        //Param
        {
            this.x = in_X;
            this.y = in_Y;

            m_SrcX = in_X;
            m_SrcY = in_Y;

            m_DstX = in_PlayerX;
            m_DstY = in_PlayerY;

            m_Type = in_Type;
            m_WaitTimer = in_WaitTime;

            m_State = STATE_WAIT;
            m_MoveTimer = 0;

            this.alpha = 1;
        }

        //Graphic
        {
            m_Bitmap.bitmapData = m_BitmapData[in_Type];

            //centering
            m_Bitmap.x = -m_Bitmap.width/2;
            m_Bitmap.y = -m_Bitmap.height/2;
        }
    }

    //Param : MoveTime
    static public function GetMoveTime(in_Type:int):Number{
        switch(in_Type){
        case TYPE_STRAIGHT:    return 4;
        case TYPE_STOP:        return GetMoveTime(TYPE_STRAIGHT) + MOVE_STOP_STOPTIME;
        case TYPE_HISPEED:    return GetMoveTime(TYPE_STRAIGHT) * 0.7;
        }

        return 0;//err
    }

    //Update
    public function Update(in_DeltaTime:Number):void{
        switch(m_State){
        case STATE_WAIT:    Update_Wait(in_DeltaTime);    break;
        case STATE_MOVE:    Update_Move(in_DeltaTime);    break;
        case STATE_DONE:    Update_Done(in_DeltaTime);    break;
        }
    }

    //Update : Wait
    public function Update_Wait(in_DeltaTime:Number):void{
        m_WaitTimer -= in_DeltaTime;

        if(m_WaitTimer <= 0){
            m_State = STATE_MOVE;
            m_MoveTimer = -m_WaitTimer;//繰り越し
        }
    }

    //Update : Move
    public function Update_Move(in_DeltaTime:Number):void{
        //Move
        {
            m_MoveTimer += in_DeltaTime;

            var ratio:Number = Clamp01(m_MoveTimer / GetMoveTime(m_Type));

            switch(m_Type){
            case TYPE_STRAIGHT:
            case TYPE_HISPEED:
                this.x = Lerp(m_SrcX, m_DstX, ratio);
                this.y = Lerp(m_SrcY, m_DstY, ratio);
                break;
            case TYPE_STOP:
                {
                    if(m_MoveTimer < GetMoveTime(m_Type)-MOVE_STOP_STOPTIME-MOVE_STOP_POSTTIME){
                        //Pre
                        ratio = Clamp01(m_MoveTimer / (GetMoveTime(m_Type) - MOVE_STOP_STOPTIME));
                    }else if(m_MoveTimer < GetMoveTime(m_Type)-MOVE_STOP_POSTTIME){
                        //Stop
                        ratio = Clamp01((GetMoveTime(m_Type) - MOVE_STOP_STOPTIME - MOVE_STOP_POSTTIME) / (GetMoveTime(m_Type) - MOVE_STOP_STOPTIME));
                    }else{
                        //Post
                        ratio = Clamp01((m_MoveTimer - MOVE_STOP_STOPTIME) / (GetMoveTime(m_Type) - MOVE_STOP_STOPTIME));
                    }
                }
                this.x = Lerp(m_SrcX, m_DstX, ratio);
                this.y = Lerp(m_SrcY, m_DstY, ratio);
                break;
            }
        }

        //Check : Hit
        //!!
    }

    //Update : Done
    public function Update_Done(in_DeltaTime:Number):void{
        this.alpha *= 0.9;
    }

    //Util : Clamp
    static public function Clamp01(in_Val:Number):Number{
        var Val:Number = in_Val;
        if(Val < 0){Val = 0;}
        if(1 < Val){Val = 1;}
        return Val;
    }

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