Beautifl - Flash Gallery

Preview

アミダ崩し(AMIDA Breakout)
o_healer 2011年10月16日 MIT License
?
操作方法  
・クリック(Click)  
 ・アミダの追加(Add Line)
      /*
 「アミダ崩し」
 ・

 操作方法
 ・クリック(Click)
  ・アミダの追加(Add Line)
*/

/*
 Memo

 アミダは1ドット単位でラインんを管理
 ・実際の表示はラインの大きさでスケーリングをかけるだけ
*/



package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;
    import net.wonderfl.utils.WonderflAPI;
 
    [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 BAR_INIT_X:int = VIEW_W/4;
        static public const BAR_INIT_Y:int = VIEW_H*7/8;

        //アミダの線の太さ
        static public const LINE_W:int = 4;

        //アミダの線の数
        static public const LINE_NUM_X:int = 5;
        static public const LINE_NUM_Y:int = (BAR_INIT_Y - 2*LINE_W)/LINE_W;

        //アミダの線の色
        static public const LINE_COLOR:uint = 0xFF000000;

        //球の色
        static public const BALL_COLOR:uint = 0xFFFFFFFF;

        //ボールの移動パターン
        static public var BallModeIter:int = 0;
        static public const BALL_MODE_U:int = BallModeIter++;
        static public const BALL_MODE_D:int = BallModeIter++;
        static public const BALL_MODE_L:int = BallModeIter++;
        static public const BALL_MODE_R:int = BallModeIter++;

        //ブロックの大きさ
        static public const BLOCK_W:int = (int)(VIEW_W/LINE_NUM_X/LINE_W) * LINE_W;
        static public const BLOCK_H:int = VIEW_H/32;

        //ブロックの数
        static public const BLOCK_NUM_X:int = LINE_NUM_X;
        static public const BLOCK_NUM_Y:int = 8;

        //作業用
        static public const BMP_INIT_OFFSET_X:int = VIEW_W/LINE_NUM_X/LINE_W/2;
        static public const BMP_GAP_X:int = VIEW_W/LINE_NUM_X/LINE_W;
//        static public const AMIDA_INIT_OFFSET_X:int = VIEW_W/LINE_NUM_X/2;
//        static public const AMIDA_GAP_X:int = (int)(VIEW_W/LINE_NUM_X/LINE_W) * LINE_W;
        static public const AMIDA_INIT_OFFSET_X:int = BMP_INIT_OFFSET_X * LINE_W;
        static public const AMIDA_GAP_X:int = BMP_GAP_X * LINE_W;


        //==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_MoveObj:Sprite = new Sprite();
        public var  m_Layer_LineCand:Sprite = new Sprite();

        //画像
        public var m_BitmapData_BG:BitmapData        = new BitmapData(VIEW_W, VIEW_H, false, 0x666666);
        public var m_BitmapData_Amida:BitmapData    = new BitmapData(VIEW_W/LINE_W + 1, VIEW_H/LINE_W + 1, true, 0x00000000);

        //横線候補
        public var m_Bitmap_LineCand:Bitmap;

        //球
        public var m_BallX:int;
        public var m_BallY:int;
        public var m_BallMove:Number = 0;
        public var m_BallMode:int = BALL_MODE_U;
        public var m_BallAttackFlag:Boolean = true;//左右移動後に上昇するか否か

        //バー
        public var m_Bar:Bar;

        //ブロック
        public var m_Blocks:Vector.<Vector.<Block> >;

        //球の移動軌跡用エフェクト
        public var m_Rect_Amida:Rectangle;
        public var m_CT_Amida:ColorTransform;

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

        //スコア
        public var m_Score:int = 0;

        //
        public var m_EndFlag:Boolean = false;


        //==Function==

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

            //Pseudo Singleton
            {
                Instance = this;
            }

            //Static Init
            {
//                ImageManager.Init();
                ScoreWindowLoader.init(this, new WonderflAPI(loaderInfo.parameters));
            }

            //Layer
            {
                //Root
                addChild(m_Layer_Root);

                {
                    //背景
                    m_Layer_Root.addChild(m_Layer_BG);

                    //動くOBJ系
                    m_Layer_Root.addChild(m_Layer_MoveObj);

                    //横線候補の表示レイヤー
                    m_Layer_Root.addChild(m_Layer_LineCand);
                }
            }

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

            //アミダ
            {
                var bmp:Bitmap;

                //基本ライン(縦線)
                var rect:Rectangle = new Rectangle(0,0, 1, VIEW_H);
                for(i = 0; i < LINE_NUM_X; i++){
                    rect.x = BMP_INIT_OFFSET_X + i*BMP_GAP_X;
                    m_BitmapData_Amida.fillRect(rect, LINE_COLOR);
                }

                bmp = new Bitmap(m_BitmapData_Amida);
                bmp.scaleX = LINE_W;
                bmp.scaleY = LINE_W;

                m_Layer_BG.addChild(bmp);
            }

            //横線候補
            //- m_Bitmap_LineCand;
            {
                var bmd:BitmapData;

                const a:uint = 0x30;
                bmd = new BitmapData(VIEW_W/LINE_NUM_X/LINE_W, 1, true, (0x00FFFFFF & LINE_COLOR) | (a << 24));
                m_Bitmap_LineCand = new Bitmap(bmd);

                //最初は範囲外にして擬似非表示
                m_Bitmap_LineCand.x = -100;
                m_Bitmap_LineCand.y = -100;
                m_Bitmap_LineCand.scaleX = LINE_W;
                m_Bitmap_LineCand.scaleY = LINE_W;

                m_Layer_LineCand.addChild(m_Bitmap_LineCand);
            }

            //球
            {
                m_BallX = BMP_INIT_OFFSET_X + (int)((LINE_NUM_X-1)/2)*BMP_GAP_X;
                m_BallY = BAR_INIT_Y/LINE_W;
            }

            //バー
            {
                m_Bar = new Bar();
                m_Bar.x = BAR_INIT_X;
                m_Bar.y = BAR_INIT_Y;

                m_Layer_MoveObj.addChild(m_Bar);
            }

            //ブロック
            {
                m_Blocks = new Vector.<Vector.<Block> >(BLOCK_NUM_Y);
                for(y = 0; y < BLOCK_NUM_Y; y++){
                    m_Blocks[y] = new Vector.<Block>(BLOCK_NUM_X);
                    for(x = 0; x < BLOCK_NUM_X; x++){
                        var hue:Number = 1.0 * x / BLOCK_NUM_X;
                        var saturation:Number = 0.8;
                        var value:Number = 1 - 0.5 * y/BLOCK_NUM_Y;
                        var block:Block = new Block(HSVtoRGB(hue, saturation, value));

                        block.x = x * BLOCK_W;
                        block.y = y * BLOCK_H;

                        m_Blocks[y][x] = block;

                        m_Layer_MoveObj.addChild(block);
                    }
                }
            }

            //エフェクト
            {
                m_Rect_Amida = m_BitmapData_Amida.rect;
                m_CT_Amida = new ColorTransform(0.9, 0.95, 0.98);
            }

            //Text
            {
                m_Text_Score.selectable = false;
                m_Text_Score.autoSize = TextFieldAutoSize.RIGHT;
                m_Text_Score.defaultTextFormat = new TextFormat('Verdana', 16, 0xFFFFFF, true);
                m_Text_Score.text = '0';
                m_Text_Score.filters = [new GlowFilter(0x00FFFF,1.0, 4,4)];

                m_Text_Score.x = VIEW_W - 32;
                m_Text_Score.y = 0;

                addChild(m_Text_Score);
            }
            {
                m_Text.selectable = false;
                m_Text.autoSize = TextFieldAutoSize.LEFT;
                m_Text.defaultTextFormat = new TextFormat('Verdana', 60, 0xFFFFFF, true);
                m_Text.text = '';
                m_Text.filters = [new GlowFilter(0x00FFFF,1.0, 8,8)];

                addChild(m_Text);
            }

            //Mouse
            {
                stage.addEventListener(MouseEvent.MOUSE_MOVE, OnMouseMove);
                stage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
            }

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

            //Debug : For Wonderfl Screenshot
            {
                stage.addEventListener(KeyboardEvent.KEY_DOWN, function(event:KeyboardEvent):void{
                    if(event.ctrlKey && event.shiftKey && event.altKey && event.keyCode == 65){
                        m_Layer_Root.y = VIEW_H/4;
                    }else{
                        m_Layer_Root.y = 0;
                    }
                });
            }
        }

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

            if(m_EndFlag){return;}

            //Bar
            m_Bar.Update(DeltaTime);

            //Ball
            Update_Ball(DeltaTime);

            //Block
            Update_Block(DeltaTime);
        }

        //Update : Block
        public function Update_Block(DeltaTime:Number):void{
            var AllClearFlag:Boolean = true;
            m_Score = 0;
            for(var y:int = 0; y < BLOCK_NUM_Y; y++){
                for(var x:int = 0; x < BLOCK_NUM_X; x++){
                    var block:Block = m_Blocks[y][x];
                    block.Update(DeltaTime);

                    if(block.IsExist()){
                        AllClearFlag = false;
                    }else{
                        ++m_Score;
                    }
                }
            }

            //Score
            {
                m_Text_Score.text = m_Score.toString();
            }

            if(AllClearFlag){
                OnGoal();
            }
        }

        public function OnFail():void{
            m_EndFlag = true;

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

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

            //スコア表示に移る
            ScoreWindowLoader.show(m_Score);
        }

        public function OnGoal():void{
            m_EndFlag = true;

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

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

            //スコア表示に移る
            ScoreWindowLoader.show(m_Score);
        }

        //Update : Ball
        public function Update_Ball(DeltaTime:Number):void{
            var Vel:Number = 30;
            m_BallMove += Vel * DeltaTime;

            while(1 <= m_BallMove){
                m_BallMove -= 1;

                switch(m_BallMode){
                case BALL_MODE_U:
                    //1ドット上に進む
                    --m_BallY;
                    //移動先にブロックがあれば反転
                    if(HitCheckBlock()){
                        m_BallMode = BALL_MODE_D;
                        m_BallAttackFlag = false;
                        break;
                    }
                    //左右にラインがあれば次の移動はそちらに進む
                    if(IsLine(m_BallX-1, m_BallY)){
                        m_BallMode = BALL_MODE_L;
                        break;
                    }
                    if(IsLine(m_BallX+1, m_BallY)){
                        m_BallMode = BALL_MODE_R;
                        break;
                    }
                    //移動先にラインがなければ反射
                    if(! IsLine(m_BallX, m_BallY-1)){
                        m_BallMode = BALL_MODE_D;
                        m_BallAttackFlag = false;
                    }
                    break;
                case BALL_MODE_D:
                    //1ドット下に進む
                    ++m_BallY;
                    //移動先にブロックがあれば壊すだけ
                    if(HitCheckBlock()){
                        //上の関数内だけで完結
                    }
                    //左右にラインがあれば次の移動はそちらに進む
                    if(IsLine(m_BallX-1, m_BallY)){
                        m_BallMode = BALL_MODE_L;
                        break;
                    }
                    if(IsLine(m_BallX+1, m_BallY)){
                        m_BallMode = BALL_MODE_R;
                        break;
                    }
                    //移動先にバーがあれば反射
                    if(m_Bar.IsRange(m_BallX * LINE_W, m_BallY * LINE_W)){
                        m_BallMode = BALL_MODE_U;
                        m_BallAttackFlag = true;
                    }
                    //移動先にラインがなければ終了
                    if(! IsLine(m_BallX, m_BallY+1)){
                        OnFail();
                    }
                    break;
                case BALL_MODE_L:
                    //1ドット左に進む
                    --m_BallX;
                    //移動先にブロックがあれば反転
                    if(HitCheckBlock()){
                        m_BallMode = BALL_MODE_R;
                        m_BallAttackFlag = false;
                        break;
                    }
                    //上下にラインがあれば次の移動はそちらに進む
                    if(m_BallAttackFlag){//上に移動すべき場合
                        if(IsLine(m_BallX, m_BallY-1)){
                            m_BallMode = BALL_MODE_U;
                        }
                    }else{//下に移動すべき場合
                        if(IsLine(m_BallX, m_BallY+1)){
                            m_BallMode = BALL_MODE_D;
                        }
                    }
                    //ただし連続横移動の方を優先する
                    if(IsLine(m_BallX-1, m_BallY)){
                        m_BallMode = BALL_MODE_L;
                    }
                    break;
                case BALL_MODE_R:
                    //1ドット右に進む
                    ++m_BallX;
                    //移動先にブロックがあれば反転
                    if(HitCheckBlock()){
                        m_BallMode = BALL_MODE_L;
                        m_BallAttackFlag = false;
                        break;
                    }
                    //上下にラインがあれば次の移動はそちらに進む
                    if(m_BallAttackFlag){//上に移動すべき場合
                        if(IsLine(m_BallX, m_BallY-1)){
                            m_BallMode = BALL_MODE_U;
                        }
                    }else{//下に移動すべき場合
                        if(IsLine(m_BallX, m_BallY+1)){
                            m_BallMode = BALL_MODE_D;
                        }
                    }
                    //ただし連続横移動の方を優先する
                    if(IsLine(m_BallX+1, m_BallY)){
                        m_BallMode = BALL_MODE_R;
                    }
                    break;
                }

                ApplyFilter();
            }
        }

        //Effect
        public function ApplyFilter():void{
            m_BitmapData_Amida.colorTransform(m_Rect_Amida, m_CT_Amida);
            m_BitmapData_Amida.setPixel32(m_BallX, m_BallY, BALL_COLOR);
        }


        //Mouse : Move
        public function OnMouseMove(event:MouseEvent):void{
            var IndexX:int = (mouseX - AMIDA_INIT_OFFSET_X) / AMIDA_GAP_X;
            var IndexY:int = mouseY / LINE_W;

            //Range
            if(IndexX < 0){IndexX = 0;}
            if(LINE_NUM_X-1 <= IndexX){IndexX = LINE_NUM_X-2;}
            if(IndexY < 0){IndexY = 0;}
            if(LINE_NUM_Y <= IndexY){IndexY = LINE_NUM_Y-1;}

            //Pos
            m_Bitmap_LineCand.x = AMIDA_INIT_OFFSET_X + IndexX * AMIDA_GAP_X;
            m_Bitmap_LineCand.y = IndexY * LINE_W;
        }

        //Mouse : Down
        public function OnMouseDown(event:MouseEvent):void{
            //ラインの(Bitmap上での)位置
            var src_x:int;
            var dst_x:int;
            var y:int;
            {
                var IndexX:int = (mouseX - AMIDA_INIT_OFFSET_X) / AMIDA_GAP_X;
                var IndexY:int = mouseY / LINE_W;

                //Range
                if(IndexX < 0){IndexX = 0;}
                if(LINE_NUM_X-1 <= IndexX){IndexX = LINE_NUM_X-2;}
                if(IndexY < 0){IndexY = 0;}
                if(LINE_NUM_Y <= IndexY){IndexY = LINE_NUM_Y-1;}

                src_x = BMP_INIT_OFFSET_X + IndexX*BMP_GAP_X;
                dst_x = src_x + BMP_GAP_X;

                src_x += 1;
                dst_x -= 1;

                y = IndexY;
            }

            //ラインカラー(オン・オフ)
            var color:uint;
            {
                color = LINE_COLOR;
//                if(IsLine((src_x+dst_x)/2, y)){
//                    color = 0x00000000;
//                }
                //→オフはなくしてみた
            }

            //反映
            for(var x:int = src_x; x <= dst_x; x++){
                m_BitmapData_Amida.setPixel32(x, y, color);
            }
        }

        //
        public function IsLine(in_X:int, in_Y:int):Boolean{
            return (m_BitmapData_Amida.getPixel32(in_X, in_Y) & 0xFF000000) != 0x00000000;
        }

        //
        public function HitCheckBlock():Boolean{
            var BallX:int = m_BallX * LINE_W;
            var BallY:int = m_BallY * LINE_W;

            for(var y:int = 0; y < BLOCK_NUM_Y; y++){
                for(var x:int = 0; x < BLOCK_NUM_X; x++){
                    var block:Block = m_Blocks[y][x];

                    if(! block.IsExist()){continue;}

                    if(block.IsRange(BallX, BallY)){
                        block.Vanish();

                        return true;
                    }
                }
            }

            //それっぽいブロックがなかったのでノーヒット
            return false;
        }


        //Utility
        static public function Lerp(in_Src:Number, in_Dst:Number, in_Ratio:Number):Number{
            return (in_Src * (1 - in_Ratio)) + (in_Dst * in_Ratio);
        }
        static public function HSVtoRGB(in_Hue:Number, in_Saturation:Number, in_Value:Number):uint{
            var r:uint;
            var g:uint;
            var b:uint;

            //色
            {
                //赤~黄、黄~緑、緑~青緑、青緑~青、青~紫、紫~赤の6フェイズ
                const calcVal:Function = function(in_Ratio:Number):uint{
                    if(in_Ratio > 1.0){in_Ratio -= 1.0;}

                    if(in_Ratio < 1.0/6.0){return 0xFF;}
                    if(in_Ratio < 2.0/6.0){return 0xFF * (2.0 - in_Ratio*6.0);}
                    if(in_Ratio < 3.0/6.0){return 0x00;}
                    if(in_Ratio < 4.0/6.0){return 0x00;}
                    if(in_Ratio < 5.0/6.0){return 0xFF * (in_Ratio*6.0 - 4.0);}
                    if(in_Ratio < 6.0/6.0){return 0xFF;}
                    return 0xFF;//err
                }

                r = calcVal(in_Hue + 0.0/3.0);
                g = calcVal(in_Hue + 2.0/3.0);
                b = calcVal(in_Hue + 1.0/3.0);
            }

            //彩度計算
            {
                r = Lerp(0xFF, r, in_Saturation);
                g = Lerp(0xFF, g, in_Saturation);
                b = Lerp(0xFF, b, in_Saturation);
            }

            //明度計算
            {
                r *= in_Value;
                g *= in_Value;
                b *= in_Value;
            }

            return (0xFF << 24) | (r << 16) | (g << 8) | (b << 0);
        }
    }
}


