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

Movie 15 Puzzle

[企画] 皆で一つのものを作ろうぜ!
15パズルを皆で作ろう!
皆が作るのは -> http://wonderfl.net/c/mJwf
をフォークして動くムービーを作る。
フォークしたら企画に勝手に参加!
難しい絵柄を作ってみよう!
注意:簡単に無理ゲーが作れてしまうので、難しすぎないように工夫してみてくださいw
(15パズルなのに MovieJigsawPuzzle って名前になっているのは気のせいです。)
@author jc at bk-zen.com
/**
 * Copyright bkzen ( http://wonderfl.net/user/bkzen )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/yb0z
 */

package  
{
    import com.adobe.serialization.json.JSON;
    import com.bit101.components.Label;
    import com.bit101.components.List;
    import com.bit101.components.NumericStepper;
    import com.bit101.components.ProgressBar;
    import com.bit101.components.PushButton;
    import com.bit101.components.VBox;
    import flash.display.DisplayObject;
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.geom.ColorTransform;
    import flash.net.navigateToURL;
    import flash.net.SharedObject;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.utils.escapeMultiByte;
    import net.wonderfl.data.APICodeData;
    import net.wonderfl.data.APIForksData;
    import net.wonderfl.utils.WonderflAPI;
    
    /**
     * [企画] 皆で一つのものを作ろうぜ!
     * 15パズルを皆で作ろう!
     * 皆が作るのは -> http://wonderfl.net/c/mJwf
     * をフォークして動くムービーを作る。
     * フォークしたら企画に勝手に参加!
     * 難しい絵柄を作ってみよう!
     * 注意:簡単に無理ゲーが作れてしまうので、難しすぎないように工夫してみてくださいw
     * (15パズルなのに MovieJigsawPuzzle って名前になっているのは気のせいです。)
     * @author jc at bk-zen.com
     */
    [SWF (backgroundColor = "0xFFFFFF", frameRate = "60", width = "465", height = "465")]
    public class MovieJigsawPuzzle extends Sprite 
    {
        private const MP_URL: String = "http://wonderfl.net/c/mJwf";
        private const NG: Array = [];
        
        public function MovieJigsawPuzzle() 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e: Event = null): void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            //
            var obj: Object = loaderInfo.parameters;
            
            api = new WonderflAPI(obj);
            
            var box: VBox = new VBox(this);
            progressTitle = new Label(box, 0, 0, "Loading...");
            progressBar = new ProgressBar(box);
            progressBar.setSize(200, 10);
            box.draw();
            box.move(465 - box.width >> 1, 465 - box.height >> 1);
            
            saveData = SharedObject.getLocal(api.appID);
            dataArray = [];
            cnt = 1;
            loadCode(api.getAppID(MP_URL));
        }
        
        private var api: WonderflAPI;
        private var dataArray: Array;
        private var mpData: Array;
        private var cnt: int;
        private var loadCnt: int;
        private var progressBar:ProgressBar;
        private var progressTitle: Label;
        private var listParent: Sprite;
        private var list: List;
        private var selectData: MPData;
        private var levelStep: NumericStepper;
        private var levelLabel: Label;
        private var playBtn: PushButton;
        private var bestScore: Label;
        private var tweetBtn: PushButton;
        private var game:Game;
        private var codeBtn:PushButton;
        
        private function loadCode(id: String): void
        {
            if (NG.indexOf(id) >= 0) 
            {
                loadCnt++;
                return;
            }
            var urlLoader: URLLoader = new URLLoader();
            urlLoader.addEventListener(Event.COMPLETE, onLoadCode);
            urlLoader.load(api.apiCode(id));
        }
        
        private function onLoadCode(e: Event): void 
        {
            loadCnt++;
            var urlLoader: URLLoader = URLLoader(e.target);
            urlLoader.removeEventListener(Event.COMPLETE, onLoadCode);
            var data: APICodeData = new APICodeData(JSON.decode(urlLoader.data));
            if (!data.isOK) return;
            if (data.code.compileOK) dataArray.push(data);
            if ((cnt += data.code.forked_count) > 0) loadFork(data.code.id);
            onProgress();
            if (cnt == loadCnt) onComp();
        }
        
        private function loadFork(id: String): void
        {
            var urlLoader: URLLoader = new URLLoader();
            urlLoader.addEventListener(Event.COMPLETE, onLoadFork);
            urlLoader.load(api.apiForks(id));
        }
        
        private function onLoadFork(e: Event): void 
        {
            var urlLoader: URLLoader = URLLoader(e.target);
            urlLoader.removeEventListener(Event.COMPLETE, onLoadFork);
            var data: APIForksData = new APIForksData(JSON.decode(urlLoader.data));
            for (var i: int = 0; i < data.length; i++) loadCode(data.forks[i].id);
        }
        
        private function onProgress():void 
        {
            progressBar.maximum = cnt, progressBar.value = loadCnt;
        }
        
        private function onComp():void 
        {
            progressTitle.text = "Initialize...";
            progressBar.maximum = cnt = dataArray.length, progressBar.value = loadCnt = 0, mpData = [];
            for (var i: int = 0; i < cnt; i++) { new MPData(dataArray[i], onCompHandler); }
        }
        
        private function onCompHandler(data: MPData):void 
        {
            if (data.isOK) loadCnt = mpData.push(data);
            else --cnt;
            progressBar.maximum = cnt, progressBar.value = loadCnt;
            if (cnt == loadCnt) onCompInit();
        }
        
        private function onCompInit():void 
        {
            while (numChildren > 0) removeChildAt(0);
            addChild(listParent = new Sprite());
            list = new List(listParent);
            list.listItemClass = MPListItem;
            list.setSize(450, 385);
            list.move(7, 7);
            list.items = mpData;
            list.listItemHeight = 55;
            list.addEventListener(Event.SELECT, onSelect);
            levelLabel        = new Label(listParent, 7, 400, "LEVEL : ");
            levelStep         = new NumericStepper(listParent, 45, 400);
            playBtn           = new PushButton(listParent, 358, 400, "PLAY", onClickStart);
            bestScore         = new Label(listParent, 7, 418, "BEST SCORE : ");
            tweetBtn          = new PushButton(listParent, 358, 418, "TWEET", onClickTweet);
            codeBtn           = new PushButton(listParent, 258, 400, "CODE", onClickCodeBtn);
            levelStep.minimum = 1;
            codeBtn.enabled = levelStep.enabled = playBtn.enabled = tweetBtn.enabled = false;
            playBtn.transform.colorTransform = new ColorTransform(1, 0.8, 0.8);
            
        }
        
        private function onClickCodeBtn(e: Event):void 
        {
            navigateToURL(new URLRequest("http://wonderfl.net/c/" + selectData.id));
        }
        
        private function onSelect(e: Event): void 
        {
            selectData        = MPData(list.selectedItem);
            levelStep.value   = 1;
            levelStep.maximum = selectData.level;
            codeBtn.enabled = levelStep.enabled = playBtn.enabled = true;
            tweetBtn.enabled  = (uint(saveData.data[selectData.id]) > 0);
            bestScore.text    = "BEST SCORE : " + uint(saveData.data[selectData.id]) + " [ms]";
        }
        
        private function onClickStart(e: Event):void 
        {
            removeChild(listParent);
            addChild(game ||= new Game(tweet, showMenu));
            game.x = 12;
            stage.frameRate = selectData.frameRate;
            game.start(selectData, levelStep.value);
        }
        
        private function showMenu():void 
        {
            removeChild(game);
            addChild(listParent);
        }
        
        private function onClickTweet(e: Event):void 
        {
            tweet(selectData.title.substr(0, 50), uint(uint(saveData.data[selectData.id]) / 1000));
        }
        
        private function tweet(title: String, score: uint): void
        {
            navigateToURL(new URLRequest("http://twitter.com/share?" + 
                "text=" + escapeMultiByte("Playing MJP [" + title + "] [score : " + score + " sec] #wonderfl") + 
                "&url=" + escapeMultiByte("http://wonderfl.net/c/" + api.appID)//+ 
                //"&via=" + escapeMultiByte("bkzen")
            ));
        }
    }
}
import com.bit101.components.Component;
import com.bit101.components.HBox;
import com.bit101.components.Label;
import com.bit101.components.ListItem;
import com.bit101.components.Panel;
import com.bit101.components.PushButton;
import com.bit101.components.VBox;
import com.bit101.components.Window;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.net.SharedObject;
import flash.net.URLRequest;
import flash.utils.describeType;
import flash.utils.getTimer;
import net.wonderfl.data.APICodeData;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.Cubic;
import org.libspark.betweenas3.tweens.ITween;

