forked from: forked from: Flight404 Particles (trails)

by jmbyh521 forked from forked from: Flight404 Particles (trails) (diff: 1)
yd_niku さんの
Flight404 の人のコードをAS3にしてみた ver2
http://wonderfl.kayac.com/code/881224c6000816b64f79b854671a48eeeac7c8d0
をもとに Flash でもそれなりの速度が出るよう書き直した
画像をプリレンダリングしたり
Particle オブジェクトを使い回したり
機を見て BitmapData.draw でなく BitmapData.copyPixels を使ったり等している
trails の描画を少しいい加減にした
他、trails の on/off (T key)、フルクリーンモード等
import com.flashdynamix.utils.SWFProfiler;
♥0 | Line 243 | Modified 2016-06-08 16:23:05 | MIT License
play

ActionScript3 source code

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

// forked from alpicola's forked from: Flight404 Particles (trails)
// forked from 5ivestar's Flight404 Particles (trails)
// forked from 5ivestar's Flight404 Particles
// yd_niku さんの
// Flight404 の人のコードをAS3にしてみた ver2
// http://wonderfl.kayac.com/code/881224c6000816b64f79b854671a48eeeac7c8d0
// をもとに Flash でもそれなりの速度が出るよう書き直した

// 画像をプリレンダリングしたり
// Particle オブジェクトを使い回したり
// 機を見て BitmapData.draw でなく BitmapData.copyPixels を使ったり等している

// trails の描画を少しいい加減にした
// 他、trails の on/off (T key)、フルクリーンモード等

package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.text.*;
    import flash.ui.*;
    //import com.flashdynamix.utils.SWFProfiler;

     [SWF(backgroundColor="#000000", frameRate="40")]

    public class Particles extends Sprite {

        private var canvas:BitmapData;
        private var bitmap:Bitmap;
        private var emitter:Emitter;
        private var mousePressed:Boolean;
        private var stats:TextField;

        public function Particles() {
            //SWFProfiler.init(stage, this);
            //stage.quality = "low";
            stage.scaleMode = "noScale";
            stage.align = "TL";
            //Mouse.hide();

            canvas = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
            bitmap = new Bitmap(canvas)
            addChild(bitmap);
            emitter = new Emitter();

            /*stats = new TextField();
            stats.x = 5;
            stats.y = 5;
            stats.autoSize = "left";
            stats.textColor = 0xFFFFFF;
            addChild(stats);*/

            addEventListener(Event.ENTER_FRAME, render);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
                mousePressed = true;
            });
            stage.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void {
                mousePressed = false;
            });
            stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void {
                var key:String = String.fromCharCode(e.charCode);
                if (key == 't' || key == 'T') emitter.allowTrails = !emitter.allowTrails;
            });
            stage.addEventListener(FullScreenEvent.FULL_SCREEN, function(e:FullScreenEvent):void {
                canvas = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
                bitmap.bitmapData = canvas;
            });

            var menu:ContextMenu = new ContextMenu();
            var item:ContextMenuItem = new ContextMenuItem("Full Screen");
            contextMenu = menu;
            menu.hideBuiltInItems();
            menu.customItems.push(item);
            menu.addEventListener(ContextMenuEvent.MENU_SELECT, function(e:ContextMenuEvent):void {
                switch (stage.displayState) {
                    case "normal":     item.enabled = true;  break;
                    case "fullScreen": item.enabled = false; break;
                }
            });
            item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:ContextMenuEvent):void {
                stage.displayState = "fullScreen";
            });
        }

        public function render(e:Event):void {
            emitter.moveTo(mouseX, mouseY);
            if (mousePressed) emitter.emitParticles(5);
            canvas.lock();
            canvas.fillRect(canvas.rect, 0x000000);
            emitter.render(canvas);
            canvas.unlock();
        }

    }
}

import flash.display.*;
import flash.geom.*;

class Emitter {

    private var position:Vector3D = new Vector3D();
    private var velocity:Vector3D = new Vector3D();
    private var particles:Vector.<Particle> = new Vector.<Particle>(500, true);
    private var candicates:uint = 0;
    private var lineBuffer:Shape = new Shape();
    public  var allowTrails:Boolean = true;

    public function Emitter() {
        var n:int = particles.length;
        while (n--) particles[n] = new Particle();
    }

    public function moveTo(x:Number, y:Number):void {
        velocity.x = (x - position.x) * 0.35;
        velocity.y = (y - position.y) * 0.35;
        position.incrementBy(velocity);
    }

    public function render(canvas:BitmapData):void {
        var n:int, m:int = 0;
        n = particles.length;
        var particle:Particle;
        var g:Graphics = lineBuffer.graphics;
        while (n--) {
            particle = particles[n];
            if (particle.alive) {
                particle.render(canvas);
                if (allowTrails) {
                    particle.renderTails(lineBuffer);
                    if ((++m & 31) == 0) {
                        canvas.draw(lineBuffer, null, null, "add");
                        g.clear();
                    }
                }
            } else if (candicates) {
                candicates--;
                var p:Vector3D, v:Vector3D;
                p = position.clone();
                p.x += (Math.random() - 0.5) * 5;
                p.y += (Math.random() - 0.5) * 5;
                p.z += (Math.random() - 0.5) * 5;
                v = velocity.clone();
                v.x += (Math.random() - 0.5) * 10;
                v.y += (Math.random() - 0.5) * 10;
                v.z += (Math.random() - 0.5) * 10;
                particle.init(p, v);
                particle.render(canvas);
            }
        }
        if (allowTrails) {
            canvas.draw(lineBuffer, null, null, "add");
            g.clear();
        }
    }