import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.ui.*;
import net.wonderfl.utils.WonderflAPI;


class MoveObj extends Sprite
{
    //==Var==

    protected var m_Bitmap:Bitmap;
    protected var m_BitmapData:BitmapData;

    protected var m_W:int;
    protected var m_H:int;


    //==Function==

    //Init
    public function MoveObj(in_W:int, in_H:int){
        //Param
        {
            m_W = in_W;
            m_H = in_H;
        }

        //m_BitmapData
        {
            m_BitmapData = new BitmapData(in_W, in_H, true, 0x00000000);

            m_Bitmap = new Bitmap(m_BitmapData);

            addChild(m_Bitmap);
        }
    }

    //Util
    public function IsRange(in_X:int, in_Y:int):Boolean{
        var RelX:int = in_X - this.x - m_Bitmap.x;
        var RelY:int = in_Y - this.y - m_Bitmap.y;

        return (0 <= RelX) && (RelX <= m_W) && (0 <= RelY) && (RelY <= m_H);
    }
}

class Bar extends MoveObj
{
    //==Const==

    static public const W:int = GameMain.VIEW_W/GameMain.LINE_NUM_X * 5/4;
    static public const H:int = GameMain.VIEW_H/32;

    static public const RANGE_X_MIN:int = W/2;
    static public const RANGE_X_MAX:int = GameMain.VIEW_W - W/2;