var saveData: SharedObject;

class MPData
{
    private var data: APICodeData;
    private var compHandler: Function;
    private var swf: Loader, thumb: Loader, user: Loader;
    private var _isOK: Boolean;
    private var _disp: DisplayObject;
    private var _color: uint;
    private var _frameRate: uint;
    private var _level: uint;
    private var cnt: uint;
    function MPData(data: APICodeData, compHandler: Function)
    {
        this.data = data, this.compHandler = compHandler;
        swf = new Loader(), thumb = new Loader(), user = new Loader();
        swf.contentLoaderInfo.addEventListener(Event.COMPLETE, onComp);
        thumb.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompThumb);
        user.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompThumb);
        swf.load(new URLRequest(data.code.swf + "?t=" + new Date().getTime()));
        user.load(new URLRequest(data.code.user.icon));
        thumb.load(new URLRequest(data.code.thumbnail));
    }
    
    private function onComp(e: Event): void 
    {
        swf.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComp);
        var obj: Object = Object(swf.content);
        try 
        {
            var o: Object = { };
            obj.initialize(o);
            _disp = o["disp"];
            if (_disp == null) throw new Error("MPError #01");
            _color = (o["color"] == null ? 0x000000 : uint(o["color"]));
            _frameRate = (o["frameRate"] == null ? 60 : uint(o["frameRate"])) || 1;
            _frameRate = _frameRate > 60 ? 60 : _frameRate;
            _level = (o["level"] == null ? 1 : uint(o["level"])) || 1;
            var xml: XML = describeType(obj);
            var start: XML = xml.method.(@name == "start")[0];
            var end: XML = xml.method.(@name == "end")[0];
            _isOK = start.parameter.length() == 1 && start.parameter[0].@type == "uint";
            _isOK = _isOK && end.toXMLString() != "" && end.parameter.length() == 0;
            if (!_isOK) throw new Error("MPError #02");
        }
        catch (err:Error)
        {
            trace("hoge:", err);
            _isOK = false;
            _disp = null;
            swf.unloadAndStop();
            thumb.unloadAndStop();
            user.unloadAndStop();
            thumb.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompThumb);
            user.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompThumb);
            swf = thumb = user = null;
        }
        cnt++;
        check();
    }
    
    private function onCompThumb(e: Event): void 
    {
        var loader: Loader = Loader(e.target.loader);
        loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompThumb);
        cnt++, loader.width = loader.height = 45;
        check();
    }
    
    private function check():void 
    {
        if (cnt == 3) compHandler(this);
    }
    
    public function unload(): void 
    {
        if (swf) 
        {
            swf.contentLoaderInfo.addEventListener(Event.COMPLETE, onComp);
            swf.unloadAndStop();
        }
        if (user)
        {
            user.unloadAndStop();
            user.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompThumb);
        }
        if (thumb) 
        {
            thumb.unloadAndStop();
            thumb.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompThumb);
        }
        swf = thumb = user = null;
    }
    
    public function start(level: uint): void
    {
        if (swf && swf.content) Object(swf.content).start(level);
    }
    
    public function end():void 
    {
        if (swf && swf.content) Object(swf.content).end();
    }
    
    public function get isOK(): Boolean { return _isOK; }
    
    public function get disp(): DisplayObject { return _disp; }
    
    public function get color(): uint { return _color; }
    
    public function get frameRate(): uint { return _frameRate; }
    
    public function get level(): uint { return _level; }
    
    public function get title(): String { return data.code.title; }
    
    public function get thumbnail(): DisplayObject { return thumb; }
    
    public function get icon(): DisplayObject { return user; }
    
    public function get name(): String { return data.code.user.name; }
    
    public function get id(): String { return data.code.id; }
}

