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: さめがめ - 完成版

ステージの導入
立ち上がりに"+ 0"を出ないようにした
デザイン調整
ゲームオーバーでも自動でやり直しが出来る(ぉ

とりあえずはこれで完成ということで機能追加終了。
あとはバグがあれば対応していくというぐらい。
/**
 * Copyright alwAYs ( http://wonderfl.net/user/alwAYs )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/b1Tj
 */

// forked from samegame's さめがめ - 完成版
/**
 * ステージの導入
 * 立ち上がりに"+ 0"を出ないようにした
 * デザイン調整
 * ゲームオーバーでも自動でやり直しが出来る(ぉ
 * 
 * とりあえずはこれで完成ということで機能追加終了。
 * あとはバグがあれば対応していくというぐらい。
 **/
package
{
    import flash.display.Sprite;
    
    [SWF(backgroundColor = "0x0", frameRate="120")]
    public class Main extends Sprite
    {
        public function Main()
        {
            // サムネの見栄え用
            graphics.beginFill(0x0);
            graphics.drawRect(0, 0, 465, 465);
            graphics.endFill();
            
            var panel:Panel = new Panel();
            addChild(panel);
        }
    }
}

import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.filters.DropShadowFilter;
import flash.filters.GlowFilter;
import flash.filters.BevelFilter;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.utils.getDefinitionByName;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.tweens.ITween;

class ScorePanel extends Sprite
{
    public var score:int = 0;
    public var scoreTF:TextField;
    public var scoreBitmap:Bitmap;
    public var targetScore:int = 10000;
    public var targetBitmap:Bitmap;
    
    public function ScorePanel()
    {
        var tf:TextField = Text.createTextField("Score", 30, 0xFFC700);
        tf.x = -10;
        tf.y = -10;
        addChild(tf);
        
        scoreTF = Text.createTextField("0", 23, 0x0);

        scoreBitmap = new Bitmap();
        scoreBitmap.y = tf.y + 30;
        addChild(scoreBitmap);
        
        targetBitmap = new Bitmap();
        targetBitmap.y = tf.y + 60;
        addChild(targetBitmap);
        
        incrementScore(0);
    }
    
    // スコアを増やす。引数は一度に消したブロックの数
    public function incrementScore(count:int):void
    {
        score += count * count * count * 10;
        scoreTF.text = score.toString();
        
        var bd:BitmapData = Text.getText(scoreTF.text, 32, 0xFFFFFF, [0xFF9900, 0xFFDD00, 0xFF9900]);
        scoreBitmap.bitmapData = bd;
        scoreBitmap.x = 150 - scoreBitmap.width + 5;
        
        bd = Text.getText(targetScore.toString(), 32, 0xFFFFFF, [0xFF9900, 0xFFDD00, 0xFF9900]);
        targetBitmap.bitmapData = bd;
        targetBitmap.x = 150 - targetBitmap.width + 5;
        
        // "+ 200のような文字列を表示させる"
        var bd2:BitmapData = Text.getText("+ " + count * count * count * 10, 20, 0x0, [0xFF9900, 0xFFBB00, 0xFF9900]);
        var bitmap:Bitmap = new Bitmap(bd2);
        bitmap.x = 80;
        bitmap.y = 0;
        
        if (count * count * count * 10 != 0)
        {
            BetweenAS3.serial
            (
                BetweenAS3.addChild(bitmap, this), // "+ 200"のような文字を表示させる
                BetweenAS3.tween(bitmap, { x:bitmap.x + 20, alpha:0.2 }, null, 1.0), // 右に移動しながら透明度を下げる
                BetweenAS3.removeFromParent(bitmap) // 1秒経ったら消す
            ).play();
        }
    }
}

class Text
{
    public static function createTextField(text:String, size:int, color:int, align:String = "left"):TextField
    {
        var tf:TextField = new TextField();
        tf.defaultTextFormat = new TextFormat("typeWriter_", size, color, true, null, null, null, null, align);
        tf.text = text;
        tf.autoSize = TextFieldAutoSize.LEFT;
        tf.selectable = false;
        
        return tf;
    }
    
    // 文字をグラデーションにする
    public static function getText(text:String, size:int, color:int, gcolor:Array, degree:Number = -45):BitmapData
    {
        var tf:TextField = Text.createTextField(text, size, color);
        var matrix:Matrix = new Matrix();
        matrix.createGradientBox(tf.width, tf.height, degree * Math.PI / 180);
        var gradation:Sprite = new Sprite();
        gradation.graphics.beginGradientFill("linear", gcolor, [1.0, 1.0, 1.0], [0, 128, 255], matrix);
        gradation.graphics.drawRect(0, 0, tf.width, tf.height);
        gradation.graphics.endFill();
        
        
        var alphabd:BitmapData = new BitmapData(tf.width, tf.height, true, 0x0);
        alphabd.draw(tf);
        
        var sourcebd:BitmapData = new BitmapData(gradation.width, gradation.height, true, 0x00);
        sourcebd.draw(gradation);
        
        var bd:BitmapData = new BitmapData(tf.width, tf.height, true, 0x0);
        bd.copyPixels(sourcebd, sourcebd.rect, new Point(), alphabd, new Point(), true);
        
        return bd;
    }
}

class ResultPanel extends Sprite // 結果表示画面
{
    private const HEIGHT:int = 150;
    
    public function ResultPanel(panel:Panel)
    {
        // 画面は黒く
        graphics.beginFill(0x0);
        graphics.drawRect(0, 0, 465, HEIGHT);
        graphics.endFill();
        
        // アクセントとして上下に白線を入れておく
        graphics.lineStyle(3.0, 0xFFFFFF);
        graphics.moveTo(0, 0);
        graphics.lineTo(465, 0);
        graphics.moveTo(0, HEIGHT);
        graphics.lineTo(465, HEIGHT);
        
        // ベベルで質感を
        this.filters = [new BevelFilter(4, 90, 0xFFFFFF, 1, 0xFFFFFF, 1, 20, 20, 1, 3, "inner")];
        
        // 画面中央に配置
        this.y = (this.width - HEIGHT) / 2;
        
        // 残りブロック数
        var countBlock:TextField = Text.createTextField("剩余: " + panel.countBlocks(), 20, 0xFFCC00);
        countBlock.x = (this.width - countBlock.width) / 2;
        countBlock.y = 10;
        
        // スコア
        var scoreTF:TextField = Text.createTextField("分数: " + panel.scorePanel.score, 20, 0xFF9900);
        scoreTF.x = countBlock.x;
        scoreTF.y = countBlock.y + countBlock.height + 10;
        
        // 結果
        var kekka:TextField = Text.createTextField("结果: ", 30, 0xFFBB00);
        kekka.x = countBlock.x - 2;
        kekka.y = scoreTF.y + 50;
        
        // 合否アニメーションテキスト
        var result:TextField = Text.createTextField("", 30, 0xFFBB00);
        result.x = countBlock.x + 90;
        result.y = scoreTF.y + 50;
        
        var t2:ITween = 
        BetweenAS3.parallel
        (
            BetweenAS3.tween(countBlock, { x: -countBlock.width } ),
            BetweenAS3.tween(scoreTF, { x:465 } ),
            BetweenAS3.tween(kekka, { x: -(kekka.width + 97) } ),
            BetweenAS3.tween(result, { x: -97 } )
        );
        
        var goukaku:Array;
        var clearFlag:Boolean = false;
        if (Mission["missionS" + Mission.stage]())
        {
            goukaku = ["h", "he", "合", "合g", "合ge", "合格"];
            clearFlag = true;
        }
        else
        {
            goukaku = ["b", "bu", "不", "不h", "不he", "不合", "不合g", "不合ge", "不合格"];
            var gameover:Bitmap = new Bitmap(Text.getText("GAME OVER", 40, 0x0, [0xFFFFFF, 0xED1A3D, 0xFFFFFF]));
            gameover.x = (this.width - gameover.width) / 2;
            gameover.y = (this.height - gameover.height) / 2;
            gameover.alpha = 0.0;
            
            t2 = BetweenAS3.serial
            (
                t2,
                BetweenAS3.addChild(gameover, this),
                BetweenAS3.delay(BetweenAS3.tween(gameover, { alpha:1.0 }, null, 2.0), 0, 1)
            )
        }
        
        if (clearFlag && Mission.MAXSTAGE <= Mission.stage)
        {
            var clear:Bitmap = new Bitmap(Text.getText("ALL STAGE CLEAR", 40, 0x0, [0xFFFFFF, 0xED1A3D, 0xFFFFFF]));
            clear.x = (this.width - clear.width) / 2;
            clear.y = (this.height - clear.height) / 2;
            clear.alpha = 0.0;
            
            t2 = BetweenAS3.serial
            (
                t2,
                BetweenAS3.addChild(clear, this),
                BetweenAS3.delay(BetweenAS3.tween(clear, { alpha:1.0 }, null, 2.0), 0, 1)
            )
        }
        else
        {
            t2 = BetweenAS3.serial
            (
                t2,
                BetweenAS3.tween(this, { y:y + 20 }, null, 0.5),
                BetweenAS3.tween(this, { y: -this.height } ),
                BetweenAS3.func(function():void { if (clearFlag) Mission.stage++; } ),
                BetweenAS3.func(panel.init),
                BetweenAS3.removeFromParent(this)
            );
        }
        
        var t:ITween = 
        BetweenAS3.serial
        (
            BetweenAS3.delay(BetweenAS3.addChild(result, this), 1),
            BetweenAS3.delay(BetweenAS3.func(function():void { result.text = goukaku[0]; } ), 0.1)
        );
        
        var index:int = 0; // クロージャ対策
        for (var i:int = index; i < goukaku.length; i++)
        {
            t = BetweenAS3.serial
            (
                t,
                BetweenAS3.delay(BetweenAS3.func(function():void { result.text = goukaku[index++]; } ), 0.1)
            )
        }
        
        t = BetweenAS3.serial
        (
            BetweenAS3.delay(BetweenAS3.tween(this, { x:0, y:y }, { x:470 } ), 2),
            BetweenAS3.addChild(countBlock, this),
            BetweenAS3.delay(BetweenAS3.addChild(scoreTF, this), 1),
            BetweenAS3.delay(BetweenAS3.addChild(kekka, this), 1),
            BetweenAS3.delay(t, 0, 1),
            t2
        );
        t.play();
    }
}

class Mission // Stageにしようかと思ったけど、描画領域のStageクラスがあるのでやめた。
{
    public static var MAXSTAGE:int = 9;
    public static var stage:int = 1; // 現在のステージ
    public static var panel:Panel;
    
    public static const messageS1:String = "清除全部方块";
    public static const messageS2:String = "获得30000分以上";
    public static const messageS3:String = "最多只可以剩余一块";
    public static const messageS4:String = "清除所有的红色方块";
    public static const messageS5:String = "获得50000分以上";
    public static const messageS6:String = "清除全部方块";
    public static const messageS7:String = "获得60000分以上";
    public static const messageS8:String = "留下圆点(一个或以上)";
    public static const messageS9:String = "获得100000分以上";
    
    public static function init(panel:Panel):void
    {
        Mission.panel = panel;
    }
    
    // ステージ1の初期設定
    public static function initS1():void
    {
        Panel.WIDTH = 8;
        Panel.numColor = 2;
    }
    
    // ステージ2の初期設定
    public static function initS2():void
    {
        Panel.WIDTH = 10;
        Panel.numColor = 4;
        panel.scorePanel.targetScore = 30000;
    }
        
    // ステージ3の初期設定
    public static function initS3():void
    {
        Panel.WIDTH = 10;
        Panel.numColor = 2;
    }
    
    // ステージ4の初期設定
    public static function initS4():void
    {
        Panel.WIDTH = 10;
        Panel.numColor = 3;
    }
    
    // ステージ5の初期設定
    public static function initS5():void
    {
        Panel.WIDTH = 13;
        Panel.numColor = 4;
        panel.scorePanel.targetScore = 50000;
    }
    
    // ステージ6の初期設定
    public static function initS6():void
    {
        Panel.WIDTH = 13;
        Panel.numColor = 3;
    }
    
    // ステージ7の初期設定
    public static function initS7():void
    {
        Panel.WIDTH = 12;
        Panel.numColor = 5;
        panel.scorePanel.targetScore = 60000;
    }
    
    
    // ステージ8の初期設定
    public static function initS8():void
    {
        Panel.WIDTH = 10;
        Panel.numColor = 3;
    }
    
    // ステージ9の初期設定
    public static function initS9():void
    {
        Panel.WIDTH = 15;
        Panel.numColor = 5;
        panel.scorePanel.targetScore = 100000;
    }
    
    // 全てのブロックを殲滅せよ
    public static function missionS1():Boolean
    {
        for (var i:int = 0; i < panel.countPanel.values.length; i++)
        {
            if (panel.countPanel.values[i] != 0) return false;
        }
        
        return true;
    }
    
    // スコア30000点以上を稼げ
    public static function missionS2():Boolean
    {
        return panel.scorePanel.score >= panel.scorePanel.targetScore;
    }
    
    // 特殊ブロックだけを残せ(一つ以上)
    public static function missionS3():Boolean
    {
        for (var i:int = 0; i < panel.countPanel.values.length; i++)
        {
            if (panel.countPanel.values[i] != 0) return true;
        }
        
        return false;
    }
    
    // 赤ブロックを殲滅せよ
    public static function missionS4():Boolean
    {
        return panel.countPanel.values[0] == 0;
    }
    
    // スコア50000点以上を稼げ
    public static function missionS5():Boolean
    {
        return panel.scorePanel.score >= panel.scorePanel.targetScore;
    }
    
    // 全てのブロックを殲滅せよ
    public static function missionS6():Boolean
    {
        for (var i:int = 0; i < panel.countPanel.values.length; i++)
        {
            if (panel.countPanel.values[i] != 0) return false;
        }
        
        return true;
    }
    
    // スコア70000点以上を稼げ
    public static function missionS7():Boolean
    {
        return panel.scorePanel.score >= panel.scorePanel.targetScore;
    }
    
    // スコア100000点以上を稼げ
    public static function missionS8():Boolean
    {
        var flag:Boolean = false; // ブロックが一つでも残っていたらtrue
        
        for (var y:int = 0; y < Panel.HEIGHT; y++)
        {
            for (var x:int = 0; x < Panel.WIDTH; x++)
            {
                if (panel.blocks[y][x] == null) continue;
                flag = true;
                if (panel.blocks[y][x].color < Block.SPECIAL) return false;
            }
        }
        
        return flag;
    }
    
    // スコア100000点以上を稼げ
    public static function missionS9():Boolean
    {
        return panel.scorePanel.score >= panel.scorePanel.targetScore;
    }
}

class Panel extends Sprite // ブロックはパネルに貼る
{
    public static var WIDTH:int = 15;     // ブロックの数 - 横
    public static var HEIGHT:int = 10;     // ブロックの数 - 縦
    public static const CH:int = 110;
    public static var numColor:int = 3; // 色数
    
    public var blocks:Array; // ブロックが入っている配列(二次元配列
    public var countPanel:CountPanel; // 残りブロック表示数を貼り付けているパネル
    public var scorePanel:ScorePanel; // スコアのパネル
    public var deleteCount:int = 0; // ブロックが一度に消えた数を保持
    public var canvas:Sprite;
    public var missionTF:TextField;
    
    public function Panel()
    {
        Mission.init(this);
        
        var header:Sprite = new Sprite();
        var matrix:Matrix = new Matrix();
        
        matrix.createGradientBox(465, 90);
        header.graphics.beginGradientFill("linear", [0x463e42, 0x594855], [1.0, 1.0], [0, 255], matrix);
        header.graphics.moveTo(0, 0);
        header.graphics.lineTo(465, 0);
        header.graphics.lineTo(465, 90);
        header.graphics.lineTo(0, 90);
        header.graphics.endFill();
        
        matrix.createGradientBox(465, 100, 0);
        header.graphics.beginGradientFill("linear", [0x231f21, 0x594855], [1.0, 1.0], [0, 255], matrix);
        header.graphics.moveTo(0, 0);
        header.graphics.lineTo(465, 0);
        header.graphics.lineTo(465, 90);
        header.graphics.lineTo(350, 90);
        header.graphics.lineTo(350, 35);
        header.graphics.lineTo(0, 35);
        header.graphics.endFill();
        
        matrix.createGradientBox(465, 70);
        header.graphics.beginGradientFill("linear", [0x231f21, 0x3d323a], [1.0, 1.0], [0, 255], matrix);
        header.graphics.moveTo(0, 0);
        header.graphics.lineTo(465, 0);
        header.graphics.lineTo(465, 60);
        header.graphics.lineTo(350, 60);
        header.graphics.lineTo(300, 35);
        header.graphics.lineTo(0, 35);
        header.graphics.endFill();
        
        header.graphics.lineStyle(2.0, 0x9f969b);
        header.graphics.moveTo(300, 28);
        header.graphics.lineTo(465, 28);
        addChild(header);

        missionTF = Text.createTextField(Mission["messageS" + Mission.stage], 20, 0xCCCCCC);
        missionTF.y = 50;
        addChild(missionTF);
        
        scorePanel = new ScorePanel();
        scorePanel.x = Block.WIDTH * 10 + 10;
        scorePanel.y = 5;
        addChild(scorePanel);
        
        countPanel = new CountPanel();
        countPanel.y = 365; // 盤面の下へ配置 
        addChild(countPanel);
        
        init();
    }
    
    public function init():void
    {
        scorePanel.score = 0;
        scorePanel.targetScore = 0;
        
        missionTF.text = Mission["messageS" + Mission.stage];
        Mission["initS" + Mission.stage]();
        
        scorePanel.incrementScore(0);
        
        if (canvas)
        {
            removeChild(canvas);
            canvas = null;
        }
        canvas = new Sprite();
        addChild(canvas);
        createBlocks();
        
        scorePanel.score = 0;
        countPanel.changeValues();
        countPanel.changeTexts();
    }
    
    // 二次元配列を作る。その配列にブロックを代入。
    private function createBlocks():void
    {
        blocks = new Array(WIDTH);
        
        for (var y:int = 0; y < HEIGHT; y++)
        {
            blocks[y] = new Array(HEIGHT);
            
            for (var x:int = 0; x < WIDTH; x++)
            {
                var block:Block = new Block();
                block.x = x * Block.WIDTH;
                block.y = y * Block.HEIGHT + Panel.CH;
                canvas.addChild(block);
                
                blocks[y][x] = block;
            }
        }
    }
    
    // 二次元配列から引数のブロック位置を検索。
    // 見つかったらPoint(x, y)で返却。
    // 見つからなかったらnullを返す
    public function searchBlock(block:Block):Point
    {
        for (var y:int = 0; y < HEIGHT; y++)
        {
            for (var x:int = 0; x < WIDTH; x++)
            {
                if (blocks[y][x] == block)
                {
                    return new Point(x, y); // ブロックが見つかったので、Pointで返却。
                }
            }
        }
        
        return null; // 見つからなかったのでnullを返す。
    }
    
    // ブロックを消す処理
    // block[ty][tx].colorが引数で渡されたcolorと同じなら削除
    // 上下左右のブロックを調べる
    public function deleteBlock(tx:int, ty:int, color:int):void
    {
        if (tx < 0 || WIDTH <= tx || 
            ty < 0 || HEIGHT <= ty) return; // 配列外ならリターン
        
        if (blocks[ty][tx] == null) return; // nullだったらリターン
        if (blocks[ty][tx].color != color && blocks[ty][tx].color != color + Block.SPECIAL) return; // クリックしたブロックの色と違っていたらリターン
        
        // 条件は満たしたのでブロックを消す
        canvas.removeChild(blocks[ty][tx]);
        blocks[ty][tx] = null;
        countPanel.decrementValue(color);
        deleteCount++;
        
        // 周りの色を調べる
        deleteBlock(tx - 1, ty, color); // 左へ
        deleteBlock(tx + 1, ty, color); // 右へ
        deleteBlock(tx, ty - 1, color); // 上へ
        deleteBlock(tx, ty + 1, color); // 下へ
    }
    
    // ブロックを消すと隙間が空くので縦に詰める処理
    // 左から右へ、下から上へ走査する
    public function verticalPackBlock():void
    {
        for (var x:int = 0; x < WIDTH; x++)
        {
            for (var y:int = HEIGHT - 1; y >= 0; y--)
            {
                if (blocks[y][x] == null) // 隙間が空いているブロックを見つけた
                {
                    for (var yy:int = y - 1; yy >= 0; yy--) // その一つ上から縦に走査
                    {
                        if (blocks[yy][x] != null) // ブロックを見つけたので[y][x]まで詰めなければならない
                        {
                            blocks[y][x] = blocks[yy][x]; // 配列の位置を変更
                            blocks[yy][x] = null;    // 元にあった位置は削除しておく
                            
                            // 0.3秒かけて下にずらす。
                            BetweenAS3.tween(blocks[y][x], {y:y * Block.HEIGHT + Panel.CH}, null, 0.3).play();
                            
                            break;
                        }
                    }
                }
            }
        }
    }
    
    // ブロックを消したとき、まるまる縦に一列空いてしまったら横に詰めなければならない。その処理がこのメソッド。
    // 最下段の左から右へ走査する
    public function horizonPackBlock():void
    {
        var y:int = HEIGHT - 1; // 一番下の段だけ走査
        
        for (var x:int = 0; x < WIDTH; x++)
        {
            if (blocks[y][x] == null) // 一番下の段に何もないということは、ここに右のブロックを詰めなければならない(端の可能性もあるけど
            {
                for (var xx:int = x + 1; xx < WIDTH; xx++) // その一つ右から走査。
                {
                    if (blocks[y][xx] != null) // ブロックを見つけた
                    {
                        for (var yy:int = HEIGHT - 1; yy >= 0; yy--) // 縦の一段をまるまる左に詰める処理
                        {
                            if (blocks[yy][xx] == null) break; // もうずらすブロックがねーよ、ということでbreak
                            
                            blocks[yy][x] = blocks[yy][xx]; // 配列の位置を変更
                            blocks[yy][xx] = null; // 元の位置にnullを入れておく
                            
                            // 0.3秒かけて左にずらす。
                            BetweenAS3.tween(blocks[yy][x], {x:x * Block.WIDTH}, null, 0.3).play();
                        }
                        
                        break;
                    }
                }
            }
        }
    }
    
    // 残っているブロック数を返します
    public function countBlocks():int
    {
        var count:int = 0;
        
        for (var y:int = 0; y < HEIGHT; y++)
        {
            for (var x:int = 0; x < WIDTH; x++)
            {
                if (blocks[y][x]) count++;
            }
        }
        
        return count;
    }
    
    // もう消せるブロックが無いならfalse, まだ消せるブロックがあるようならtrueを返す
    public function endCheck():Boolean
    {
        for (var y:int = 0; y < HEIGHT; y++)
        {
            for (var x:int = 0; x < WIDTH; x++)
            {
                if (blocks[y][x] == null) continue;
                
                // 通常ブロックの処理
                if (blocks[y][x].color < Block.SPECIAL)
                {
                    if (colorCheck(x, y, blocks[y][x].color)) return true; // 周りに同じ色が一つでもあったら
                }
                // 特殊ブロックの処理
                else
                {
                    if (0 <= x - 1 && blocks[y][x - 1] != null && blocks[y][x - 1].color < Block.SPECIAL) return true;
                    else if (x + 1 < WIDTH && blocks[y][x + 1] != null && blocks[y][x + 1].color < Block.SPECIAL) return true;
                    else if (0 <= y - 1 && blocks[y - 1][x] != null && blocks[y - 1][x].color < Block.SPECIAL) return true;
                    else if (y + 1 < HEIGHT && blocks[y + 1][x] != null && blocks[y + 1][x].color < Block.SPECIAL) return true;
                }
            }
        }
        
        return false;
    }
    
    // 周りに自分の色と同じマスが1つでもあったらtrue, なかったらfalse.
    public function colorCheck(tx:int, ty:int, color:int):Boolean
    {
        var check:Boolean = false;
        
        if (0 <= tx - 1 && blocks[ty][tx - 1] != null && (blocks[ty][tx - 1].color == color || blocks[ty][tx - 1].color == color + Block.SPECIAL)) check = true;
        else if (tx + 1 < WIDTH && blocks[ty][tx + 1] != null && (blocks[ty][tx + 1].color == color || blocks[ty][tx + 1].color == color + Block.SPECIAL)) check = true;
        else if (0 <= ty - 1 && blocks[ty - 1][tx] != null && (blocks[ty - 1][tx].color == color || blocks[ty - 1][tx].color == color + Block.SPECIAL)) check = true;
        else if (ty + 1 < HEIGHT && blocks[ty + 1][tx] != null && (blocks[ty + 1][tx].color == color || blocks[ty + 1][tx].color == color + Block.SPECIAL)) check = true;
        
        return check;
    }
}

class CountPanel extends Sprite // 残りブロック数を表示するクラス
{
    public var texts:Array;  // 表示用テキスト
    public var values:Array; // 残りブロック数
    
    public function CountPanel()
    {    
        // ブロックのデザイン
        graphics.beginFill(0x393939);
        graphics.drawRoundRect(0, 50, 380, 50, 20, 20);
        graphics.endFill();
        this.filters = [new BevelFilter(4, 45, 0xFFFFFF, 1, 0x0, 1, 20, 20, 1, 3, "inner")];
        
        values = new Array(Color.COLORS.length); // 色数の長さで初期化
        
        texts = new Array();
        for (var i:int = 0; i < Color.COLORS.length; i++)
        {
            // ブロックを描画
            graphics.beginFill(Color.COLORS[i]);
            graphics.drawRoundRect(Block.WIDTH * i * 2.5 + Block.CW, Block.HEIGHT * 2, Block.WIDTH - Block.CW, Block.HEIGHT - Block.CH, Block.RW, Block.RH);
            graphics.endFill();this.filters = [new BevelFilter(4, 45, 0xFFFFFF, 1, 0x0, 1, 20, 20, 1, 3, "inner")];
            
            // 残り数を表示
            var tf:TextField = new TextField();
            tf.defaultTextFormat = new TextFormat("_typeWriter", 20, 0xFFFFFF, true);
            tf.x = Block.WIDTH + 5 + Block.WIDTH * i * 2.5;
            tf.y = Block.HEIGHT * 2 + 2;
            tf.selectable = false;
            addChild(tf);
            
            texts.push(tf);
        }
    }
    
    // ブロック数再計算
    public function changeValues():void
    {    
        var blocks:Array = Panel(this.parent).blocks;
        for (var i:int = 0; i < Color.COLORS.length; i++)
        {
            values[i] = 0;
        }
        
        for (var y:int = 0; y < Panel.HEIGHT; y++)
        {
            for (var x:int = 0; x < Panel.WIDTH; x++)
            {
                if (Block.SPECIAL <= blocks[y][x].color)
                {
                    values[blocks[y][x].color - Block.SPECIAL]++;
                }
                else
                {
                    values[blocks[y][x].color]++;
                }
            }
        }
    }
    
    public function changeTexts():void
    {
        for (var i:int = 0; i < values.length; i++)
        {
            texts[i].text = values[i];
        }
    }
    
    // 色番号を受け取りその色の残り数を減らす
    public function decrementValue(color:int):void
    {
        values[color]--;
        texts[color].text = values[color];
    }
    
    // 色番号を受け取りその色の残り数を増やす
    public function incrementValue(color:int):void
    {
        values[color]++;
        texts[color].text = values[color];
    }
}

class Block extends Sprite
{
    public static const WIDTH:int = 30;     // ブロックの横幅
    public static const HEIGHT:int = 30;     // ブロックの縦幅
    
    public static const CW:int = 2;            // 補正幅 - ブロック同士がくっつかないように
    public static const CH:int = 2;            // 補正縦
    
    public static const RW:int = 15;        // drawRoundRect()のellipseWidth
    public static const RH:int = 15;        // drawRoundRect()のellipseHeight
    
    public static const SPECIAL:int = 100;  // 特殊ブロックの番号
    
    public var color:int;                    // 自分自身の色。といってもColorクラスのCOLORS配列indexをいれる。ブロック識別用。
    
    public function Block()
    {    
        this.color = Math.random() * Panel.numColor; // colorは色番号を保持しておく。
        //this.color = 1;
        
        if (0.05 >= Math.random())
        {
            graphics.beginFill(Color.COLORS[this.color]); // ランダムで色を選ぶ
            graphics.drawCircle(Block.WIDTH / 2 + Block.CW / 2, Block.HEIGHT / 2 + Block.CH / 2, Block.WIDTH / 2.2);
            graphics.endFill();
            
            this.color += Block.SPECIAL;
        }
        else
        {
            graphics.beginFill(Color.COLORS[this.color]); // ランダムで色を選ぶ
            graphics.drawRoundRect(CW, CH, WIDTH - CW, HEIGHT - CH, RW, RH);
            graphics.endFill();
        }
        
        this.filters = [new BevelFilter(4, 45, 0xFFFFFF, 1, 0x0, 1, 20, 20, 1, 3, "inner")]; // ベベルフィルターでブロックに質感を持たせる
        
        addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); // ブロックをクリックしたらonMouseDown()を呼ぶ
    }
    
    private function onMouseDown(event:MouseEvent):void
    {
        var panel:Panel = this.parent.parent as Panel; // ブロックはパネルに貼り付けるので、ブロックの親がパネルになる。this.parentで取得できる。
        
        var point:Point = panel.searchBlock(this); // ブロックの位置を検索
        if (point)
        {
            // 周りに自分と同じ色が無かったらクリックしたブロックを消すことが出来ないのでreturn
            if (this.color < Block.SPECIAL && !panel.colorCheck(point.x, point.y, this.color))
            {
                return;
            }
            
            if (this.color < Block.SPECIAL)
            {
                // 自分自身と周りのブロックを消す処理。
                // removeChild()と二次元配列から削除。
                // 上のparent.removeChild()を消して、panelに消す処理をまかせることにした。
                panel.deleteCount = 0; // 一度に消える数を数えたいので初期化
                panel.deleteBlock(point.x, point.y, this.color) // 自分自身の位置から削除スタート。
                panel.scorePanel.incrementScore(panel.deleteCount);
                
                panel.verticalPackBlock(); // ブロックを消すと隙間が空くので縦に詰める処理
                panel.horizonPackBlock(); // 同じく横に詰める処理
                if (!panel.endCheck())
                {
                    panel.addChild(new ResultPanel(panel));
                }
            }
            else
            {
                changeColor();
            }
        }
    }
    
    // 特殊ブロックの色を変える
    private function changeColor():void
    {
        var panel:Panel = this.parent.parent as Panel;
        panel.countPanel.decrementValue(this.color - 100);
        panel.countPanel
        this.color = ((this.color - Block.SPECIAL + 1) % Panel.numColor) + Block.SPECIAL;
        panel.countPanel.incrementValue(this.color - 100);
        
        graphics.clear();
        graphics.beginFill(Color.COLORS[this.color - Block.SPECIAL]);
        graphics.drawCircle(Block.WIDTH / 2 + Block.CW / 2, Block.HEIGHT / 2 + Block.CH / 2, Block.WIDTH / 2.2);
        graphics.endFill();
    }
}

// ブロックの色を保持している
class Color
{
    public static const COLORS:Array = [0xED1A3D, 0x00B16B, 0x007DC5, 0xf39800, 0xA757A8];
}