    static public const VEL:Number = 15;


    //==Var==

    //移動速度
    public var m_VX:Number = VEL;


    //==Function==

    //Init
    public function Bar(){
        //Super
        {
            super(W, H);
        }

        //Centering
        {
            m_Bitmap.x = -W/2;
            m_Bitmap.y = -H/2;
        }

        //Graphic
        {
            m_BitmapData.fillRect(m_BitmapData.rect, 0xFFFFFFFF);
        }
    }

    //Update
    public function Update(DeltaTime:Number):void{
        this.x += m_VX * DeltaTime;

        if(this.x < RANGE_X_MIN){
            this.x = RANGE_X_MIN + (RANGE_X_MIN - this.x);
            m_VX = -m_VX;
        }
        if(RANGE_X_MAX < this.x){
            this.x = RANGE_X_MAX - (this.x - RANGE_X_MAX);
            m_VX = -m_VX;
        }
    }
}

class Block extends MoveObj
{
    //==Const==

    static public const W:int = GameMain.BLOCK_W;
    static public const H:int = GameMain.BLOCK_H;


    //==Var==

    public var m_Color:uint;

    public var m_VanishFlag:Boolean = false;


    //==Function==

    //Init
    public function Block(in_Color:uint){
        //Super
        {
            super(W, H);
        }

        //Param
        {
            m_Color = in_Color;
        }

        //Graphic
        {
            m_BitmapData.fillRect(m_BitmapData.rect, in_Color);
        }
    }