    public function emitParticles(n:uint):void {
        candicates += n;
    }

}

class Particle {

    //static private const FLOOR_LEVEL:uint = 360;
    static private const Z_FAR:uint = 1000;
    static private const IMAGES:Vector.<BitmapData> = loadImages();

    private var position:Vector3D;
    private var velocity:Vector3D;
    private var trail:Vector.<Vector3D> = new Vector.<Vector3D>();
    private var lifeSpan:uint;
    private var age:uint;
    private var bounce:uint;
    private var images:Vector.<BitmapData>;
    private var matrix:Matrix = new Matrix();
    private var transform:ColorTransform = new ColorTransform();
    private var point:Point = new Point();
    private var rectangle:Rectangle = new Rectangle();
    private var yAxis:Vector3D;
    public  var alive:Boolean = false;

    static private function loadImages():Vector.<BitmapData> {
        var s:Shape = new Shape();
        var matrix:Matrix = new Matrix();
        matrix.createGradientBox(32, 32);
        s.graphics.beginGradientFill(GradientType.RADIAL, [0xFFFFFF, 0xFF0000, 0xFF0000], [1, 0.2, 0], [0, 88, 255], matrix);
        s.graphics.drawCircle(16, 16, 16);
        s.graphics.endFill();
        var images:Vector.<BitmapData> = new Vector.<BitmapData>(64 * 32, true);
        var transform:ColorTransform = new ColorTransform();
        for (var i:int = 0; i < 64; i++) {
            for (var j:int = 1; j < 32; j++) {
                var image:BitmapData = new BitmapData(j, j, true, 0x000000);
                matrix.identity();
                matrix.scale(j/32, j/32);
                transform.blueOffset = i * 4;
                image.draw(s, matrix, transform);
                images[int(i*32+j)] = image;
            }
        }
        return images;
    }

    public function Particle() {
        images = IMAGES;
        yAxis  = Vector3D.Y_AXIS;
    }

    public function init(p:Vector3D, v:Vector3D):void {
        position = p;
        velocity = v;
        lifeSpan = (Math.random() + 0.5) * 60;
        age    = 0;
        bounce = 0;
        alive  = true;
        trail.splice(0, trail.length);
    }

    public function render(canvas:BitmapData):void {
        var d:Number = position.x + position.y + position.z;
        velocity.x += Math.cos(d) * 0.5;
        velocity.y += Math.sin(d) * 0.5 + 0.35;
        velocity.z += Math.cos(d) * -0.5;
        if (position.y > canvas.height * 0.6) {
            velocity.scaleBy(0.75);
            velocity.y *= -0.5;
            bounce++;
            age += bounce * 3;
        } else {
            age++;
        }
        position.incrementBy(velocity);

        if (age < lifeSpan) {
            var perspective:Number = Z_FAR / (Z_FAR - position.z);
            var diameter:uint = (lifeSpan - age) * perspective * 0.5;
            var color:uint = 32 * age / lifeSpan;
            if (diameter <= 0 || 32 <= diameter) return;
            if (age < 20) {
                matrix.tx = position.x * perspective - diameter * 0.5;
                matrix.ty = position.y * perspective - diameter * 0.5;
                canvas.draw(images[int(color * 32 + diameter)], matrix, null, "add");
            } else {
                point.x = position.x * perspective - diameter * 0.5;
                point.y = position.y * perspective - diameter * 0.5;
                rectangle.width = rectangle.height = diameter;
                canvas.copyPixels(images[int(color * 32 + diameter)], rectangle, point, null, null, true);
            }
        } else {
            alive = false;
        }
    }

    public function renderTails(buffer:Shape):void {
        var length:int = trail.length;
        var p:Vector3D = velocity.crossProduct(yAxis);
        p.normalize();
        if ((age & 1) == 0 || length == 0) {
            trail[int(length)]   = position.clone();
            trail[int(length+1)] = p;
        } else {
            trail[int(length-2)] = position.clone();
            trail[int(length-1)] = p;
        }

        var g:Graphics = buffer.graphics;
        var v:Vector3D, p1:Vector3D, p2:Vector3D, p3:Vector3D, p4:Vector3D;
        var f1:Number, f2:Number, f3:Number, f4:Number;
        p1 = p2 = trail[0];
        f1 = f2 = Z_FAR / (Z_FAR - p1.z);
        length = length >> 1;
        for (var i:int = 1; i < length; i++) {
            var per:Number = i / length;
            v = trail[int(i*2+1)].clone();
            v.scaleBy(per * (lifeSpan - age) * 0.02)
            p3 = trail[int(i*2)].add(v);
            v.negate();
            p4 = trail[int(i*2)].add(v);
            f3 = Z_FAR / (Z_FAR - p3.z);
            f4 = Z_FAR / (Z_FAR - p4.z);
            g.beginFill((per * 0xFF) << 16 | (per * 0.5 * 0xFF) << 8 | (1.5 - per) * 0xFF, per);
            g.moveTo(p1.x * f1, p1.y * f1);
            g.lineTo(p2.x * f2, p2.y * f2);
            g.lineTo(p4.x * f4, p4.y * f4);
            g.lineTo(p3.x * f3, p3.y * f3);
            g.endFill();
            f1 = f3;
            f2 = f4;
            p1 = p3;
            p2 = p4;
        }

        if (length > 5) {
            trail.slice(0, 2);
        }
    }

}