forked from: ぷよ雪

by katopz forked from ぷよ雪 (diff: 8)
ぷよ雪
でっちあげプロトタイプ@November 8, 2009
今後やりたかったこと:
  ・ちゃんとテストする
  ・連鎖だとわかるように一連鎖ずつ消す
  ・落下・連鎖を滑らかに描画する
  ・ASの配列の扱い方を調べて書き直す
  ・ASのイベントと時間の扱い方を調べて書き直す
  ・ASのコーディング規約を調べて書き直す
♥0 | Line 192 | Modified 2011-04-06 14:29:25 | MIT License
play

ActionScript3 source code

/**
 * Copyright katopz ( http://wonderfl.net/user/katopz )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/yUde
 */

// forked from naraba's ぷよ雪
// ぷよ雪
// でっちあげプロトタイプ@November 8, 2009
// 今後やりたかったこと:
//  ・ちゃんとテストする
//  ・連鎖だとわかるように一連鎖ずつ消す
//  ・落下・連鎖を滑らかに描画する
//  ・ASの配列の扱い方を調べて書き直す
//  ・ASのイベントと時間の扱い方を調べて書き直す
//  ・ASのコーディング規約を調べて書き直す
package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    
    [SWF(width="400", height="450", frameRate="30", backgroundColor="0x4444FF")]
    public class PuyoSnow extends Sprite
    {
        private const CELL_WIDTH:int = 10;
        private const CELL_HEIGHT:int = 10;
        private const SCENE_WIDTH:int = 40;
        private const SCENE_HEIGHT:int = 45;
        private const BLANK:int = -1;
        private const FLOOR:int = -2;
        private const MARKING:int = -3;
        private const COLORS:Array = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00];
        private var scene:Array = [];
        private var fallingPairs:Array = [];
        private var topLevelAt:Array = [];
        private var groundLevelAt:Array = [];
        private var fallTimer:Timer = new Timer(20);
        
        public function PuyoSnow()
        {
            Wonderfl.capture_delay(30);
            
            scene = new Array(SCENE_HEIGHT+1).map(function():* {
                return new Array(SCENE_WIDTH).map(function():* {
                    return null;
                })
            });
            for (var i:int = 0; i < SCENE_WIDTH; i++) {
                for (var j:int = 0; j < SCENE_HEIGHT; j++) {
                    scene[i][j] = BLANK;
                }
                scene[i][SCENE_HEIGHT] = FLOOR;
            }
            topLevelAt = new Array(SCENE_WIDTH).map(function():* {
                return SCENE_HEIGHT;
            });
            groundLevelAt = new Array(SCENE_WIDTH).map(function():* {
                return SCENE_HEIGHT;
            });
            stage.addEventListener(Event.ENTER_FRAME, function(e:Event):void {
                draw();
            });
            fallTimer.addEventListener(TimerEvent.TIMER, fallPairs);
            fallTimer.start();
        }

        private function makePair():void
        {
            fallingPairs.push(new Pair(SCENE_WIDTH, COLORS.length));
        }
        
        private function fallPairs(e:TimerEvent):void
        {
            if (Math.random() < .4) { makePair(); }
            for (var i:int = 0; i < fallingPairs.length; i++) {
                var pair:Pair = fallingPairs[i];
                var p1x:int = pair.p1.x;
                var p1y:int = pair.p1.y;
                var p2x:int = pair.p2.x;
                var p2y:int = pair.p2.y;
                if (scene[p1x][p1y+1] != BLANK || scene[p2x][p2y+1] != BLANK) {
                    scene[p1x][p1y] = pair.p1.color;
                    scene[p2x][p2y] = pair.p2.color;
                    topLevelAt[p2x] = p2y;
                    topLevelAt[p1x] = p1y;
                    if (topLevelAt[p2x] <= 0 || topLevelAt[p1x] <= 0) {
                        // どこかが上まで積もったら何も言わずにただ止まる
                        fallTimer.stop();
                    }
                    fallingPairs.splice(i, 1);
                    i -= 1;  // bug fix @ November 12, 2009
                } else {
                    pair.fall();
                }
            }
            do { // 連鎖があってもノータイムで全部消す
                ground();
            } while (vanish());
        }
        
        private function ground():void
        {
            for (var i:int = 0; i < SCENE_WIDTH; i++) {
                for (var j:int = SCENE_HEIGHT; j >= topLevelAt[i]; j--) {
                    if (scene[i][j] != BLANK) {
                        groundLevelAt[i] = j;
                        continue;
                    }
                    var k:int = j - 1;
                    while (scene[i][k] == BLANK && k >= topLevelAt[i]) { k--; }
                    if (scene[i][k] != BLANK) {
                        scene[i][j] = scene[i][k];
                        scene[i][k] = BLANK;
                        groundLevelAt[i] = j;
                    } else {
                        topLevelAt[i] = groundLevelAt[i];
                        break;
                    }
                }
            }
        }
        
        private function vanish():Boolean
        {
            var didVanish:Boolean = false;
            for (var i:int = 0; i < SCENE_WIDTH; i++) {
                for (var j:int = SCENE_HEIGHT-1; j >= groundLevelAt[i]; j--) {
                    var color:int = scene[i][j];
                    if (color < 0) { continue; }
                    var mode:Boolean = (markChunk(i, j, color) > 3);
                    unmarkChunk(i, j, color, mode);
                    didVanish = didVanish || mode;
                }
            }
            return didVanish;
        }
        
        private function markChunk(x:int, y:int, col:int):int
        {
            if (x < 0 || x >= SCENE_WIDTH) { return 0; }
            if (scene[x][y] == col) {
                scene[x][y] = MARKING;
                return 1 + markChunk(x-1, y, col) + markChunk(x+1, y, col) +
                        markChunk(x, y-1, col) + markChunk(x, y+1, col);
            }
            return 0;
        }
        
        private function unmarkChunk(x:int, y:int, col:int, isVanishMode:Boolean):void
        {
            if (x < 0 || x >= SCENE_WIDTH) { return; }
            if (scene[x][y] == MARKING) {
                scene[x][y] = (isVanishMode ? BLANK : col);
                unmarkChunk(x-1, y, col, isVanishMode);
                unmarkChunk(x+1, y, col, isVanishMode);
                unmarkChunk(x, y-1, col, isVanishMode);
                unmarkChunk(x, y+1, col, isVanishMode);
            }
        }
        
        private function draw():void
        {
            graphics.clear();
            graphics.beginFill(0x333333);
            graphics.drawRect(0, 0, CELL_WIDTH*SCENE_WIDTH, CELL_HEIGHT*SCENE_HEIGHT);
            graphics.endFill();

            for each (var pair:Pair in fallingPairs) {
                drawPuyo(pair.p1.x, pair.p1.y, pair.p1.color);
                drawPuyo(pair.p2.x, pair.p2.y, pair.p2.color);
            }
            for (var i:int = 0; i < SCENE_WIDTH; i++) {
                for (var j:int = SCENE_HEIGHT; j >= groundLevelAt[i]; j--) {
                    var s:int = scene[i][j];
                    if (s >= 0) { drawPuyo(i, j, s); }
                }
            }
        }
        
        private function drawPuyo(x:int, y:int, col:int):void
        {
            graphics.beginFill(COLORS[col]);
            graphics.drawEllipse(CELL_WIDTH*x, CELL_HEIGHT*y, CELL_WIDTH, CELL_HEIGHT);
            graphics.endFill();
        }    
    }
}

class Pair
{
    public var p1:Puyo;
    public var p2:Puyo;
    
    public function Pair(maxX:int, numColors:int)
    {
        var x:int = int(Math.random()*(maxX-1));
        p1 = new Puyo(x, 0, int(Math.random()*numColors));
        if (Math.random() < .5) {
            p2 = new Puyo(x+1, 0, int(Math.random()*numColors));
        } else {
            p2 = new Puyo(x, 1, int(Math.random()*numColors));
        }
    }
    
    public function fall():void
    {
        p1.y += 1;
        p2.y += 1;
    }
}

class Puyo
{
    public var x:int;
    public var y:int;
    public var color:int;
    
    public function Puyo(x:int, y:int, color:int)
    {
        this.x = x;
        this.y = y;
        this.color = color;
    }
}