Beautifl - Flash Gallery

Thumbnail : What the hex
What the hex
bkzen 2010-12-24 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

/**
 * @see        http://yizzle.com/whatthehex/
 * @see        http://wonderfl.net/c/cuY4 (ランキング+Tweet部分)
 * @author    jc at bk-zen
 */
package  
{
    import com.bit101.components.HUISlider;
    import com.bit101.components.Style;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.DropShadowFilter;
    import net.wonderfl.utils.WonderflAPI;
    import org.libspark.betweenas3.BetweenAS3;
    import org.libspark.betweenas3.tweens.ITween;
    
    [SWF (backgroundColor = "0x333333", frameRate = "30", width = "465", height = "465")]
    public class WhatTheHex extends Sprite 
    {
        private const resultTxts: Array = ["stage click to start", "guess the color", "correct!", "stage click and try again.\nthat color was \n", "next stage", "game over", "time up", "stage click to restart"];
        private const topY: int = 85;
        private const maxBtns: int = 48;
        private const baseTime: int = 10000;
        private const LIFE: int = 10;
        
        private var title: LLabel, colorLabel: LLabel, lifeLabel: LLabel, scoreLabel: LLabel, resultLabel: LLabel, pointLabel: LLabel;
        private var difficulty: HUISlider;
        private var diffValue: int, _score: int, _life: int;
        private var stageW: int, stageH: int, areaW: int, areaH: int;
        private var targetColor: uint;
        private var isGameStart: Boolean;
        private var bgSprite: Sprite, bg: Graphics;
        private var areaSprite: Sprite;
        private var container: CButtonContainer;
        private var resTween: ITween;
        private var _point: int;
        private var correctCnt: int;
        private var timer:LimitTimer;
        private var loadingLabel: LLabel;
        private var clickSp: Sprite, clickBg: Graphics;
        
        public function WhatTheHex() 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e: Event = null): void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            Style.LABEL_TEXT = 0xFFFFFF;
            loadingLabel = new LLabel(this, 0, 0, "Now Loading...", 2);
            loadingLabel.x = stage.stageWidth  - loadingLabel.width  >> 1;
            loadingLabel.y = stage.stageHeight - loadingLabel.height >> 1;
            var obj: Object = loaderInfo.parameters;
            ScoreWindowLoader.init(this, new WonderflAPI(obj), compLib);
        }
        
        private function compLib():void 
        {
            removeChild(loadingLabel);
            // UI を作る
            var f: Array = [new DropShadowFilter(1, 45, 0, 1, 5, 5, 100, 1)];
            addChild(bgSprite = new Sprite());
            addChild(areaSprite = new Sprite());
            container = new CButtonContainer(areaSprite, maxBtns, onClickBtn);
            bg = bgSprite.graphics;
            title = new LLabel(this, 0, 0, "What the Hex", 2.5);
            colorLabel = new LLabel(this, 0, title.y + title.height, " ", 3);
            lifeLabel = new LLabel(this, 0, 0, "LIFE : " + life);
            scoreLabel = new LLabel(this, 10, 0, "SCORE : 0");
            resultLabel = new LLabel(this, 0, 0, " ", 3, 0xCCCCCC);
            difficulty = new HUISlider(this, 0, 0, "difficulty");
            difficulty.labelPrecision = 0;
            difficulty.setSliderParams(3, maxBtns, diffValue = 5);
            pointLabel = new LLabel(this, 0, 0, "+score", 1.5, 0xCCCCCC);
            timer = new LimitTimer(this, "limit time");
            title.filters = colorLabel.filters = lifeLabel.filters = scoreLabel.filters = resultLabel.filters = difficulty.filters = pointLabel.filters = timer.label.filters = f;
            addChild(clickSp = new Sprite());
            clickBg = clickSp.graphics;
            // 一旦リサイズ
            onResize();
            stage.addEventListener(Event.RESIZE, onResize);
            stage.addEventListener(MouseEvent.MOUSE_UP, onChanged); // HUISlider の Change Event は 変わるたびに送出されるから Stage の MouseUp を取得する。
            resultLabel.alpha = 0;
            showRes(resultTxts[0]);
            clickSp.addEventListener(MouseEvent.CLICK, onClickStart);
            timer.addEventListener(Event.COMPLETE, onTimer);
        }
        
        /**
         * タイムアップ
         * @param    e
         */
        private function onTimer(e:Event):void 
        {
            container.allChangeEnabled(false);
            damage();
        }
        
        /**
         * ボタンが押された時の処理
         * @param    e
         */
        private function onClickBtn(e: Event):void 
        {
            var c: CButton = CButton(e.target);
            if (c.color == targetColor)
            {
                container.allHide();
                score += _point;
                correctCnt ++;
                timer.stop();
                showRes(resultTxts[2], function(): void {
                    showRes(resultTxts[4], function(): void {
                        initColors();
                    }, true)
                }, true);
            }
            else
            {
                container.allChangeEnabled(false);
                difficulty.enabled = false;
                point -= diffValue >> 1;
                damage(c);
            }
        }
        
        /**
         * ダメージ処理
         * @param    c
         */
        private function damage(c: CButton = null):void 
        {
            if (--life > 0) 
            {
                if (c)
                {
                    showRes(resultTxts[3] + getColorStr(c.color), function(): void {
                        clickSp.mouseEnabled = true;
                        clickSp.addEventListener(MouseEvent.CLICK, onClickRetry);
                    });
                }
                else showRes(resultTxts[6], initColors, true);
            }
            else 
            {
                showRes(resultTxts[5], function(): void {
                    ScoreWindowLoader.show(score, onCloseEndWindow);
                });
            }
        }
        /**
         * ScoreWindow の表示が終了
         */
        private function onCloseEndWindow():void 
        {
            showRes(resultTxts[7], function(): void {
                clickSp.mouseEnabled = true;
                clickSp.addEventListener(MouseEvent.CLICK, onClickStart);
            });
        }
        
        /**
         * リトライ
         * @param    e
         */
        private function onClickRetry(e:MouseEvent):void 
        {
            clickSp.mouseEnabled = false;
            clickSp.removeEventListener(MouseEvent.CLICK, onClickRetry);
            hideRes(function(): void {
                container.allChangeEnabled(true);
                difficulty.enabled = true;
            })
        }
        
        /**
         * スタート
         * @param    e
         */
        private function onClickStart(e: MouseEvent): void 
        {
            clickSp.mouseEnabled = false;
            clickSp.removeEventListener(MouseEvent.CLICK, onClickStart);
            score = 0, life = LIFE, correctCnt = 0, _point = 0;
            hideRes(startStage);
        }
        
        /**
         * result label に文字表示
         * @param    str        : 表示する文字列
         * @param    onComp    : Tween終了ハンドラ andHide が true の時は消えた後に送出される。
         * @param    andHide    : ついでに消す
         */
        private function showRes(str: String, onComp: Function = null, andHide: Boolean = false):void 
        {
            resultLabel.alpha = 0, resultLabel.text = str;
            resultLabel.draw();
            resultLabel.x =  stageW - resultLabel.width >> 1;
            resultLabel.y =  areaSprite.y - resultLabel.height;
            if (resTween && resTween.isPlaying) resTween.stop(), resTween.onComplete && resTween.onComplete();
            resTween = BetweenAS3.to(resultLabel, { alpha: 1 }, 0.5);
            if (andHide) resTween.onComplete = function(): void { hideRes(onComp) }
            else resTween.onComplete = onComp;
            resTween.play();
        }
        /**
         * result label を消す
         * @param    onComp
         */
        private function hideRes(onComp: Function = null): void
        {
            if (resTween && resTween.isPlaying) resTween.stop(), resTween.onComplete && resTween.onComplete();
            resTween = BetweenAS3.to(resultLabel, { alpha: 0 }, 0.5);
            resTween.onComplete = onComp;
            resTween.play();
        }
        
        /**
         * 難易度が変わった時の処理
         * @param    e
         */
        private function onChanged(e: Event):void 
        {
            if (diffValue != int(difficulty.value)) 
            {
                diffValue = difficulty.value;
                if (isGameStart) initColors();
            }
        }
        
        /**
         * ゲーム開始
         */
        private function startStage(): void 
        {
            showRes(resultTxts[1], function(): void {
                isGameStart = true;
            }, true);
            initColors();
        }
        
        /**
         * CButton 初期化
         */
        private function initColors(): void 
        {
            point = diffValue * Math.sqrt(diffValue);
            colorLabel.text = getColorStr(targetColor = container.init(diffValue));
            colorLabel.draw();
            colorLabel.x  = stageW - colorLabel.width >> 1;
            container.layout(areaW, areaH);
            timer.start((20 + diffValue) * baseTime - correctCnt * 100); // TODO 適当に 20 秒
        }
        
        /**
         * 0x000000 のように6桁の文字列にする(Hex)
         * @param    col
         * @return
         */
        private function getColorStr(col: uint): String
        {
            var str: String = col.toString(16);
            var i: int = str.length;
            for (; i < 6; i ++) str = "0" + str;
            return "0x" + str.toUpperCase();
        }
        
        /**
         * 画面のリサイズ
         * @param    e
         */
        private function onResize(e: Event = null): void 
        {
            stageW = stage.stageWidth, stageH = stage.stageHeight;
            bg.clear();
            bg.beginFill(0x333333);
            bg.drawRect(0, 0, stageW, stageH);
            bg.beginFill(0x444444);
            bg.drawRoundRect(10, topY, areaW = stageW - 20, areaH = stageH - topY - 40, 5, 5);
            clickBg.clear();
            clickBg.beginFill(0, 0);
            clickBg.drawRect(10, topY, areaW, areaH);
            
            areaSprite.x  =  stageW                          >> 1;
            areaSprite.y  = (areaH                           >> 1) + topY;
            title.x       =  stageW - title.width            >> 1;
            colorLabel.x  =  stageW - colorLabel.width       >> 1;
            difficulty.x  =  stageW - difficulty.width  + 20 >> 1;
            difficulty.y  =  stageH - difficulty.height - 15;
            lifeLabel.x   =  stageW - lifeLabel.width   - 10;
            lifeLabel.y   =  stageH - lifeLabel.height  - 20;
            scoreLabel.y  =  stageH - scoreLabel.height - 20;
            resultLabel.x =  stageW - resultLabel.width      >> 1;
            resultLabel.y =  areaSprite.y - resultLabel.height;
            pointLabel.x  =  stageW - pointLabel.width       >> 1;
            pointLabel.y  =  difficulty.y - pointLabel.height - 5;
            timer.y       =  stageH - 16;
            timer.setSize(stageW);
            container.layout(areaW, areaH);
        }
        
        public function get life():int { return _life; }
        
        public function set life(value:int):void 
        {
            lifeLabel.text = "LIFE : " + (_life = value);
            lifeLabel.draw();
            lifeLabel.x = stageW - lifeLabel.width - 10;
        }
        
        public function get score():int { return _score; }
        
        public function set score(value:int):void 
        {
            scoreLabel.text = String(_score = value);
        }
        
        public function get point(): int { return _point; }
        
        public function set point(value:int):void 
        {
            pointLabel.text = "+" + (_point = value);
            pointLabel.draw();
            pointLabel.x = stageW - pointLabel.width >> 1;
        }
    }
}
import com.bit101.components.Label;
import com.bit101.components.Style;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import net.wonderfl.utils.WonderflAPI;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.Quad;
import org.libspark.betweenas3.tweens.ITween;

