flash on 2015-8-9

by insocium
ネットで投稿されたメッセージが

クリスマスの夜空を飾ります

クリスマスメッセージは

「Twitter」と「はてなブックマーク」で送ることができます

※追記:11/5(木)、Twitter仕様変更によりTwitter投稿はできなくなりました

※投稿はFlash内のボタンを押して、

Twitterの場合は[]内にコメントを

はてなブックマークの場合は、ブックマークコメントを記入下さい

このFlashはwonderfl上の様々なテクニックを元に作られました

Twitter連動

http://wonderfl.net/code/04d6d1ae7e943b7faab88623ed83404e7a40c5f7

キラキラ3D

http://wonderfl.net/code/c0f513f31389ba07e375331256c2bfa3a8b9006c

文字のパーティクル化

http://wonderfl.net/code/08ec1c2c8da8e9e487867a8e2ab8cddeb75f8986

木を作る再帰関数

 http://wonderfl.net/code/00cbe3ecbf0db2e865bc410a8ea54677c19ba4c6 

配列のシャッフル

http://wonderfl.net/code/8cfa39c9e91a268791142fe605c010dc30338588 

BetweenAS3の時間調整

http://wonderfl.net/code/59af9d8a3cc45e4c2e6fcf12a9bc9ea55b1576e7
♥0 | Line 411 | Modified 2015-08-09 17:13:00 | MIT License
play

ActionScript3 source code

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

/**

 * ネットで投稿されたメッセージが

 * クリスマスの夜空を飾ります

 * 

 * クリスマスメッセージは

 * 「Twitter」と「はてなブックマーク」で送ることができます

 * ※追記:11/5(木)、Twitter仕様変更によりTwitter投稿はできなくなりました

 * 

 * ※投稿はFlash内のボタンを押して、

 * Twitterの場合は[]内にコメントを

 * はてなブックマークの場合は、ブックマークコメントを記入下さい

 * 

 * このFlashはwonderfl上の様々なテクニックを元に作られました

 * 

 * Twitter連動

 * http://wonderfl.net/code/04d6d1ae7e943b7faab88623ed83404e7a40c5f7

 * 

 * キラキラ3D

 * http://wonderfl.net/code/c0f513f31389ba07e375331256c2bfa3a8b9006c

 * 

 * 文字のパーティクル化

 * http://wonderfl.net/code/08ec1c2c8da8e9e487867a8e2ab8cddeb75f8986

 * 

 * 木を作る再帰関数

 * http://wonderfl.net/code/00cbe3ecbf0db2e865bc410a8ea54677c19ba4c6 

 * 

 * 配列のシャッフル

 * http://wonderfl.net/code/8cfa39c9e91a268791142fe605c010dc30338588 

 * 

 * BetweenAS3の時間調整

 * http://wonderfl.net/code/59af9d8a3cc45e4c2e6fcf12a9bc9ea55b1576e7

 * 

 */

