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

forked from: ぷよぷよ

おじゃまぷよ実装、サイズ変更などなど
本家の とことんぷよぷよ っぽくしてみた

連鎖しすぎると死ぬというのはいかがなものか・・・
[←][↓][→]: 移動
[Z]: 左回転
[X]: 右回転
[C]: 下まで一気に落下
Get Adobe Flash player
by ic_yas 05 Apr 2011
/**
 * Copyright ic_yas ( http://wonderfl.net/user/ic_yas )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gklx
 */

/**
 * GAME :: ぷよぷよ
 * 
 * [←][↓][→]: 移動
 * [Z]: 左回転
 * [X]: 右回転
 * [C]: 下まで一気に落下
 * 
 * できたらいいな、300連鎖♪
 */
package 
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.ShaderParameter;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.ui.Keyboard;
    import flash.utils.getTimer;
    
    import frocessing.math.Random;
    
    [SWF(backgroundColor = "0x555555", frameRate = "30", width = "465", height = "465")]
    public class Puyopuyo extends Sprite 
    {
        private const NUM_W:uint = 6;    // ヨコ 個数
        private const NUM_H:uint = 13;    // タテ 個数
        
        private const BLOCK_SIZE:uint = 15;    // 1ブロックの大きさ
        // 0, 1, 2, 3, 4, 5, 6,
        //白、赤、緑、青、黄、紫、灰
        private const COLOR1:Vector.<uint> = Vector.<uint>([0xffffff, 0xff3300, 0x33dd00, 0x3366dd, 0xffcc00, 0xbb00cc, 0x333344]);
        private const COLOR2:Vector.<uint> = Vector.<uint>([0xffffff, 0xff9966, 0x99ff55, 0x88aaff, 0xffee66, 0xee44ff, 0xbbbbcc]);
        
        private const OJAMA:int = 6;
        /*落下中ぷよの回転状態を表す配列
        0:ぷよ無し
        1:中心(回転軸)となるぷよ
        2:回転するぷよ
        */
        private const BLOCK :Array = 
            [
                [[0, 2, 0],
                 [0, 1, 0],
                 [0, 0, 0]],
                
                [[0, 0, 0],
                 [0, 1, 2],
                 [0, 0, 0]],
                
                [[0, 0, 0],
                 [0, 1, 0],
                 [0, 2, 0]],
                
                [[0, 0, 0],
                 [2, 1, 0],
                 [0, 0, 0]]
            ];
        
        
        private var phase:int;
        private var map  :Vector.<Vector.<Puyo>>;
        
        private var bmd:BitmapData;
        private var bmp:Bitmap;
        
        private var nowX:int = int((NUM_W - 3) / 2);
        private var nowY:int = 0;
        private var num :int = 0;    // BLOCK 番号
        
        private var maxH:Vector.<int> = new Vector.<int>(NUM_W);    //列ごとのぷよを積める高さ
        private var tmpH:Vector.<int> = new Vector.<int>(NUM_W);    //
        private var ojamaH:Vector.<int> = new Vector.<int>(NUM_W);    //おじゃまぷよデータ
        
        private var numColor    :int = 4;    //出現する色の数
        private var nowCols :Vector.<int> = Vector.<int>([rand(numColor), rand(numColor)]);
        private var nextCols:Vector.<int> = Vector.<int>([rand(numColor), rand(numColor)]);
        
        private var que :Vector.<Puyo> = new Vector.<Puyo>();
        private var ojamaQue :Vector.<Puyo> = new Vector.<Puyo>();
        private var isChain :Boolean = false;
        
        private var interval    :int = 30;
        private var intervalCt    :int = 0;
        private var time        :int = 0;
        
        private var ojamaInterval    :int =10;
        private var ojamaIntervalCt    :int =0;
        private var ojamaStack        :int =0;
        private var ojamaFlag        :Boolean = false;
        
        private var chainCt :uint;
        private var status  :Status;
        private var mapRect :Rectangle = new Rectangle(0, 1, NUM_W, NUM_H);
        
        private var keyFlags  :Array = new Array();
        private var keyCounts :Array = new Array();
        
        private var tf :TextField = new TextField();
        
        private var DebugTime:int=0;
        
        public function Puyopuyo():void 
        {
            bmd = new BitmapData(NUM_W + 5, NUM_H, false, 0x555555);
            bmp = new Bitmap(bmd);
            bmp.scaleX = bmp.scaleY = BLOCK_SIZE;
            addChild(bmp);
            
            // map 初期化
            map = new Vector.<Vector.<Puyo>>(NUM_H);
            for (var i :int = 0; i < NUM_H; i ++)
            {
                map[i] = new Vector.<Puyo>(NUM_W);
                for (var j :int = 0; j < NUM_W; j ++)
                {
                    var puyo :Puyo = new Puyo();
                    puyo.x = j;
                    puyo.y = i;
                    map[i][j] = puyo;
                }
            }
            
            status = new Status();
            //status.addScore(0);
            //status.setChain(0);
            addChild(status);
            
            status.x = status.y = bmp.x = 15;
            bmp.y = int(status.y + status.height + 5);
            
            tf.defaultTextFormat = new TextFormat("_sans", 10, 0xffffff); tf.autoSize = "left"; tf.selectable = false;
            tf.text = "CLICK TO START"; tf.x = (465 - tf.width) / 2; tf.y = (465 - tf.height) / 2;
            addChild(tf);
            
            stage.addEventListener(MouseEvent.CLICK, clickHandler);
        }
        private function clickHandler(e:MouseEvent = null):void
        {
            tf.visible = false;
            
            // 次手表示
            bmd.fillRect(new Rectangle(NUM_W + 1, 1, 3, 4), 0xffffff);
            bmd.setPixel(NUM_W + 2, 2, COLOR1[nextCols[1]]);
            bmd.setPixel(NUM_W + 2, 3, COLOR1[nextCols[0]]);
            
            // 配列初期化
            for (var i :int = 0; i < NUM_H; i ++)
                for (var j :int = 0; j < NUM_W; j ++)
                    map[i][j].type = 0;
            
            for (i = 0; i < NUM_W; i ++) { maxH[i] = NUM_H - 1; tmpH[i] = -1; }
            
            status.reset();
            interval = 30;
            phase = 1;
            render();
            
            stage.removeEventListener(MouseEvent.CLICK, clickHandler);
            stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
        }
        /* ENTER FRAME */
        private function enterFrameHandler(e:Event):void
        {
            
            if (phase == 1)     loopPhase1(); /* phase1 (操作) */
            else if(phase == 2) {loopPhase2();} /* phase2 (探索, 落下) */
        }
        private function loopPhase1():void
        {
            intervalCt ++;
            time++;
            
            // スコアによって落下速度アップ
            interval = 31 - status.level;
            
            // 落下速度アップ(とりあえずなし)
            // time ++; if (time % 1800 == 0) interval = (2 <= interval)? interval - 1:1;
            
            //var tmp:int = (nowY != 0)? interval:Math.max(NUM_W, interval);
            var tmp:int = interval;
            if (keyFlags[37]) if (keyCounts[37]++ == 0 || 4 < keyCounts[37]) move(-1);    //左移動
            if (keyFlags[39]) if (keyCounts[39]++ == 0 || 4 < keyCounts[39]) move(1);    //右移動
            if (keyFlags[90]) if (keyCounts[90]++ == 0 || 4 < keyCounts[90]) rotate();    //左回転
            if (keyFlags[88]) if (keyCounts[88]++ == 0 || 4 < keyCounts[88]) rotate(true);    //右回転
            if (keyFlags[40]) move(1, true, true);    //落下
            if (keyFlags[67]) while(phase==1) move(1, true, true); //高速落下
            
            if (tmp <= intervalCt) { move(1, true); intervalCt = 0; } //自然落下
        }
        private function loopPhase2():void
        {
            intervalCt ++;
            switch ( intervalCt )
            {
                case  3: fallPuyo();        break;
                case  9: searchStep();    break;
                case 18: fallStep();    break;
            }
        }
        /* 移動 */
        private function move ( n :int, isY :Boolean = false, isScore :Boolean = false ) :void
        {
            if ( ! isY ) /* x 方向 */
            {
                if ( ! check(BLOCK[num], nowX + n, nowY) ) nowX += n;
            }
            else /* y 方向 */
            {
                DebugTime = getTimer();
                if (isScore) status.addScore(1);
                
                if ( ! check(BLOCK[num], nowX, nowY + n) ){
                    nowY += n;
                    
                }
                else {
                    intervalCt = 0;
                    phase = 2;
                    return;
                }
            }
            
            render();
        }
        /* 回転 */
        private function rotate ( isRight :Boolean = false ) :void
        {
            var nn :int;
            if (isRight)    nn = (num + 1 < 4)? num + 1:0;
            else            nn = (0 <= num - 1)? num - 1:3;
            
            var tmp :int = num; num = nn;
            if ( check(BLOCK[nn], nowX, nowY) )
            {
                if ( nn == 2 ) nowY --;
                else if ( nn == 1 || nn == 3 )
                {
                    if ( ! check(BLOCK[nn], nowX + (nn - 2), nowY) ) nowX += (nn - 2);
                    else
                    {//1ぷよ分のスキマに入ったとき
                        num = - (tmp - 2);         //回転可
                        //num = tmp ;             //こうすると回転不可
                        if ( check(BLOCK[num], nowX, nowY) ) nowY --;    //ぷよ最下段時で、nowY-- しないと下部画面外に出てしまう
                    }
                }
            }
            render();
        }
        /* ぷよ接地ステップ */
        private function fallPuyo () :void
        {
            var px :int, py :int;
            var ar :Array = BLOCK[num];
            
            chainCt = 0;
            
            for (var i :int = 2; 0 <= i; i --)
            {
                py = i + nowY;
                for (var j :int = 0; j < 3; j ++)
                {
                    px = j + nowX;
                    if ( 0 < ar[i][j] )
                    {
                        map[py][px].type = nowCols[ar[i][j] - 1];
                        fall( px, py );
                        
                        if (tmpH[px] < maxH[px] + 1) tmpH[px] = maxH[px] + 1;
                    }
                }
            }
            render();
        }
        /* 探索ステップ */
        private function searchStep ():void
        {
            var i :int, j :int;
            var tH :Vector.<int> = Vector.<int>(tmpH.concat()); // Vector コピー
            for (i = 0; i < NUM_W; i ++) tmpH[i] = -1;    // 初期化
            
            for (i = 0; i < NUM_W; i ++)
            {
                if (tH[i] == -1) continue;
                for (j = tH[i]; 0 <= j; j --) search(i, j);
            }
            render();
        }
        /* 落下ステップ */
        private function fallStep ():void
        {
            var i :int, j :int;
            
            if (isChain)    // 1 箇所でも消えた
            {
                chainCt ++;
                
                for (i = 0; i < NUM_W; i ++)
                {
                    if (tmpH[i] == -1) continue;
                    for (j = tmpH[i]; 0 <= j; j --) fall(i, j);
                }
                isChain = false;
                intervalCt = 4;
            }
            else
            {
                //おじゃまぷよ落下処理
                if(ojamaFlag){
                    setOjama();
                    ojamaFlag=false;
                    status.removeOjamaCaution();
                }
                else ojamaIntervalCt++;
                
                if(ojamaIntervalCt >= ojamaInterval && ojamaStack >0){
                    ojamaFlag =true; 
                    status.addOjamaCaution(ojamaStack);
                }
                
                nowX = int((NUM_W - 3) / 2);
                nowY = 0;
                
                num = 0;
                intervalCt = 0;
                
                //setNumColor();
                nowCols[0] = nextCols[0]; nextCols[0] = rand(numColor);
                nowCols[1] = nextCols[1]; nextCols[1] = rand(numColor);
                
                bmd.setPixel(NUM_W + 2, 2, COLOR1[nextCols[1]]);
                bmd.setPixel(NUM_W + 2, 3, COLOR1[nextCols[0]]);
                
                if (!check(BLOCK[num], nowX, nowY))        phase = 1;
                else                                    gameover();
            }
            render();
            status.setChain(chainCt);
        }
        private function gameover ():void
        {
            tf.visible = true;
            stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
            stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            stage.addEventListener(MouseEvent.CLICK, clickHandler);
        }
        /* 落下 */
        private function fall (nx:int, ny:int) :void
        {
            var nn :int = maxH[nx];
            
            if (0 <= nn && 0 < map[ny][nx].type)
            {
                if (nn != ny)
                {
                    map[nn][nx].type = map[ny][nx].type;
                    map[ny][nx].type = 0;
                }
                maxH[nx] = nn - 1;
            }
        }
        /* 描画 */
        private function render ( ) :void
        {
            bmd.lock();
            bmd.fillRect(mapRect, COLOR1[0]);
            
            for (var i :int = 1; i < NUM_H; i ++)
                for (var j :int = 0; j < NUM_W; j ++)
                {
                    if(map[i][j].type == 0 && (i+j)%2 == 0) 
                        bmd.setPixel(j, i, 0xEFEFEF);    //空白の色を1マスごとに変える
                    else
                        bmd.setPixel(j, i, COLOR1[map[i][j].type]);
                }
            if (phase == 1)
            {
                var px:int, py:int;
                var ar :Array = BLOCK[num];
                
                for (i = 0; i < 3; i ++)
                {
                    py = i + nowY;
                    for (j = 0; j < 3; j ++)
                    {
                        px = j + nowX;
                        if ( 0 < ar[i][j] )
                        {
                            var n:int = ((num == 0 && ar[i][j] == 2) || (num == 2 && ar[i][j] == 1))? 1:0;    //一番高い落下中ぷよ
                            if(maxH[px]- n > 0)    //(上から)0段目は描画しない
                                bmd.setPixel(px, maxH[px] - n, COLOR2[nowCols[ar[i][j] - 1]]);    //落下地点表示
                            if(py != 0)            //(上から)0段目は描画しない
                                bmd.setPixel(px, py, COLOR1[nowCols[ar[i][j] - 1]]);            //落下中ぷよ表示
                            /*
                            // 落下中ぷよの中心ぷよを光らせてみたかった
                            var tmpColor:uint = (ar[i][j] == 1 && (time%60)<=30 )? COLOR2[nowCols[ar[i][j] - 1]]:COLOR1[nowCols[ar[i][j] - 1]];
                            bmd.setPixel(px, py, tmpColor);            //落下中ぷよ表示
                            */
                        }
                    }
                }
            }
            bmd.unlock();
        }
        /* 衝突チェック */
        private function check(ar:Array, nx:int, ny:int):Boolean
        {
            var px :int, py :int;
            
            for (var i :int = 0; i < 3; i ++)
            {
                py = i + ny;
                for (var j :int = 0; j < 3; j ++)
                {
                    px = j + nx;
                    if ( 0 < ar[i][j] )
                    {
                        if ((px < 0 || NUM_W <= px) || (py < 0 || NUM_H <= py)) return true; // 壁
                        if (0 < map[py][px].type) return true; // ぷよ
                    }
                }
            }
            return false;
        }
        /* ぷよ消し 探索開始 */
        private function search(nx:int, ny:int):void
        {
            if (map[ny][nx].type == 0) return;
            
            searchLoop(map[ny][nx].type, nx, ny); /* 再帰探索 */
            
            if (que.length >=4) // 4 連結以上
            {
                // score 加算
                status.addScore( generateScore(que.length, chainCt) );
                //おじゃまぷよ加算
                generateOjama(que.length, chainCt);
                deletePuyo(que)
                deletePuyo(ojamaQue)
                /*
                while (que.length != 0)
                {
                var p:Puyo = que.pop();
                p.flag = false;
                p.type = 0;
                
                tmpH[p.x] = maxH[p.x] = Math.max(maxH[p.x], p.y);
                }
                isChain = true;
                */
            }
            else
            {
                while (que.length != 0) que.pop().flag = false;
                while (ojamaQue.length != 0) ojamaQue.pop().flag = false;
            }
        }
        /*ぷよ削除*/
        private function deletePuyo(q:Vector.<Puyo>):void{
            while (q.length != 0)
            {
                var p:Puyo = q.pop();
                p.flag = false;
                p.type = 0;
                
                tmpH[p.x] = maxH[p.x] = Math.max(maxH[p.x], p.y);
            }
            isChain = true;
        }
        /* 再起探索 */
        private function searchLoop(n:int, nx:int, ny:int):void
        {
            //  通常ぷよ and (探索済み or 不一致の場合) 
            if ( map[ny][nx].type!=6 && ( map[ny][nx].flag || n != map[ny][nx].type ) ) return;
            // (上から)0段目の場合 (幽霊連鎖用の処理)
            if (ny == 0) return;
            
            map[ny][nx].flag = true;
            //おじゃまぷよの場合、再帰探索しない
            if (map[ny][nx].type == 6) {
                ojamaQue.push(map[ny][nx]);
                return;
            }else{
                que.push(map[ny][nx]);
            }
            
            if (0 <= nx - 1)    searchLoop(n, nx - 1, ny);
            if (nx + 1 < NUM_W)    searchLoop(n, nx + 1, ny);
            if (0 <= ny - 1)    searchLoop(n, nx, ny - 1);
            if (ny + 1 < NUM_H)    searchLoop(n, nx, ny + 1);
        }
        private function keyDownHandler(e:KeyboardEvent):void
        {
            if (phase != 1) return;
            keyCounts[e.keyCode] = 0;
            keyFlags[e.keyCode] = true;
        }
        private function keyUpHandler(e:KeyboardEvent):void
        {
            keyFlags[e.keyCode] = false;
        }
        
        private function generateScore(len:uint, chain:uint):uint
        {
            var k:uint;
            if (chain == 0)        k = 1;
            else if (chain < 3)    k = chain * 8;
            else                k = (chain - 2) * 32;
            
            if (5 <= len) k += (len - 4) + 1;
            
            return k * (len * 10);
        }
        /*色数指定 (非使用 現在は4色固定)*/
        private function setNumColor():void
        {
            numColor =  4;
            /*
            //色数をレベル10ごとに増やす 
            numColor = int(3+status.level/10);
            numColor = (numColor>5)? 5:numColor;
            */
        }
        private function rand(max:int = 4, min:int = 1):int
        {
            return int(Math.random() * (max - min + 1)) + min;
        }
        
        /*おじゃまぷよ数計算、蓄積*/
        private function generateOjama(len:uint, chain:uint):void{
            var k:uint;
            k= (chain+1) *( len-3 );
            ojamaStack+=k;
            status.ojama = ojamaStack;
            /*
            if (chain <= 1)        k = 1;
            else                k = (chain - 1) * 6;
            
            if (5 <= len)        k += (len - 4) + 1;
            */
        }
        /*おじゃまぷよセット*/
        private function setOjama():void{
            var tmpRowNum:Array = Random.shakedIntegers(NUM_W);
            for(var i:int=0;i<ojamaStack;i++){
                ojamaH[tmpRowNum[i%NUM_W]]++;
                if(i%NUM_W == NUM_W-1) tmpRowNum=Random.shake(tmpRowNum);
            }
            fallOjama();
        }
        /*おじゃまぷよ落下*/
        private function fallOjama():void{
            for(var i:int=0;i<NUM_W;i++){
                if(ojamaH[i]>0){
                    for (var j:int=ojamaH[i];j>0;j--){
                        if(maxH[i] <0) break; 
                        map[maxH[i]][i].type = OJAMA;
                        maxH[i]--
                    }
                }
                ojamaH[i] = 0;
            }
            ojamaIntervalCt = 0;
            ojamaStack = 0;
            status.ojama = ojamaStack;
        }
    }
}
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;