/**
 * サイズ・色変更付きの Label
 */
class LLabel extends Label
{
    protected var _scale: Number = 1;
    
    function LLabel(parent: DisplayObjectContainer = null, x: int = 0, y: int = 0, text: String = "", scale: Number = 1, color: uint = 0xFFFFFF)
    {
        var c: uint = Style.LABEL_TEXT;
        Style.LABEL_TEXT = color;
        super(parent, x, y, text);
        Style.LABEL_TEXT = c;
        scaleX = scaleY = _scale = scale;
    }
    override public function get width():  Number { return super.width    * _scale; }
    override public function get height(): Number { return _tf.textHeight * _scale; }
}

/**
 * Color 表示用のボタン
 */
class CButton extends Sprite
{
    private var _color: uint, _size: int, targetSize: int;
    function CButton()
    {
        buttonMode = true, mouseEnabled = false, alpha = 0;
        addEventListener(MouseEvent.CLICK, onClick);
    }
    
    /**
     * ボタンをクリックしたときのアクション(非表示にするだけ)
     * @param    e
     */
    private function onClick(e: MouseEvent): void 
    {
        hide();
    }
    
    /**
     * 色の初期化
     * @param    color
     */
    public function init(color: uint, size: int): void 
    {
        mouseEnabled = visible = true;
        _color = color, alpha = 0;
        setSize(size);
    }
    
