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

flash on 2010-11-10

Get Adobe Flash player
by kihon 03 Oct 2011
    Embed
/**
 * Copyright kihon ( http://wonderfl.net/user/kihon )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/54lZ
 */

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;
    import flash.utils.ByteArray;
 
    public class Main extends Sprite
    {
        private var keys:Array = [];
        private var status:Status = new Status();
        private var blocks:Array = [];
        private var next/*Array*/:Array = [];
        private var nextLength:int = 3;
        private var map/*Array*/:Array;    // テトリス盤面
        private var landingCount:int = 10;    // 地面(ブロック)に付いてから固定されるまでのフレーム
        private var leftKeyPressCount:int = 0;
        private var rightKeyPressCount:int = 0;
        private var rotateKeyPressFlag:Boolean;    // 回転キーを押している状態か
        private const WIDTH:int = 12;    // 横幅
        private const HEIGHT:int = 21;    // 縦幅
        private const FALL_SPEED:Number = 0.05;    // 落ちるスピード
 
        public function Main()
        {            
            map = [];
            for (var y:int = 0; y < HEIGHT; y++)
            {
                map[y] = new Array();
                for (var x:int = 0; x < WIDTH; x++)
                {
                    // 左端/右端/下端は壁なので1を入れ、それ以外のところは0を入れる
                    if (x == 0 || x == WIDTH - 1 || y == HEIGHT - 1) map[y][x] = 1;
                    else map[y][x] = 0;
                }
            }
            
            for (var i:int = 0; i < nextLength; i++) next.push(getBlock());
            initalize();
 
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
        }
 
        // 初期化処理
        private function initalize():void
        {
            rotateKeyPressFlag = false;
            status.x = 4;
            status.y = 0;
            status.block = next.shift();
            next.push(getBlock());
        }
        
        private function getBlock():Array
        {
            if (blocks.length == 0)
            {
                for (var i:int = 0; i < Block.SHAPE.length; i++)
                {
                    blocks.push(Block.SHAPE[i]);
                }
                blocks = shuffle(blocks);
            }
            return blocks.pop();
        }

        // 配列をシャッフルする
        private function shuffle(src:Array):Array
        {
            var temp:Array = src.slice();
            var dest:Array = new Array();

            while (temp.length > 0)
            {
                var index:int = Math.random() * temp.length;
                dest.push(temp[index]);
                temp.splice(index, 1);
            }

            return dest;
        }
 
        // 毎フレーム行う処理
        private function onEnterFrame(event:Event):void 
        {
            status.y += FALL_SPEED;
            // 一つ下に移動して衝突する場合は、今のマスから動かさないようにする
            if (check(status.x, status.y + 1)) status.y = int(status.y);
            if (keys[Keyboard.LEFT] && !check(status.x - 1, Math.ceil(status.y)) && !check(status.x - 1, Math.floor(status.y)))
            {
                if (leftKeyPressCount == 0 || leftKeyPressCount >= 3)
                {
                    status.x--;
                }
                leftKeyPressCount++;
            }
            else leftKeyPressCount = 0; // キーが離されたら、値を0に戻す
            if (keys[Keyboard.RIGHT] && !check(status.x + 1, Math.ceil(status.y)) && !check(status.x + 1, Math.floor(status.y)))
            {
                if (rightKeyPressCount == 0 || rightKeyPressCount >= 3)
                {
                    status.x++;
                }
                rightKeyPressCount++;
            }
            else rightKeyPressCount = 0;
            if (keys[Keyboard.DOWN])
            {
                status.y += FALL_SPEED * 10; // 普通に落ちる速度の10倍
                if (check(status.x, status.y + 1)) status.y = int(status.y);
            }
            if (keys[Keyboard.UP])
            {
                drop();
            }

            if (!rotateKeyPressFlag && keys[90])
            {
                status.block = rotate(status.block);
                if (check(status.x, status.y)) status.block = rotate(status.block, false);
                rotateKeyPressFlag = true;
            }
             
            if (!rotateKeyPressFlag && keys[88])
            {
                status.block = rotate(status.block, false);
                if (check(status.x, status.y)) status.block = rotate(status.block);
                rotateKeyPressFlag = true;
            }
             
            if (!keys[90] && !keys[88]) rotateKeyPressFlag = false;
            
            if (check(status.x, status.y + 1))
            {
                if (--landingCount <= 0) endProcess();
            }
            else landingCount = 10;
         
            draw();
        }
        
        // 仮に引数の(x, y)に今落ちているブロックを置いた場合、
        // 他のブロックや壁と衝突してしまう場合はtrue, しない場合はfalseが返却される
        private function check(tx:int, ty:int):Boolean
        {
            var block:Array = status.block;
            for (var y:int = 0; y < Block.SIZE; y++)
            {
                for (var x:int = 0; x < Block.SIZE; x++)
                {
                    if (block[y][x] && map[ty + y][tx + x]) return true;
                }
            }
         
            return false;
        }
 
        // ブロックが地面に落ちて、位置が確定した後の処理
        private function endProcess():void
        {
            // ENTER_FRAMEを一度止める
            removeEventListener(Event.ENTER_FRAME, onEnterFrame);
            lock(); // ブロックを固定
            deleteLine(); // 削除
            draw(); // 描画
         
            initalize(); // 初期化
            landingCount = 10; // 初期化
         
            // 最初の位置にブロックが置けなかったらゲームオーバー。
            if (check(status.x, status.y)) gameOver();
            else addEventListener(Event.ENTER_FRAME, onEnterFrame); // 再開
        }
        
        // 着地したブロックを固定させる
        private function lock():void
        {
            var block:Array = status.block;
            for (var y:int = 0; y < Block.SIZE; y++)
            {
                for (var x:int = 0; x < Block.SIZE; x++)
                {
                    if (block[y][x]) map[status.y + y][status.x + x] = block[y][x];
                }
            }
        }
        
        private function deleteLine():void
        {
            for (var y:int = HEIGHT - 2; y >= 0; y--)
            {
                var flag:Boolean = true; // trueなら横一列が揃っている
                for (var x:int = 1; x <= WIDTH - 2; x++)
                {
                    // ある行に隙間を見つけたら横一列揃っていないということなので、
                    // flagをfalseにしてループを抜ける
                    if (!map[y][x])
                    {
                        flag = false;
                        break;
                    }
                }
         
                // 横一列揃っていたら
                if (flag)
                {
                    // 揃っている行から上にある全ての行を一段下にずらす
                    for (var yy:int = y - 1; yy >= 0; yy--)
                    {
                        for (x = 1; x <= WIDTH - 2; x++)
                        {
                            map[yy + 1][x] = map[yy][x];
                        }    
                    }
         
                    // 一段ずれるので、yの値を戻す
                    y++;
                }
            }
        }
        
        private function getDropPosition():int
        {
            for (var y:int = status.y; ; y++)
            {
                if (check(status.x, y))
                {
                    return y - 1;
                }
            }
         
            return -999; // ここまで来ないが、何か書いておかないと警告が出る
        }
        
        private function drop():void
        {
            status.y = getDropPosition();
        }
        
        // block = 回転させるブロック(配列)  leftRotateがtrueなら左に回転、falseなら右に回転
        private function rotate(block:Array, leftRotate:Boolean = true):Array
        {
            var cloneBlock:Array = clone(block);
            for (var y:int = 0; y < Block.SIZE; y++)
            {
                for (var x:int = 0; x < Block.SIZE; x++)
                {
                    if (leftRotate) cloneBlock[Block.SIZE - x - 1][y] = block[y][x];
                    else cloneBlock[x][Block.SIZE - y - 1] = block[y][x];
                }
            }
         
            return cloneBlock;
        }
        
        private function clone(array:Array):Array
        {
            var b:ByteArray = new ByteArray();
            b.writeObject(array);
            b.position = 0;
            return b.readObject();
        }
                
        private function gameOver():void
        {
            trace("GAME OVER");
        }
 
        // ブロックの描画
        private function draw():void
        {
            graphics.clear(); // 初期化
            graphics.beginFill(0x0);
            graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            graphics.endFill();
            
            for (var y:int = 0; y < HEIGHT; y++)
            {
                for (var x:int = 0; x < WIDTH; x++)
                {
                    // 注目しているマスに0が入っていない、つまり壁かブロックが入っている場合
                    if (map[y][x])
                    {    
                        // 壁だったら
                        if (x == 0 || x == WIDTH - 1 || y == HEIGHT - 1)
                        {
                            graphics.lineStyle(1.0);
                            graphics.beginFill(0x555555);
                        }
                        // ブロックだったら
                        else
                        {
                            graphics.lineStyle(2.0);
                            graphics.beginFill(Block.COLOR[map[y][x]]);
                        }
                        graphics.drawRect(x * Block.WIDTH, y * Block.HEIGHT, Block.WIDTH, Block.HEIGHT);
                        graphics.endFill();
                    }
                }
            }
            
            var block:Array = status.block;
            var dropY:int = getDropPosition(); // 落下地点の位置yを取得
            for (y = 0; y < Block.SIZE; y++)
            {
                for (x = 0; x < Block.SIZE; x++)
                {
                    // 4*4配列の中でブロックの描画があるところだけを表示する
                    if (block[y][x])
                    {
                        // (status.x, drop.y)のところにブロックを薄く表示させる
                        graphics.lineStyle(1.5, 0x777777);
                        graphics.beginFill(Block.COLOR[block[y][x]], 0.1);
                        graphics.drawRect((status.x + x) * Block.WIDTH, (dropY + y) * Block.HEIGHT, Block.WIDTH, Block.HEIGHT);
                        graphics.endFill();
                        
                        graphics.lineStyle(1.5);
                        graphics.beginFill(Block.COLOR[block[y][x]]);
                        graphics.drawRect((status.x + x) * Block.WIDTH, (status.y + y) * Block.HEIGHT, Block.WIDTH, Block.HEIGHT);
                        graphics.endFill();
                    }
                }
            }
                
            for (var i:int = 0; i < next.length; i++)
            {
                block = next[i];
                for (y = 0; y < Block.SIZE; y++)
                {
                    for (x = 0; x < Block.SIZE; x++)
                    {
                        if (block[y][x])
                        {    
                            graphics.lineStyle(1.5);
                            graphics.beginFill(Block.COLOR[block[y][x]]);
                            graphics.drawRect(300 + x * Block.WIDTH, i * 100 + y * Block.HEIGHT, Block.WIDTH, Block.HEIGHT);
                            graphics.endFill();
                        }
                    }
                }
            }
        }
 
        // キーが押されたとき
        private function onKeyDown(event:KeyboardEvent):void
        {
            keys[event.keyCode] = true; 
        }
 
        // キーが離されたとき
        private function onKeyUp(event:KeyboardEvent):void
        {
            keys[event.keyCode] = false; 
        }
    }
}