class Status extends Sprite
{
    private var _score      :uint = 0;
    private var _chain      :uint = 0;
    private var _level      :uint = 1;
    private var _tfMaxChain :TextField;
    private var _tfScore    :TextField;
    private var _tfLevel     :TextField;
    private var _tfOjama     :TextField;
    private var _tfOjamaCaution:TextField;
    
    public function get score():uint{
        return _score;
    } 
    public function get level():uint{
        return _level;
    } 
    public function set ojama(n:int):void{
        _tfOjama.text = "ojama: " + String(n);
    }
    
    public function Status()
    {
        _tfMaxChain = createTextField(); _tfMaxChain.y = 13;
        _tfScore    = createTextField();
        _tfLevel    = createTextField(); _tfLevel.x = 80;
        _tfOjama    = createTextField(); _tfOjama.x = 80; _tfOjama.y = 13;
        _tfOjamaCaution= createTextField(); _tfOjamaCaution.y = 26;
        addChild(_tfMaxChain);
        addChild(_tfScore);
        addChild(_tfLevel);
        addChild(_tfOjama);
        addChild(_tfOjamaCaution);
    }
    public function reset():void
    {
        _score = 0; _tfScore.text = "score: " + _score;
        _chain = 0; _tfMaxChain.text = "chain: " + _chain;
        _level = 1; _tfLevel.text = "level: " + _level;
        _tfOjama.text = "ojama: 0";
        _tfOjamaCaution.text = "Next Ojama: 0";
        _tfOjamaCaution.visible =false;
    }
    public function addScore(n:uint):void
    {
        _score += n;
        _tfScore.text = "score: " + _score;
        levelup();
    }
    public function setChain(n:uint):void
    {
        if (n < _chain) return;
        _chain = n;
        _tfMaxChain.text = "chain: " + _chain;
    }
    public function addOjamaCaution(n:int):void
    {
        _tfOjamaCaution.text = "Next, "+String(n)+" ojama fall !!";
        _tfOjamaCaution.visible =true;
    }
    public function removeOjamaCaution():void
    {
        _tfOjamaCaution.visible =false;
    }
    
    private function levelup():void{
        //1500点ごとにレベル上昇
        _level = uint(_score/1500)+1;
        _tfLevel.text = "level: " + _level;
    }
    private function createTextField():TextField
    {
        var format :TextFormat = new TextFormat("_等幅", 10, 0xffffff);
        format.letterSpacing = 1;
        
        var tf :TextField = new TextField();
        tf.autoSize = "left";
        tf.defaultTextFormat = format;
        
        return tf;
    }
}
class Puyo
{
    public var type:int = 0;
    public var flag:Boolean = false;
    public var x   :int;
    public var y   :int;
}