    /**
     * サイズ変更
     */
    public function setSize(value: int): void 
    {
        targetSize = value >> 1;
        BetweenAS3.to(this, { alpha: 1, size: value }, 0.5, Quad.easeOut).play();
    }
    
    /**
     * ボタンを非表示にして押せなくする。
     */
    public function hide():void 
    {
        mouseEnabled = false;
        var tw: ITween = BetweenAS3.to(this, { alpha: 0, size: 0 }, 0.5, Quad.easeOut);
        tw.onComplete = function(): void { visible = false; }
        tw.play();
    }
    
    public function get size(): int { return _size; }
    public function set size(value: int): void
    {
        _size = value;
        var g: Graphics = graphics, d: int = value - 4, t: int = targetSize - (d >> 1);
        g.clear();
        g.beginFill(_color);
        g.drawRoundRect(t, t, d, d, 4, 4);
    }
    
    public function get color(): uint { return _color; }
}
/**
 * CButton をもじゃもじゃするやつ
 */
class CButtonContainer
{
    private const SIZE: int = 40;
    private var parent: Sprite;
    private var maxBtns: int;
    private var btns: Array/*CButton*/ = [];
    private var _diffValue:int;
    function CButtonContainer(parent: Sprite, maxBtns: int, handler: Function)
    {
        this.parent = parent, this.maxBtns = maxBtns;
        for (var i: int = 0; i < maxBtns; i++) (btns[i] = parent.addChild(new CButton())).addEventListener(MouseEvent.CLICK, handler);
    }
    