class Status
{
    public var x:Number;                // このx, yの位置からブロックを表示する
    public var y:Number;            
    public var block/*Array*/:Array;    // 今持っているブロック
}

class Block
{
    public static const SIZE:int = 4;    // ブロックの形状を4*4の配列で保持しているので、その4を定数にしている
    public static const WIDTH:int = 20;    // ブロックの横サイズ
    public static const HEIGHT:int = 20;    // ブロックの縦サイズ
 
    // 色
    public static const COLOR/*int*/:Array = [0x0, 0xFEFBB3, 0x69DEEE, 0x3DC642, 0xF33433, 0x797CFB, 0xF88C2D, 0xFFAAFF];
 
    // 形状
    public static const SHAPE/*Array*/:Array =
    [
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [0, 1, 1, 0],
            [0, 0, 0, 0]
        ],
        [
            [0, 2, 0, 0],
            [0, 2, 0, 0],
            [0, 2, 0, 0],
            [0, 2, 0, 0]
        ],
        [
            [0, 0, 0, 0],
            [0, 3, 3, 0],
            [3, 3, 0, 0],
            [0, 0, 0, 0]
        ],
        [
            [0, 0, 0, 0],
            [4, 4, 0, 0],
            [0, 4, 4, 0],
            [0, 0, 0, 0]
        ],
        [
            [0, 0, 0, 0],
            [5, 0, 0, 0],
            [5, 5, 5, 0],
            [0, 0, 0, 0]
        ],
        [
            [0, 0, 0, 0],
            [0, 0, 6, 0],
            [6, 6, 6, 0],
            [0, 0, 0, 0]
        ],
        [
            [0, 0, 0, 0],
            [0, 7, 0, 0],
            [7, 7, 7, 0],
            [0, 0, 0, 0]
        ]
    ];
}