package {

    import com.bit101.components.Label;

    

    import flash.display.*;

    import flash.events.*;

    import flash.geom.Matrix;

    import flash.net.*;

    import flash.system.*;

    import flash.text.*;

    import flash.utils.*;

    

    import jp.progression.casts.*;

    import jp.progression.commands.lists.LoaderList;

    import jp.progression.commands.lists.SerialList;

    import jp.progression.commands.net.*;

    import jp.progression.data.getResourceById;

    

    import org.libspark.betweenas3.BetweenAS3;

    import org.libspark.betweenas3.easing.*;

    import org.libspark.betweenas3.tweens.ITween;

    import org.papervision3d.cameras.Camera3D;

    import org.papervision3d.core.effects.*;

    import org.papervision3d.core.geom.Pixels;

    import org.papervision3d.core.geom.renderables.Pixel3D;

    import org.papervision3d.core.math.Number3D;

    import org.papervision3d.materials.*;

    import org.papervision3d.objects.DisplayObject3D;

    import org.papervision3d.objects.primitives.*;

    import org.papervision3d.render.BasicRenderEngine;

    import org.papervision3d.scenes.Scene3D;

    import org.papervision3d.view.Viewport3D;

    import org.papervision3d.view.layer.BitmapEffectLayer;



    [SWF(width=465, height=465, frameRate=30, backgroundColor=0)]

    public class Main extends CastDocument {

        static public const URL_HATENA:String = "http://pipes.yahooapis.com/pipes/pipe.run?_id=a9fa16f111d33689315b50bd196f691e&_render=rss";

        //static public const URL_TWITTER:String = "http://search.twitter.com/search.atom?q=%23XmasMessage&rpp=50";

        static public const URL_TWITTER:String =  "http://clockmaker.jp/labs/091022_pv3d_xmas/search.atom";

        static public const URL_IMG_BG:String = "http://clockmaker.jp/labs/091021_checkmate/assets/bg.png";

        static public const URL_IMG_TITLE:String = "http://clockmaker.jp/labs/091021_checkmate/assets/title.png";

        static public const URL_IMG_BTN_HATENA:String = "http://clockmaker.jp/labs/091021_checkmate/assets/btn-hatena.png";

        static public const URL_IMG_BTN_TWITTER:String = "http://clockmaker.jp/labs/091021_checkmate/assets/btn-twitter.png";

        static private const MAX_PARTICLES:int = 2500;

        // color

        public static const WHITE:uint = 0xFFF0F0F0;

        public static const GREEN:uint = 0xFF008800;

        public static const RED:uint = 0xFFCC0000;

        public static const GOLD:uint = 0xFFFFCC66;

        public static const SILVER:uint = 0xFFCCCCCC;

        public static const COLORS:Array = [WHITE, GREEN, RED, GOLD, SILVER];

        // 3d

        private var scene:Scene3D = new Scene3D();

        private var renderer:BasicRenderEngine = new BasicRenderEngine();

        private var viewport:Viewport3D = new Viewport3D(465, 465);

        private var camera:Camera3D = new Camera3D()

        // 3d objects

        private const MAX_RADIUS:int = 10000;

        private const PIXCEL_MARGIN:Number = 1.25;

        private var textPixels:Pixels;

        private var treePixels:Pixels;

        private var pixelArr:Array = [];

        private var bfx:BitmapEffectLayer;

        private var dmyObjs:Array = [];

        private var tweens:Array = [];

        // 3d camera

        public var cameraDistance:Number  = 1000;

        public var cameraYaw:Number = 0;

        public var cameraPitch:Number = 0;

        // 2d 

        private var canvas:BitmapData;

        private var mtx:Matrix;

        private var progress:ProgressBar;

        private var loading:Label;

        private var loadingTween:ITween;

        // array of objs

        private var data:Array = [];

        // fractal

        private var level:int = 0;

        // data

        private var index:int = 0;

        private const RESET_TIMER:Timer = new Timer(11 * 1000);

        

        /**

         * Progression 4 では atReady から処理が始まります

         */        

        override protected function atReady() : void{

            stage.quality = StageQuality.MEDIUM;

            

            // 3D

            addChild(viewport);

            

            // progress bar

            progress = new ProgressBar();

            progress.value = 0;

            this.addChild(progress)

            progress.x = int(stage.stageWidth / 2 - progress.width/2);

            progress.y = int(stage.stageHeight / 2 + 10);

            

            // loading

            loading = new Label(this, stage.stageWidth / 2 - 33, stage.stageHeight / 2 - 10, "NOW LOADING");

            loadingTween = BetweenAS3.tween(loading, { alpha:1 }, { alpha:0.25 }, 0.05);

            loadingTween = BetweenAS3.serial(loadingTween, BetweenAS3.reverse(loadingTween));

            loadingTween.stopOnComplete = false;

            loadingTween.play();

            

            var context:LoaderContext = new LoaderContext(true);

            var loaderList:LoaderList = new LoaderList(null,

                new LoadBitmapData(new URLRequest(URL_IMG_BG), {context:context}),

                new LoadBitmapData(new URLRequest(URL_IMG_TITLE), {context:context}),

                new LoadURL(new URLRequest(URL_TWITTER), {context:context}),

                new LoadURL(new URLRequest(URL_HATENA), {context:context}),

                new LoadBitmapData(new URLRequest(URL_IMG_BTN_HATENA), {context:context}),

                new LoadBitmapData(new URLRequest(URL_IMG_BTN_TWITTER), {context:context})

                );

            loaderList.onProgress = function():void{

                progress.value = 0.5 * (loaderList.loaded / loaderList.numCommands)

            }

            

            new SerialList(null,

                loaderList,

                function():void{

                    

                    // Twitter連携 by http://wonderfl.net/code/04d6d1ae7e943b7faab88623ed83404e7a40c5f7 (coppieee)

                    default xml namespace = new Namespace("http://www.w3.org/2005/Atom");

                    var xml:XML = XML(getResourceById(URL_TWITTER).data);

                    for (var i:int = 0; i < xml.entry.length(); i++) {

                        // コメントを抽出

                        var comment:String = scan(xml.entry[i].title,/\[(.+)\]/);

                        // RT は除外

                        if(xml.entry[i].title.indexOf("RT") > -1) continue;

                        // コメントなしは除外

                        if(comment == "") continue;

                        // データに追加

                        data.push({

                            img : xml.entry[i].link.(@type == "image/png").@href,

                            name : xml.entry[i].author.name.split(" (")[0],

                            comment : comment

                        });

                    }

                    

                    xml = XML(getResourceById(URL_HATENA).data);

                    

                    for (i = 0; i < xml.channel.item.length(); i++) {

                        if(xml.channel.item[i].description != undefined){

                            comment = xml.channel.item[i].description;

                            var name:String = xml.channel.item[i].title;

                            var imgurl:String = "http://www.st-hatena.com/users/" + name.substr(0,2) + "/" + name + "/profile.gif";

                            data.push({

                                img : imgurl,

                                name : name,

                                comment : comment

                            });

                        }

                    }

                    

                    data = shuffle(data);

                    data = data.slice(0, 8)

                },

                init3d

            ).execute();

        }

        /**

         * Papervision3D関係のごにょごにょ 

         */        

        private function init3d():void {

            // カメラの設定

            camera.target = DisplayObject3D.ZERO;

            // ビットマップエフェクトレイヤー

            bfx = new BitmapEffectLayer(viewport, stage.stageWidth, stage.stageHeight);

            bfx.addEffect(new BitmapColorEffect(1, 1, 1, 0.75));

            viewport.containerSprite.addLayer(bfx);

            // ピクセル3D

            textPixels = new Pixels(bfx);

            scene.addChild(textPixels);

            treePixels = new Pixels(bfx);

            scene.addChild(treePixels);

            

            var i:int;

            var arr:Array = [];

            // snow

            var star:Array = [0xFFFFFFFF, 0xFFcccccc, 0xFF666666, 0xFF333333]

            for (i = 0; i < 1500; i++) {

                treePixels.addPixel3D(new Pixel3D(star[star.length * Math.random() | 0],

                    10000 * (Math.random() - 0.5),

                    10000 * (Math.random()) - 1000,

                    10000 * (Math.random() - 0.5)));

            }

            for (i = 0; i < 255; i++) {

                treePixels.addPixel3D(new Pixel3D(0xFF0066CC,

                    100 * (Math.floor(i / 15) - 7),

                    -1000,

                    100 * (i % 15 - 7)));

            }

            // ダミーオブジェクトを作成

            for (var k:int = 0; k < data.length; k++) {

                dmyObjs[k] = new DisplayObject3D();

                while (true) {

                    var angle:Number = 360 * Math.random();

                    dmyObjs[k].x = 2000 * Math.sin(angle * Number3D.toRADIANS);

                    dmyObjs[k].y = 2000 * (Math.random() - 0.5);

                    dmyObjs[k].z = 2000 * Math.cos(angle * Number3D.toRADIANS);

                    if (k == 0)

                        break;

                    else {

                        if (DisplayObject3D(dmyObjs[k]).distanceTo(dmyObjs[k - 1]) >= 500)

                            break;

                    }

                }

                dmyObjs[k].lookAt(DisplayObject3D.ZERO);

                scene.addChild(dmyObjs[k]);

            }

            for (i = 0; i < MAX_PARTICLES; i++) {

                var p:Pixel3D = new Pixel3D(COLORS[COLORS.length * Math.random() | 0]);

                textPixels.addPixel3D(p);

            }

            drawTree(0, -1000, 0, 1000, 90, GOLD);

            

            loading.text = "NOW RENDERING"

            loading.x = stage.stageWidth / 2 - 39

            var cmd:SerialList = new SerialList();

            var renderIndex:int=0;

            for (i = 0; i < data.length; i++) {

                cmd.addCommand(

                    function():void{

                        preRenderText(renderIndex);

                        createText(renderIndex);

                        renderIndex ++;

                        

                        progress.value = 0.5 + 0.5 * (renderIndex / data.length);

                    },

                    0.05

                );

            }

            cmd.addCommand(

                function():void{

                    // remove loading

                    removeChild(loading);

                    removeChild(progress);

                    loadingTween.stop();

                    loadingTween = null;

                    

                    // ui

                    addChildAt(new CastBitmap(getResourceById(URL_IMG_BG).data), 0);

                    addChild(new CastBitmap(getResourceById(URL_IMG_TITLE).data, "auto", false, {x:20, y:376}));

                    

                    var hatenaBtn:CastButton = new CastButton({x:20, y:433});

                    hatenaBtn.addChild(new Bitmap(getResourceById(URL_IMG_BTN_HATENA).data));

                    hatenaBtn.onCastMouseUp = function():void{

                        navigateToURL(new URLRequest("http://b.hatena.ne.jp/append?http://wonderfl.net/code/d5de28ad1f65364ee33b964101222be41a7320af"));

                    }

                    hatenaBtn.buttonMode = true;

                    addChild(hatenaBtn);

                    

                    var tweetBtn:CastButton = new CastButton({x:240, y:433});

                    tweetBtn.addChild(new Bitmap(getResourceById(URL_IMG_BTN_TWITTER).data));

                    tweetBtn.onCastMouseUp = function():void{

                        navigateToURL(new URLRequest("http://twitter.com/home/?status=" + escapeMultiByte("#XmasMessage [] http://j.mp/xmaswon")));

                    };

                    tweetBtn.buttonMode = true;

                    addChild(tweetBtn);

                    

                    // キラキラロジック by http://wonderfl.net/code/c0f513f31389ba07e375331256c2bfa3a8b9006c (sake)

                    canvas = new BitmapData(720 / 4, 485 / 4, false, 0x000000);

                    var bmp:Bitmap = new Bitmap(canvas, PixelSnapping.NEVER, false);

                    bmp.scaleX = bmp.scaleY = 4;

                    bmp.smoothing = true;

                    bmp.blendMode = BlendMode.ADD;

                    addChildAt(bmp,2);

                    mtx = new Matrix();

                    mtx.scale(0.25, 0.25);

                    // tree

                    drawTree(0, -1000, 0, 1000, 90, GOLD);

                    // タイマーを作る

                    RESET_TIMER.addEventListener(TimerEvent.TIMER, timerHandler);

                    RESET_TIMER.start();

                    // エンターフレーム

                    addEventListener(Event.ENTER_FRAME, loop);

                },

                timerHandler

            );

            cmd.execute();

        }



        private function timerHandler(e:TimerEvent = null):void {

            var i:int;

            var arr:Array = [];

            for (i = 0; i < textPixels.pixels.length; i++) {

                arr[i] = BetweenAS3.serial(

                    BetweenAS3.delay(

                        BetweenAS3.to(textPixels.pixels[i], getRandomPos(), 3, Expo.easeInOut),

                        Math.random()));

            }

            BetweenAS3.serial(

                BetweenAS3.parallelTweens(arr),

                BetweenAS3.func(function():void {

                    setTimeout(motionText, 2 * 1000);

                })

                ).play();

            //

            index++;

            if (index == data.length - 1)

                index = 0;

            //

            var cameraTarget:DisplayObject3D = new DisplayObject3D();

            cameraTarget.copyTransform(dmyObjs[index]);

            cameraTarget.moveBackward(250);

            var dis:Number = cameraTarget.distanceTo(DisplayObject3D.ZERO);

            var rot:Number = Math.atan2(cameraTarget.x, cameraTarget.z);

            

            BetweenAS3.parallel(

                BetweenAS3.delay(

                    BetweenAS3.bezier(this, {

                        cameraYaw: rot,

                        cameraDistance: dis,

                        cameraPitch: cameraTarget.y

                    }, null, getRandomPos(), 10.5, Expo.easeInOut),

                1.0) ,

                BetweenAS3.serial(

                    BetweenAS3.to(camera, {

                        fov: 60

                    }, 4, Sine.easeInOut),

                    BetweenAS3.to(camera, {

                        fov: 50

                    }, 8, Sine.easeInOut)

                    )

                ).play();

        }

        private var preRenderedTests:Array = [];



        private function preRenderText(itemIndex:int):void {

            preRenderedTests[itemIndex] = [];

            var text:TextField = new TextField();

            text.multiline = true;

            text.autoSize = "left";

            text.htmlText = "<font face='Arial' size='24'>WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW</font>";

            trace(data[itemIndex].comment);

            

            var size:int = 24;

            while(text.textWidth * text.textHeight > MAX_PARTICLES){

                text.htmlText = "<font face='Arial' size='" + size +"'>" + data[itemIndex].comment + "</font>"

//                                +"<br><font face='Arial' size='" + size / 2 + "'>" + String(data[itemIndex].name).toUpperCase() + "</font>";

                size--;

            }

            

            var cap:BitmapData = new BitmapData(text.textWidth + 10, text.textHeight, true, 0xFFFFFFFF);

            cap.lock();

            cap.draw(text);

            // particle motion

            var cnt:int = 0;

            for (var i:int = 0; i < text.textWidth + 10; i++) {

                for (var j:int = 0; j < text.textHeight; j++) {

                    if (cap.getPixel(i, j) == 0xFFFFFF)

                        continue;

                    if(preRenderedTests[itemIndex].length >= MAX_PARTICLES) break; 

                    preRenderedTests[itemIndex].push({x: i, y: j, textWidth: text.textWidth, textHeight: text.textHeight});

                }

            }

            cap.unlock();

            cap.dispose();

        }



        /**

         * テキストをBitmapData化してトゥイーンとして作成 

         * @param itemIndex

         */        

        private function createText(itemIndex:int):void {

            var t:DisplayObject3D = dmyObjs[itemIndex];

            // particle motion

            var cnt:int = 0;

            var arr:Array = [];

            for (var i:int = 0; i < preRenderedTests[itemIndex].length; i++) {

                var pix:Object = preRenderedTests[itemIndex][i];

                var p:Pixel3D = textPixels.pixels[i];

                var vec:DisplayObject3D = new DisplayObject3D();

                vec.x = (pix.x - pix.textWidth / 2) * PIXCEL_MARGIN;

                vec.y = (pix.textHeight / 2 - pix.y) * PIXCEL_MARGIN;

                vec.z = 0;

                vec.transform.calculateMultiply(t.transform, vec.transform);

                arr[i] = BetweenAS3.bezier(p, {

                        x: vec.x,

                        y: vec.y,

                        z: vec.z

                    }, null, getRandomPos(), 1.2 + Math.random() * 0.25 + i * 0.002, Expo.easeOut);

            }

            tweens.push(arr);

        }



        private function motionText():void {

            var tw:ITween = BetweenAS3.parallelTweens(tweens[index]);

            // トゥイーンのデュレーションを調整

            tw = BetweenAS3.scale(tw, 3.5 / tw.duration);

            tw.play();

        }



        /**

         * エンターフレームイベント 

         */        

        private function loop(e:Event = null):void {

            // カメラ

            camera.x = cameraDistance * Math.sin(cameraYaw);

            camera.y = cameraPitch;

            camera.z = cameraDistance * Math.cos(cameraYaw);

            

            // レンダリング

            renderer.renderScene(scene, camera, viewport);

            

            // キラキラ

            canvas.fillRect(canvas.rect, 0x000000);

            canvas.draw(viewport, mtx);

        }



        private function getRandomPos():Object {

            return {

                    x: MAX_RADIUS * (Math.random() - 0.5),

                    y: MAX_RADIUS * (Math.random() - 0.5),

                    z: MAX_RADIUS * (Math.random() - 0.5)

                };

        }

        /**

         * 木を作る再帰関数

         * http://wonderfl.net/code/00cbe3ecbf0db2e865bc410a8ea54677c19ba4c6 

         * @param x

         * @param y

         * @param z

         * @param length

         * @param angle

         * @param cf

         * 

         */

        private function drawTree(x:Number, y:Number, z:Number, length:Number, angle:Number, cf:int):void {

            level += 1;

            var destx:Number = x + length * Math.cos(angle * (Math.PI / 180));

            var desty:Number = y + length * Math.sin(angle * (Math.PI / 180));

            var destz:Number = z + length * (Math.random() - 0.5) * 2;

            if (Math.random() < 0.5)

                cf = COLORS[COLORS.length * Math.random() | 0];

            var max:int = 10 - level / 1.5;

            for (var i:int = 0; i < max; i++) {

                treePixels.addPixel3D(new Pixel3D(cf,

                    destx * i / max + x * (max - i) / max,

                    desty * i / max + y * (max - i) / max,

                    destz * i / max + z * (max - i) / max

                    ));

            }

            if (level < 6) {

                drawTree(destx, desty, destz, length * (1 + 3 * Math.random()) * 0.25, angle + 60 * (Math.random() - Math.random()), cf);

                drawTree(destx, desty, destz, length * (1 + 3 * Math.random()) * 0.25, angle + 60 * (Math.random() - Math.random()), cf);

                drawTree(destx, desty, destz, length * (1 + 3 * Math.random()) * 0.25, angle + 60 * (Math.random() - Math.random()), cf);

                drawTree(destx, desty, destz, length * (1 + 3 * Math.random()) * 0.25, angle + 60 * (Math.random() - Math.random()), cf);

            }

            level -= 1;

        }

        

        /**

         * 1行でArrayをシャッフルする by nemu90kWw

         * http://wonderfl.net/code/8cfa39c9e91a268791142fe605c010dc30338588 

         */        

        public function shuffle(array:Array):Array{

            return array.sort(function():int{return int(Math.random()*3)-1});

        }

        

        /**

         * @see http://takumakei.blogspot.com/2009/05/actionscriptrubystringscan.html

         */ 

        //package com.blogspot.takumakei.utils

        //{

        //public

        public function scan(str:String, re:RegExp):Array

        {

            if(!re.global){

                var flags:String = 'g';

                

                if(re.dotall)

                    flags += 's';

                if(re.multiline)

                    flags += 'm';

                if(re.ignoreCase)

                    flags += 'i';

                if(re.extended)

                    flags += 'x';

                re = new RegExp(re.source, flags);                    

            }

            var r:Array = [];

            var m:Array = re.exec(str);

            while(null != m){

                if(1 == m.length)

                    r.push(m[0]);

                else

                    r.push(m.slice(1, m.length));

                m = re.exec(str);

            }

            return r;

        }

        //}

    }

}



import flash.display.*;

class ProgressBar extends Sprite {

    private var edge:Sprite = new Sprite;

    private var cont:Sprite = new Sprite;

    

    private var _value:Number = 0;

    

    public function set value(v:Number):void {

        _value = v;

        cont.scaleX = _value;

    }

    

    public function get value():Number {

        return _value;

    }

    

    public function ProgressBar() {

        edge.graphics.lineStyle(1, 0xFFFFFF);

        edge.graphics.drawRect(0.5, 0.5, 100, 10);

        

        cont.graphics.beginFill(0x555555);

        cont.graphics.drawRect(0, 0, 100, 10);

        

        addChild(cont);

        addChild(edge);

        

        value = 0;

    }

}