    /**
     * 初期化
     * @param    diffValue : ボタンの個数(難易度)
     * @return    正解の色
     */
    public function init(diffValue: int): uint 
    {
        var i: int, n: int = Math.random() * (_diffValue = diffValue), c: CButton, targetColor: uint = getRandomColor();
        for (i = 0; i < maxBtns; i++) 
        {
            c = btns[i];
            if (i < diffValue) c.init(i == n ? targetColor : getRandomColor(), SIZE)
            else c.hide();
        }
        return targetColor;
    }
    
    /**
     * タイル状に並べる
     * TODO: もっときれいに並べる。適当過ぎた・・・
     * @param    areaW    : エリアの幅
     * @param    areaH    : エリアの高さ
     */
    public function layout(areaW: int, areaH: int): void 
    {
        var i: int, c: CButton, tx: int, ty: int, n: int;
        var maxRows: int = (areaW - 120) / SIZE;
        if (maxRows < 2) maxRows = 2;
        var numCols: int = (_diffValue - 1) / maxRows + 1;
        if (numCols == 1) maxRows = _diffValue;
        for (i = 0; i < _diffValue; i++) 
        {
            c = btns[i];
            tx = i % maxRows;
            ty = i / maxRows;
            n = ty < numCols - 1 ? maxRows : _diffValue % maxRows || maxRows;
            c.x = (tx - n / 2) * SIZE;
            c.y = (ty - numCols / 2) * SIZE;
        }
    }
    