    //Update
    public function Update(DeltaTime:Number):void{
        if(m_VanishFlag){
            this.alpha *= 0.9;
        }
    }

    //
    public function Vanish():void{
        m_VanishFlag = true;
    }

    //
    public function IsExist():Boolean{
        return !m_VanishFlag;
    }
}


//*
//bkzenさんのコードを利用
//@see http://wonderfl.net/c/cuY4
//@see http://wonderfl.net/c/kYyY
class ScoreWindowLoader
{
    private static var _top: DisplayObjectContainer;
    private static var _api: WonderflAPI;
    private static var _content: Object;
    //private static const URL: String = "wonderflScore.swf";
    private static const URL: String = "http://swf.wonderfl.net/swf/usercode/5/57/579a/579a46e1306b5770d429a3738349291f05fec4f3.swf";
    private static const TWEET: String = "Playing Amida Breakout [score: %SCORE%] #wonderfl";
    
    public static function init(top: DisplayObjectContainer, api: WonderflAPI): void 
    {
        _top = top, _api = api;
        var loader: Loader = new Loader();
        var comp: Function = function(e: Event): void
        {
            loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, comp);
            _content = loader.content;
//            handler();
        }
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, comp);
        loader.load(new URLRequest(URL), new LoaderContext(true));
    }

    public static function show( score: int): void
    {
        var window: DisplayObject = _content.makeScoreWindow(_api, score, "Amida Breakout", 1, TWEET);
//        var close: Function = function(e: Event): void
//        {
//            window.removeEventListener(Event.CLOSE, close);
//            closeHandler();
//        }
//        window.addEventListener(Event.CLOSE, close);
        _top.addChild(window);
    }
    
}
//*/