class MPListItem extends ListItem
{
    function MPListItem(parent: DisplayObjectContainer = null, xpos: Number = 0, ypos: Number = 0, data: Object = null) { super(parent, xpos, ypos, data); }
    
    protected var thumb: Panel;
    protected var user:  Panel;
    protected var level: Label;
    protected var userName: Label;
    
    override protected function addChildren(): void 
    {
        _label = new Label(this, 55, 2), level = new Label(this, 55, 17), userName = new Label(this, 55, 32);
        thumb = new Panel(this, 5, 5), thumb.setSize(45, 45), user = new Panel(this, 388, 5), user.setSize(45, 45);
    }
    
    override public function draw(): void 
    {
        dispatchEvent(new Event(Component.DRAW));
        graphics.clear();
        graphics.beginFill(_selected ? _selectedColor : (_mouseOver ? _rolloverColor : _defaultColor));
        graphics.drawRect(0, 0, _width, _height);
        if (_data == null) return;
        while (thumb.content.numChildren > 0) thumb.content.removeChildAt(0);
        thumb.content.addChild(_data.thumbnail);
        while (user.content.numChildren > 0) user.content.removeChildAt(0);
        user.content.addChild(_data.icon);
        _label.text   = "TITLE : " + _data.title;
        level.text    = "LEVEL : " + _data.level + "    SCORE : " + uint(saveData.data[_data.id]) + " [ms]";
        userName.text = "USER  : " + _data.name;
    }
}

