forked from: 3 x 3 Random Tetris

by aobyrne forked from 3 x 3 Random Tetris (diff: 11)
♥0 | Line 278 | Modified 2012-02-18 06:19:08 | MIT License
play

ActionScript3 source code

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

// forked from daniwell's 3 x 3 Random Tetris
package  
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFormat;
    
    [SWF(backgroundColor = "0xbbbbbb", frameRate = "30", width = "465", height = "465")]
    public class Tetris extends Sprite
    {
        /* サイズ */
        private const SIZE  :int = 3;
        /* ヨコ */
        private const NUM_W :int = 12;
        /* タテ */
        private const NUM_H :int = 24;
        
        private const SCALE :int = 16;
        
        private var field :Vector.<Vector.<int>> = new Vector.<Vector.<int>>(NUM_H);
        private var blocks:Vector.<Block> = new Vector.<Block>();
        
        private var keyFlags  :Array = [];
        private var keyCounts :Array = [];
        
        private var now  :int;
        private var nowX :int;
        private var nowY :int;
        private var nowBlock  :Block;
        private var nextBlock :Block;
        
        private var bmd :BitmapData;
        private var bmp :Bitmap;
        
        private var nextBmd :BitmapData;
        private var nextBmp :Bitmap;
        
        private var phase :int = 0;
        private var count :int = 0;
        private var score :int = 0;
        
        private var tf      :TextField;
        private var tfScore :TextField;
        private var texdft:TextField;
        private var sc_rotateKey:Number;
        private var sc_fullFallKey:Number;
        
        public function Tetris() 
        {
            texdft = addChild(new TextField) as TextField;
            sc_rotateKey = 38;
            sc_fullFallKey = 32;
            graphics.beginFill(0xbbbbbb); graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            
            bmd = new BitmapData(NUM_W, NUM_H, false);
            bmp = new Bitmap(bmd);
            addChild(bmp);
            
            nextBmd = new BitmapData(SIZE + 2, SIZE + 2, false);
            nextBmp = new Bitmap(nextBmd);
            addChild(nextBmp);
            
            nextBmp.scaleX = nextBmp.scaleY = bmp.scaleX = bmp.scaleY = SCALE;
            
            bmp.x = int((stage.stageWidth - (nextBmp.width + bmp.width + SCALE)) / 2);
            nextBmp.x = bmp.x + bmp.width + SCALE;
            nextBmp.y = bmp.y = int((stage.stageWidth - (bmp.height)) / 2);
            
            for (var i :int = 0; i < NUM_H; i ++)
            {
                field[i] = new Vector.<int>(NUM_W);
                for (var j :int = 0; j < NUM_W; j++) field[i][j] = 0;
            }
            
            // "Score" TextField
            tfScore = addChild(new TextField()) as TextField;
            tfScore.defaultTextFormat = new TextFormat("_等幅", 11, 0xffffff);
            tfScore.autoSize = "left"; addScore(0);
            tfScore.x = nextBmp.x; tfScore.y = bmp.y + bmp.height - tfScore.height;
            
            // "Click To Start" TextField
            tf = addChild(new TextField()) as TextField;
            tf.defaultTextFormat = new TextFormat("_sans", 10, 0xaaaaaa); tf.autoSize = "left"; tf.selectable = false;
            tf.text = "CLICK TO START"; tf.x = bmp.x + (bmp.width - tf.width) / 2; tf.y = bmp.y + (bmp.height - tf.height) / 2;
            addChild(tf);
            
            stage.addEventListener(MouseEvent.CLICK, clickHandler);
        }
        
        /* ゲーム開始 */
        private function clickHandler(e:MouseEvent):void
        {
            tf.visible = false; stage.removeEventListener(MouseEvent.CLICK, clickHandler);
            
            nextBlock = new Block(SIZE); reset();
            
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
            stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        /* リセット & 初期化 */
        private function reset():void
        {
            now = count = 0;
            phase = 1; nowX  = (NUM_W - SIZE) / 2;
            
            nowBlock = nextBlock;
            nextBlock = new Block(SIZE);
            
            LABEL: for (var i :int = 0; i < SIZE; i ++) for (var j :int = 0; j < SIZE; j ++) if (0 < nowBlock.data[now][i][j]) break LABEL;
            nowY = - i;
            
            nextBmd.fillRect(nextBmd.rect, 0xffffff);
            renderBlock(nextBlock, nextBmd, 1, 1);
            render();
            
            // Game End
            if (hitCheck(nowBlock.data[now], nowX, nowY)) { stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler); tf.text = " - GAME END - "; tf.visible = true; }
        }
        /* X 軸移動 */
        private function moveX(n:int):void
        {
            if (! hitCheck(nowBlock.data[now], nowX + n, nowY)) nowX += n;
            render();
        }
        /* Y 軸移動 */
        private function moveY (score:int = 0):void
        {
            if (! hitCheck(nowBlock.data[now], nowX, nowY + 1))
            {
                addScore(score);
                
                nowY ++;
                render();
            }
            else
            {
                count = 0
                phase = 2;
                
                setBlock();
                search();
            }
        }
        /* 探索 */
        private function search ():void
        {
            for (var i :int = 0, ct :int = 0; i < NUM_H; i ++)
            {
                for (var j :int = 0; j < NUM_W; j++) if (field[i][j] == 0) break;
                if (j == NUM_W) { fall(i); ct ++ }
            }
            if (0 < ct) addScore(ct * ct * 100);
            render();
        }
        /* 落下 */
        private function fall(line:int):void
        {
            for (var i :int = line; 0 <= i; i --)
            {
                for (var j :int = 0; j < NUM_W; j++) 
                {
                    if (i != 0)    field[i][j] = field[i-1][j];
                    else        field[i][j] = 0;
                }
            }
        }
        
        /* 回転 */
        private function rotate(n:int):void
        {
            var nn :int = now + n;
            if (nn < 0) nn = 3; if (3 < nn) nn = 0;
            
            if (! hitCheck(nowBlock.data[nn], nowX, nowY)) now = nn;
            
            render();
        }
        /* ブロックの接地 */
        private function setBlock ():void
        {
            var px :int, py :int;
            
            for (var i :int = 0; i < SIZE; i ++)
            {
                py = i + nowY;
                for (var j :int = 0; j < SIZE; j++)
                {
                    px = j + nowX;
                    if (nowBlock.data[now][i][j] == 0 || px < 0 || py < 0 || NUM_W <= px || NUM_H <= py) continue;
                    field[py][px] = 1;
                }
            }
        }
        
        /* 衝突判定 */
        private function hitCheck (data:Array, nX:int, nY:int):Boolean
        {
            var px :int, py :int;
            
            for (var i :int = 0; i < SIZE; i ++)
            {
                py = i + nY;
                for (var j :int = 0; j < SIZE; j++)
                {
                    px = j + nX;
                    if (data[i][j] == 0) continue;
                    
                    if (px < 0 || NUM_W <= px || NUM_H <= py) return true;
                    if (0 <= py && 0 < field[py][px]) return true;
                }
            }
            return false;
        }
        /* レンダリング */
        private function render():void
        {
            bmd.lock();
            bmd.fillRect(bmd.rect, 0xffffff);
            
            for (var i :int = 0; i < NUM_H; i ++)
                for (var j :int = 0; j < NUM_W; j++) 
                    if (0 < field[i][j]) bmd.setPixel(j, i, 0);
            
            if (phase == 1) renderBlock(nowBlock, bmd, nowX, nowY);
            
            bmd.unlock();
        }
        /* 操作中のブロックのレンダリング */
        private function renderBlock (bl:Block, bd:BitmapData, ox:int, oy:int) :void
        {
            for (var i :int = 0; i < SIZE; i ++)
                for (var j :int = 0; j < SIZE; j++)
                    if (0 < bl.data[now][i][j]) bd.setPixel(j + ox, i + oy, 0);
        }
        /* スコア加算 */
        private function addScore (value :int) :void
        {
            score += value;
            tfScore.text = "SCORE: " + score;
        }
        
        private function enterFrameHandler (e:Event):void
        {
            count ++;
            
            if (phase == 1)
            {
                if (30 <= count)
                {
                    moveY();
                    count = 0;
                }
                
                if (keyFlags[37]) if (keyCounts[37]++ == 0 || 4 < keyCounts[37]) moveX(-1);
                if (keyFlags[39]) if (keyCounts[39]++ == 0 || 4 < keyCounts[39]) moveX(1);
                if (keyFlags[sc_rotateKey]) if (keyCounts[sc_rotateKey]++ == 0 || 4 < keyCounts[sc_rotateKey]) rotate(-1);
                if (keyFlags[88]) if (keyCounts[88]++ == 0 || 4 < keyCounts[88]) rotate(1);
                if (keyFlags[40]) moveY(1);
                if (keyFlags[sc_fullFallKey]) while (phase == 1) moveY(1);
            }
            else if (phase == 2)
            {
                if (6 <= count) reset();
            }
        }
        
        private function keyDownHandler (e:KeyboardEvent):void
        {
            keyCounts[e.keyCode] = 0;
            trace( "e.keyCode : " + e.keyCode );
            texdft.text = e.keyCode.toString();
            keyFlags[e.keyCode] = true;
        }
        private function keyUpHandler (e:KeyboardEvent):void
        {
            keyFlags[e.keyCode] = false;
        }
    }
}

