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

「チェインフレーション(Chain Inflation)」

半自動的に連鎖が起こり続けるパズルゲーム

操作方法(How To Play)
・ブロックをタッチ(Touch : Block)
 ・ブロックの模様の変更(Change : Pattern)

ルール
・ブロックを縦か横に3つ並べると消える

エフェクト(パーティクル)
・以下のコードを参考に作成
 ・http://wonderfl.net/c/g9s1/

比較用(あとで追加)
・Android版(Air)
 ・https://play.google.com/store/apps/details?id=air.showohealer.game.airprototype
Get Adobe Flash player
by o_healer 31 May 2012
/**
 * 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/qNgu
 */

/*
 「チェインフレーション(Chain Inflation)」
 ・半自動的に連鎖が起こり続けるパズルゲーム

 操作方法(How To Play)
 ・ブロックをタッチ(Touch : Block)
  ・ブロックの模様の変更(Change : Pattern)

 ルール
 ・ブロックを縦か横に3つ並べると消える

 エフェクト(パーティクル)
 ・以下のコードを参考に作成
  ・http://wonderfl.net/c/g9s1/

 比較用(あとで追加)
 ・Android版(Air)
  ・https://play.google.com/store/apps/details?id=air.showohealer.game.airprototype
*/



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 net.wonderfl.utils.WonderflAPI;
 
    [SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
    public class ChainInflation extends Sprite {
        //==Const==

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

        //ブロックを並べる数
        static public const BLOCK_NUM_X:int = 9;//7;//14;
        static public const BLOCK_NUM_Y:int = 8;//6;//12;

        //ブロックの大きさ
        static public const BLOCK_W:int = 48;//64;//32;

        //制限時間
        static public const TIME_LIMIT:Number = 30;

        //パーティクルの数
        static public const PARTICLE_NUM_PER_BLOCK:int = 10;
        static public const PARTICLE_NUM:int = PARTICLE_NUM_PER_BLOCK * BLOCK_NUM_X * BLOCK_NUM_Y;


        //初期配置
        static public const TYPE_ARR:Array = [
            //
            [
                [0,1,0,1],
                [1,0,1,0],
                [0,1,0,1],
                [1,0,1,0],
            ],
            //
            [
                [0,1,0,1],
                [1,1,0,0],
                [0,0,1,1],
                [1,0,1,0],
            ],
        ];


        //==Var==

        //Pseudo Singleton
        static public var Instance:ChainInflation;

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

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

        //パーティクル
        public var m_Particle:Vector.<Particle>;
        public var m_BitmapData_Particle:BitmapData;
        public var m_BitmapData_Glow:BitmapData;
        public var m_Mtx_Glow:Matrix;


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

        //タイマー
        public var m_RestTimer:Number = TIME_LIMIT;
        public var m_TimerUpdateFlag:Boolean = false;//最初のタッチまでは更新しない

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



        //==Function==

        //Init
        public function ChainInflation():void{
            //Pseudo Singleton
            {
                Instance = this;
            }

            //stageを参照できるようになってから初期化する(イベントリスナの追加や画面の大きさの取得のため)
            if(stage != null){
                Init();
            }else{
                addEventListener(
                    Event.ADDED_TO_STAGE,//ステージに追加されたら
                    function(e:Event):void{
                        Init();
                    }
                );
            }
        }
        public function Init():void{
            var i:int;

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

            //BG
            {
                //主にwonderfl用
                addChild(new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000)));
            }

            //Layer
            {
                addChild(m_Layer_BG);
                addChild(m_Layer_Block);
                addChild(m_Layer_Particle);

                m_Layer_Block.x = (VIEW_W - BLOCK_W * BLOCK_NUM_X) / 2;
                m_Layer_Particle.x = m_Layer_Block.x;
            }

            //Block
            {
                m_Block = new Vector.<Vector.<Block> >(BLOCK_NUM_Y);

                for(var yy:int = 0; yy < BLOCK_NUM_Y; ++yy){
                    m_Block[yy] = new Vector.<Block>(BLOCK_NUM_X);
                    for(var xx:int = 0; xx < BLOCK_NUM_X; ++xx){
                        var block:Block = new Block();
                        block.SetType(TYPE_ARR[0][yy % 4][xx % 4]);

                        block.x = xx * BLOCK_W;
                        block.y = yy * BLOCK_W;

                        m_Layer_Block.addChild(block);

                        m_Block[yy][xx] = block;
                    }
                }
            }

            //Particle
            {
                m_Particle = new Vector.<Particle>(PARTICLE_NUM);
                for(i = 0; i < PARTICLE_NUM; ++i){
                    m_Particle[i] = new Particle();
                }
            }
            //
            {
                m_BitmapData_Particle = new BitmapData(VIEW_W, VIEW_H, true, 0x00000000);
                m_Layer_Particle.addChild(new Bitmap(m_BitmapData_Particle));

                m_BitmapData_Glow = new BitmapData(VIEW_W/4, VIEW_H/4, false, 0x000000);
                var bmp_glow:Bitmap = new Bitmap(m_BitmapData_Glow, PixelSnapping.NEVER, true);
                bmp_glow.scaleX = bmp_glow.scaleY = 4;
                bmp_glow.blendMode = BlendMode.ADD;
                m_Layer_Particle.addChild(bmp_glow);

                m_Mtx_Glow = new Matrix(0.25, 0, 0, 0.25, 0,0);
            }

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

                m_Text_Score.x = 12;
                m_Text_Score.y = VIEW_H - 32;

                addChild(m_Text_Score);

                //Reset
                AddScore(0);
            }
            {
                m_Text_Time.selectable = false;
                m_Text_Time.autoSize = TextFieldAutoSize.LEFT;
                m_Text_Time.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);
                m_Text_Time.text = "Time : " + TIME_LIMIT;
                m_Text_Time.filters = [new GlowFilter(0x00FFFF,1.0, 8,8)];

                m_Text_Time.x = VIEW_W - m_Text_Time.textWidth - 12;
                m_Text_Time.y = VIEW_H - 32;

                addChild(m_Text_Time);
            }

            //Touch
            {
                stage.addEventListener(MouseEvent.MOUSE_DOWN,    OnMouseDown);
            }

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

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

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

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

            if(Update_Timer(DeltaTime)){
                return;
            }

            Check_Vanish();

            Update_Block(DeltaTime);

            Update_Particle(DeltaTime);
        }

        //Update : Timer
        public function Update_Timer(in_DeltaTime:Number):Boolean{
            if(! m_TimerUpdateFlag){
                return false;
            }

            if(m_RestTimer <= 0){
                return true;
            }

            m_RestTimer -= in_DeltaTime;

            if(m_RestTimer <= 0){
                //Time Up

                m_Text_Time.text = "Time Up!!";

                ScoreWindowLoader.show(m_Score);

                return true;
            }

            m_Text_Time.text = "Time : " + int(m_RestTimer + 0.999999);

            return false;
        }

        //Update : CheckVanish
        public function Check_Vanish():void{
            var last_type:int;
            var connect_count:int;

            var i:int;
            var xx:int;
            var yy:int;
            var block:Block;

            //横のつながりのチェック
            for(yy = 0; yy < BLOCK_NUM_Y; ++yy){
                last_type = -1;
                connect_count = 0;

                for(xx = 0; xx < BLOCK_NUM_X; ++xx){
                    block = m_Block[yy][xx];

                    if(block.m_Mode != Block.MODE_FALL){
                        if(block.m_Type == last_type){
                            ++connect_count;

                            //3つ以上並んでたら消す
                            if(3 == connect_count){
                                for(i = xx-2; i <= xx; ++i){
                                    //m_Block[yy][i].Vanish();
                                    Vanish(i, yy);
                                }
                            }
                            if(3 < connect_count){
                                //m_Block[yy][xx].Vanish();
                                Vanish(xx, yy);
                            }
                        }else{
                            //つながってない
                            last_type = block.m_Type;
                            connect_count = 1;
                        }
                    }else{
                        //つながってない
                        last_type = -1;
                        connect_count = 0;
                    }
                }
            }

            //縦のつながりのチェック
            //- 下からチェックしていき、空間があればそれ以降はチェックしない(落下中のやつはムシ)
            for(xx = 0; xx < BLOCK_NUM_X; ++xx){
                last_type = -1;
                connect_count = 0;

                for(yy = BLOCK_NUM_Y-1; 0 <= yy; --yy){
                    block = m_Block[yy][xx];

                    if(block.m_Mode != Block.MODE_FALL){
                        if(block.m_Type == last_type){
                            ++connect_count;

                            //3つ以上並んでたら消す
                            if(3 == connect_count){
                                for(i = yy+2; yy <= i; --i){
                                    //m_Block[i][xx].Vanish();
                                    Vanish(xx, i);
                                }
                            }
                            if(3 < connect_count){
                                //m_Block[yy][xx].Vanish();
                                Vanish(xx, yy);
                            }
                        }else{
                            //つながってない
                            last_type = block.m_Type;
                            connect_count = 1;
                        }
                    }else{
                        //つながってない
                        break;//以降はムシ
                    }
                }
            }
        }

        //Do Vanish
        public function Vanish(in_X:int, in_Y:int):void{
            if(m_Block[in_Y][in_X].m_Mode != Block.MODE_WAIT){
                return;
            }

            m_Block[in_Y][in_X].Vanish();

            //Effect
            var particle_offset:int = (in_Y + in_X * BLOCK_NUM_Y) * PARTICLE_NUM_PER_BLOCK;
            for(var i:int = 0; i < PARTICLE_NUM_PER_BLOCK; ++i){
                var particle:Particle = m_Particle[particle_offset + i];

                var offset_x:Number = BLOCK_W/2 - Math.random() * BLOCK_W;
                var offset_y:Number = BLOCK_W/2 - Math.random() * BLOCK_W;

//                particle.m_X = in_X * BLOCK_W + offset_x;
//                particle.m_Y = in_Y * BLOCK_W + offset_y;
                particle.m_X = in_X * BLOCK_W + BLOCK_W/2;
                particle.m_Y = in_Y * BLOCK_W + BLOCK_W/2;

                particle.m_VX = offset_x * 10;
                particle.m_VY = offset_y * 10;

                //particle.m_Color = 
            }
        }

        //Update : Block
        public function Update_Block(in_DeltaTime:Number):void{
            var xx:int;
            var yy:int;
            var i:int;
            var block:Block;

            //Update
            for(yy = 0; yy < BLOCK_NUM_Y; ++yy){
                for(xx = 0; xx < BLOCK_NUM_X; ++xx){
                    block = m_Block[yy][xx];

                    block.Update(in_DeltaTime);

                    //Check : Fall End
                    if(block.m_Mode == Block.MODE_FALL && yy * BLOCK_W <= block.y){
                        block.y = yy * BLOCK_W;
                        block.ChangeMode(Block.MODE_WAIT);
                    }
                }
            }

            //Check Fall
            for(xx = 0; xx < BLOCK_NUM_X; ++xx){
                var fall_flag:Boolean = false;

                for(yy = BLOCK_NUM_Y-1; 0 <= yy; --yy){
                    block = m_Block[yy][xx];

                    if(block.IsEndVanish()){
                        fall_flag = true;

                        //1マスずつ落下させる
                        //- Indexだけ先にズラす
                        for(i = yy; 0 < i; --i){
                            m_Block[i][xx] = m_Block[i-1][xx];
                        }
                        block.y = m_Block[0][xx].y - BLOCK_W;
                        m_Block[0][xx] = block;

                        block.SetType(int(Block.TYPE_NUM * Math.random()));
                        block.ChangeMode(Block.MODE_FALL);

                        ++yy;
                        continue;
                    }

                    if(fall_flag){
                        if(block.m_Mode == Block.MODE_WAIT){
                            block.ChangeMode(Block.MODE_FALL);
                        }
                    }
                }
            }
        }

        //Particle
        public function Update_Particle(in_DeltaTime:Number):void{
            //パーティクルを1ドットずつ描く
            m_BitmapData_Particle.fillRect(m_BitmapData_Particle.rect, 0x00000000);
            m_BitmapData_Particle.lock();
            for(var i:int = 0; i < PARTICLE_NUM; ++i){
                var particle:Particle = m_Particle[i];

                //Coord
                particle.m_X += particle.m_VX * in_DeltaTime;
                particle.m_Y += particle.m_VY * in_DeltaTime;

                //Set
                m_BitmapData_Particle.setPixel32(particle.m_X, particle.m_Y, particle.m_Color);
            }
            m_BitmapData_Particle.unlock();

            //
            m_BitmapData_Glow.fillRect(m_BitmapData_Glow.rect, 0x000000);
            m_BitmapData_Glow.draw(m_BitmapData_Particle, m_Mtx_Glow);
        }

        //Touch
        private function OnMouseDown(e:MouseEvent):void{
            m_TimerUpdateFlag = true;

            for(var yy:int = 0; yy < BLOCK_NUM_Y; ++yy){
                for(var xx:int = 0; xx < BLOCK_NUM_X; ++xx){
                    var block:Block = m_Block[yy][xx];

                    if(block.HitCheck(mouseX, mouseY)){
                        block.FlipType();
                        return;
                    }
                }
            }
        }

        //Add : Score
        public function AddScore(in_Val:int):void{
            m_Score += in_Val;

            m_Text_Score.text = "Score : " + m_Score;
        }
    }
}


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 Block extends Sprite
{
    //==Const==

    //Size
    static public const BLOCK_W:int = ChainInflation.BLOCK_W;

    //Time
    static public const VANISH_TIME:Number = 0.5;

    //
    static public const MAX_SCALE:Number = 2;

    //
    static public const FALL_VY:Number = BLOCK_W * 7.0;

    //Type
    static public var s_TypeIter:int = 0;
    static public const TYPE_SQUARE    :int = s_TypeIter++;
    static public const TYPE_DIAMOND:int = s_TypeIter++;
    static public const TYPE_NUM    :int = s_TypeIter;

    //Mode
    static public var s_ModeIter:int = 0;
    static public const MODE_WAIT    :int = s_ModeIter++;
    static public const MODE_VANISH    :int = s_ModeIter++;
    static public const MODE_FALL    :int = s_ModeIter++;


    //==Var==

    //Type
    public var m_Type:int = 0;

    //Mode
    public var m_Mode:int = 0;
    public var m_ModeTimer:Number = 0;

    //Graphic
    public var m_Bitmap:Bitmap = new Bitmap();
    public var m_SclRoot:Sprite = new Sprite();
    static public var s_BitmapData:Vector.<BitmapData>;


    //==Function==

    //Static Init
    static public function StaticInit():void{
        //Graphic
        {
            s_BitmapData = new Vector.<BitmapData>(TYPE_NUM);

            var shape:Shape = new Shape();
            var g:Graphics = shape.graphics;
            for(var i:int = 0; i < TYPE_NUM; ++i){
                g.clear();

                //Frame
                g.lineStyle(2, 0x000000, 1.0);
                g.drawRect(0,0,BLOCK_W,BLOCK_W);

                //Icon
                var rad:Number = BLOCK_W * 40/100;
                var theta:Number = i * Math.PI/4;
                var color:uint = (i == 0)? 0x00DDFF: 0x00FFDD;
                g.lineStyle(3, color, 1.0);
                g.moveTo(BLOCK_W/2 + rad * Math.cos(theta + Math.PI*0/2), BLOCK_W/2 + rad * Math.sin(theta + Math.PI*0/2));
                g.lineTo(BLOCK_W/2 + rad * Math.cos(theta + Math.PI*1/2), BLOCK_W/2 + rad * Math.sin(theta + Math.PI*1/2));
                g.lineTo(BLOCK_W/2 + rad * Math.cos(theta + Math.PI*2/2), BLOCK_W/2 + rad * Math.sin(theta + Math.PI*2/2));
                g.lineTo(BLOCK_W/2 + rad * Math.cos(theta + Math.PI*3/2), BLOCK_W/2 + rad * Math.sin(theta + Math.PI*3/2));
                g.lineTo(BLOCK_W/2 + rad * Math.cos(theta + Math.PI*4/2), BLOCK_W/2 + rad * Math.sin(theta + Math.PI*4/2));

                //Apply
                s_BitmapData[i] = new BitmapData(BLOCK_W, BLOCK_W, false, 0xEEEEEE);
                s_BitmapData[i].draw(shape);
            }
        }
    }

    //Init
    public function Block(){
        //Graphic
        {
            m_Bitmap.x = -BLOCK_W/2;
            m_Bitmap.y = -BLOCK_W/2;
            m_SclRoot.x = BLOCK_W/2;
            m_SclRoot.y = BLOCK_W/2;
            m_SclRoot.addChild(m_Bitmap);
            addChild(m_SclRoot);
        }
    }

    //Set : Type
    public function SetType(in_Type:int):void{
        //Param
        m_Type = in_Type;

        //Change Graphic
        m_Bitmap.bitmapData = s_BitmapData[m_Type];
    }

    //Flip : Type
    public function FlipType():void{
        if(m_Mode != MODE_WAIT){
            return;
        }

        //Flip
        m_Type = 1 - m_Type;

        //Change Graphic
        m_Bitmap.bitmapData = s_BitmapData[m_Type];
    }

    //Set : Mode
    public function ChangeMode(in_Mode:int):void{
        m_Mode = in_Mode;
        m_ModeTimer = 0;

        m_SclRoot.scaleX = m_SclRoot.scaleY = 1;
        this.alpha = 1;
    }

    //Touch
    public function HitCheck(in_X:int, in_Y:int):Boolean{
        return (this.x <= in_X && in_X < this.x + BLOCK_W && this.y <= in_Y && in_Y < this.y + BLOCK_W);
    }

    //消す処理
    public function Vanish():void{
        if(m_Mode != MODE_WAIT){
            return;
        }

        //Mode
        ChangeMode(MODE_VANISH);

        //++score
        ChainInflation.Instance.AddScore(1);
    }

    //
    public function IsEndVanish():Boolean{
        return (m_Mode == MODE_VANISH) && (VANISH_TIME <= m_ModeTimer);
    }

    //Update
    public function Update(in_DeltaTime:Number):void{
        m_ModeTimer += in_DeltaTime;

        switch(m_Mode){
        case MODE_WAIT:
            break;
        case MODE_VANISH:
            m_SclRoot.scaleX = m_SclRoot.scaleY = Lerp(1, MAX_SCALE, m_ModeTimer/VANISH_TIME);
            this.alpha = 1 - m_ModeTimer/VANISH_TIME;
            break;
        case MODE_FALL:
            this.y += FALL_VY * in_DeltaTime;
            break;
        }
    }

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


class Particle
{
    //==Var==

    //Coord
    public var m_X:int = -1;
    public var m_Y:int = -1;
    public var m_VX:int = 0;
    public var m_VY:int = 0;

    //Color
    public var m_Color:uint = 0xFFFFFFFF;
}


//*
//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 Chain Inflation [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, "Chain Inflation", 1, TWEET);
//        var close: Function = function(e: Event): void
//        {
//            window.removeEventListener(Event.CLOSE, close);
//            closeHandler();
//        }
//        window.addEventListener(Event.CLOSE, close);
        _top.addChild(window);
    }
    
}
//*/