class Game extends Sprite
{
    private var bmd: BitmapData, rect: Rectangle, time: Label, blank: Piece, id: String, title: String;
    private var disp: DisplayObject, color: uint, startTime: int, isClear: Boolean = false, clearTime: uint;
    private var pieces: Vector.<Piece> = new Vector.<Piece>(16, true);
    private var clearWindow: Window, scoreLabel: Label;
    private var retryBtn: PushButton, menuBtn: PushButton, tweetBtn: PushButton;
    private var _tweetHandler:Function;
    private var _selectData:MPData;
    private var _level:int;
    private var _showMenu:Function;
    function Game(tweetHandler: Function, showMenu: Function) 
    {
        _showMenu = showMenu;
        _tweetHandler = tweetHandler;
        bmd = new BitmapData(440, 440, false, 0), rect = bmd.rect;
        time = new Label(this);
        time.x = 12, time.y = 440;
        time.text = "TIME : ";
        for (var i: int = 0; i < 16; i++) addChild(pieces[i] = new Piece(bmd, i)).addEventListener(MouseEvent.CLICK, onClick);
        //
        blank       = pieces[15];
        clearWindow = new Window(null, 0, 0, "PUZZLE CLEAR");
        scoreLabel  = new Label(clearWindow.content);
        retryBtn    = new PushButton(clearWindow.content, 0, 20, "RETRY", onClickRetry);
        menuBtn     = new PushButton(clearWindow.content, 0, 40, "RETURN TO MENU", onClickMenu);
        tweetBtn    = new PushButton(clearWindow.content, 0, 60, "TWEET", onClickTweet);
    }
    
    private function onClickTweet(e: Event):void 
    {
        _tweetHandler(title.substr(0, 50), clearTime / 1000);
    }
    
    private function onClickRetry(e: Event):void 
    {
        removeChild(clearWindow);
        _selectData.end();
        start(_selectData, _level);
    }
    
    private function onClickMenu(e: Event):void 
    {
        removeChild(clearWindow);
        removeEventListener(Event.ENTER_FRAME, loop);
        isClear = false;
        clearTime = startTime = 0;
        _showMenu();
    }
    
    public function start(selectData:MPData, level: int):void 
    {
        _level = level;
        _selectData = selectData;
        _selectData.start(level);
        isClear = false;
        clearTime = 0;
        shuffle();
        disp = selectData.disp, color = selectData.color, startTime = getTimer(), id = selectData.id, title = selectData.title;
        addEventListener(Event.ENTER_FRAME, loop);
        for (var i: int = 0; i < 16; i++) pieces[i].move(i);
    }
    