class Block
{
    private var _data :Array;
    
    public function Block(size:int)
    {
        _data = [];
        _data[k] = BlockUtil.getBlockData(size);
        for (var k :int = 1; k < 4; k ++)
        {
            _data[k] = [];
            for (var i :int = 0; i < size; i ++)
            {
                _data[k][i] = [];
                for (var j :int = 0; j < size; j++) _data[k][i][j] = _data[k-1][size-j-1][i];
            }
        }
    }
    public function get data( ) :Array { return _data; }
}

class BlockUtil
{
    public static function getBlockData (size:int) :Array
    {
        var d :Array = [];
        for (var i :int = 0; i < size; i ++)
        {
            d[i] = [];
            for (var j :int = 0; j < size; j++) d[i][j] = 0;
        }
        _update(d, size, [int(Math.random()*size), int(Math.random()*size)], [int(Math.random()*size), int(Math.random()*size)]);
        return d;
    }
    private static function _update (d:Array, size:int, p1:Array , p2:Array) :void
    {
        d[p1[1]][p1[0]] = 1;
        d[p2[1]][p2[0]] = 2;
        
        if (p1[0] == p2[0] && p1[1] == p2[1]) return;
        
        _getp(size, p1, int(Math.random() * 4));
        _getp(size, p2, int(Math.random() * 4));
        
        if (d[p1[1]][p1[0]] == 2) return;
        if (d[p2[1]][p2[0]] == 1) return;
        
        _update(d, size, p1, p2);
    }
    private static function _getp (size:int, p:Array, n:int) :void
    {
        switch ( n % 4 ) {
        case 0: p[0] ++; if (size <= p[0]) { p[0] --; _getp(size, p, n + 1); } break;
        case 1: p[1] ++; if (size <= p[1]) { p[1] --; _getp(size, p, n + 1); } break;
        case 2: p[0] --; if (p[0]  <  0)   { p[0] ++; _getp(size, p, n + 1); } break;
        case 3: p[1] --; if (p[1]  <  0)   { p[1] ++; _getp(size, p, n + 1); } break;
        }
    }
}