    /**
     * ランダムな色取得
     * @return
     */
    public function getRandomColor(): uint
    {
        var r: int = (0xCC * Math.random() + 0x33) & 0xFF, g: int = (0xCC * Math.random() + 0x33) & 0xFF, b: int = (0xCC * Math.random() + 0x33) & 0xFF;
        return (r << 0x10) | (g << 0x08) | (b << 0x00);
    }
    
    /**
     * 全部消す
     */
    public function allHide(): void 
    {
        for (var i: int = 0; i < _diffValue; i++) btns[i].hide();
    }
    
    /**
     * 全部の enabled を変える
     * @param    value
     */
    public function allChangeEnabled(value: Boolean):void 
    {
        for (var i: int = 0; i < _diffValue; i++) btns[i].mouseEnabled = value; 
    }
}

/**
 * 時間制限を設けるためのもじゃもじゃするやつ。
 */
[Event(name="complete", type="flash.events.Event")]
class LimitTimer extends Sprite
{
    private var _label: Label;
    private var _time: int, currentTime: Number, passTime: int;
    private var line: Shape;
    private var _size: int, _lineSize: int;
    function LimitTimer(parent: DisplayObjectContainer, label: String)
    {
        mouseEnabled = mouseChildren = false;
        addChild(line = new Shape());
        _label = new Label(this, 0, -2, label);
        _label.draw();
        parent.addChild(this);
    }
    
    public function setSize(size: int): void
    {
        if (_size == size) return;
        _lineSize = (_size = size) - 8;
        var g: Graphics = graphics;
        g.clear();
        g.beginFill(0x555555);
        g.drawRect(2, 2, _size - 4, 12);
        _label.x = size - _label.width >> 1;
        draw();
    }
    
    private function draw():void 
    {
        var g: Graphics = line.graphics;
        g.clear();
        g.beginFill(0x333333);
        g.drawRect(4, 4, _lineSize * passTime / _time || 1, 8);
    }
    
    public function start(time: int): void
    {
        _time = time, passTime = 0, currentTime = new Date().getTime();
        removeEventListener(Event.ENTER_FRAME, loop);
        addEventListener(Event.ENTER_FRAME, loop);
    }
    
    public function stop(): void
    {
        removeEventListener(Event.ENTER_FRAME, loop);
    }
    
    private function loop(e:Event):void 
    {
        var t: Number = new Date().getTime(), d: int = t - currentTime;
        if (d < 0) passTime -= 1000 / stage.frameRate
        else passTime += d;
        currentTime = t;
        draw();
        if (passTime >= _time)
        {
            removeEventListener(Event.ENTER_FRAME, loop);
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
    
    public function get label():Label { return _label; }
}
class ScoreWindowLoader
{
    private static var _top: DisplayObjectContainer;
    private static var _api: WonderflAPI;
    private static var _content: Object;
    //private static const URL: String = "wonderflScore.swf";
    private static const URL: String = "http://swf.wonderfl.net/swf/usercode/5/57/579a/579a46e1306b5770d429a3738349291f05fec4f3.swf";
    private static const TWEET: String = "Playing What the Hex [score: %SCORE%] #wonderfl";
    
    public static function init(top: DisplayObjectContainer, api: WonderflAPI, handler: Function): void 
    {
        _top = top, _api = api;
        var loader: Loader = new Loader();
        var comp: Function = function(e: Event): void
        {
            loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, comp);
            _content = loader.content;
            handler();
        }
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, comp);
        loader.load(new URLRequest(URL), new LoaderContext(true));
    }
    
    /**
     * Wonderfl の Score API 用
     * ランキング表示から Tweet までをひとまとめにしたSWF素材を使う
     * @param    score            : 取得スコア
     * @param    closeHandler    : Window が閉じるイベントハンドら
     */
    public static function show( score: int, closeHandler: Function): void
    {
        var window: DisplayObject = _content.makeScoreWindow(_api, score, "What the Hex", 1, TWEET);
        var close: Function = function(e: Event): void
        {
            window.removeEventListener(Event.CLOSE, close);
            closeHandler();
        }
        window.addEventListener(Event.CLOSE, close);
        _top.addChild(window);
    }
    
}