    private function shuffle(): void 
    {
        for (var i: int = 0, to: int ; i < 200; i++ ) { for (var j: int = 0; j < 2; j++ ) { // 0 - 15 で偶数回シャッフルすれば解けない問題は作られない。
            var from: int = Math.random() * 15;
            do { to = Math.random() * 15; } while (from == to);
            swap(from, to);
        }}
    }
    private function swap(from: int, to: int, slideX: int = 0, slideY: int = 0): void
    {
        var p: Piece = pieces[from];
        pieces[from] = pieces[to];
        pieces[to] = p;
        if (slideX != 0)
        {
            pieces[from].slideX(slideX);
            pieces[to].slideX(- slideX);
        }
        if (slideY != 0)
        {
            pieces[from].slideY(slideY);
            pieces[to].slideY(- slideY);
        }
    }
    
    private function onClick(e: MouseEvent): void 
    {
        if (isClear) return;
        var b: int = blank.point, c: int = Piece(e.target).point, i: int, n: int, m: int, j: int, k: int;
        if ((b % 4) == (c % 4)) 
        {
            m = (b - c) / 4 | 0, n = (m < 0 ? - m : m), j = m < 0 ? -1 : 1;
            for (i = 0; i < n; i++) swap(k = b - i * j * 4, k - j * 4, 0, j);
        }
        else if ((b / 4 | 0) == (c / 4 | 0))
        {
            m = (b - c) % 4, n = (m < 0 ? - m : m), j = m < 0 ? -1 : 1;
            for (i = 0; i < n; i++) swap(k = b - i * j, k - j, j);
        }
        var check: Boolean = true;
        for (i = 0; i < 16; i++) 
        {
            if (!pieces[i].check()) check = false;
        }
        if (check)
        {
            for (i = 0; i < 16; i++) pieces[i].clear();
            clearTime = (getTimer() - startTime);
            scoreLabel.text = time.text = "TIME : " + clearTime + " [ms]";
            if ((uint(saveData.data[id]) == 0) || uint(saveData.data[id]) > clearTime) 
            {
                saveData.data[id] = clearTime;
                saveData.flush();
            }
            isClear = true;
            clearWindow.x = stage.stageWidth  - clearWindow.width  >> 1;
            clearWindow.y = stage.stageHeight - clearWindow.height >> 1;
            addChild(clearWindow);
        }
    }
    
    private function loop(e: Event): void 
    {
        bmd.lock();
        bmd.fillRect(rect, color);
        bmd.draw(disp);
        bmd.unlock();
        if (!isClear) time.text = "TIME : " + (getTimer() - startTime) + " [ms]";
    }
}

class Piece extends Sprite
{
    private var bmp: Bitmap, sh: Shape, index: int;
    public var point: int;
    private var tw:ITween;
    function Piece(bmd: BitmapData, index: int)
    {
        addChild(bmp = new Bitmap(bmd));
        bmp.mask = addChild(sh = new Shape());
        sh.graphics.beginFill(0);
        sh.graphics.drawRect(1, 1, 108, 108);
        bmp.x = - (x = (index % 4)     * 110);
        bmp.y = - (y = (index / 4 | 0) * 110);
        this.index = index;
    }
    public function move(index: int): void
    {
        point = index;
        x = (index % 4)     * 110;
        y = (index / 4 | 0) * 110;
        if (index == 15) visible = false;
    }
    public function slideX(i: int): void
    {
        tw = BetweenAS3.tween(this, { x: ((point % 4) + i) * 110 }, { x: (point % 4) * 110 }, 0.2, Cubic.easeInOut);
        tw.play();
        point += i;
    }
    public function slideY(i: int): void
    {
        tw = BetweenAS3.tween(this, { y: ((point / 4 | 0) + i) * 110 }, { y: (point / 4 | 0) * 110 }, 0.2, Cubic.easeInOut);
        tw.play();
        point += i * 4;
    }
    
    public function check(): Boolean
    {
        return index == point;
    }
    
    public function clear():void 
    {
        if (tw && tw.isPlaying) tw.onComplete = onComp;
        else onComp();
    }
    
    private function onComp():void 
    {
        tw = null;
        sh.graphics.clear();
        sh.graphics.beginFill(0);
        sh.graphics.drawRect(0, 0, 110, 110);
        visible = true;
    }
}