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

Shining Drops

memo
BitmapData.drawでブレンドするよりも
BitmapでBlendModeを指定した方が軽くなる。

画像のプリレンダリング+Bitmap.bitmapDataの差し替え
により描画の負荷を軽減させる。
Get Adobe Flash player
by poiasd 11 Aug 2011
/**
 * Copyright poiasd ( http://wonderfl.net/user/poiasd )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/r4TJ
 */

package {
    
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.filters.BlurFilter;
    import flash.filters.GlowFilter;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;
    import org.libspark.betweenas3.BetweenAS3;
    import org.libspark.betweenas3.easing.Linear;
    
    [SWF (width = "465", height = "465", frameRate = "30", backgroundColor = "0xFFFFFF")]
    
    public class Main extends Sprite {
        
        private const _FOV:Number = 60;
        private const _RADIUS:Number = 130;
        private const _DROP_RADIUS:Number = 5;
        private const _IMAGE_COUNT:int = 30;
        private const _IMAGE_COLOR:uint = 0x2463A2;
        private const _BLUR_SIZE:Number = 8;
        private const _GRAVITY:Number = 0.3;
        
        private var _stageWidth:int;
        private var _stageHeight:int;
        private var _centerX:int;
        private var _centerY:int;
        
        private var _focalLength:Number;
        private var _matrix3D:Matrix3D;
        
        private var _dropImages:Vector.<BitmapData>;
        private var _dropList:Vector.<Drop>;
        
        public function Main() {
            _init();
        }
        
        private function _init():void {
            stage.scaleMode = "noScale";
            stage.align = "TL";
            _stageWidth = stage.stageWidth;
            _stageHeight = stage.stageHeight;
            _centerX = _stageWidth >> 1;
            _centerY = _RADIUS + 30;
            
            // 背景の描画
            graphics.beginFill(0x000000, 1);
            graphics.drawRect(0, 0, _stageWidth, _stageHeight);
            graphics.endFill();
            
            // 焦点距離の計算
            _focalLength = 0.5 * _stageWidth / Math.tan(0.5 * _FOV * Math.PI / 180);
            _matrix3D = new Matrix3D();
            
            // 表示画像のプリレンダリング
            _dropImages = _createDropImages();
            _dropList = new Vector.<Drop>();
            
            addEventListener(Event.ENTER_FRAME, _enterFrameHandler);
        }
        
        private var _rotationY:Number = 0;
        
        private function _enterFrameHandler(event:Event):void {
            // frameごとにDropを3個作る
            _createDrops(3);
            
            // マウス位置により回転させる
            _rotationY += (stage.mouseX - _rotationY) * 0.1;
            _matrix3D.identity();
            _matrix3D.appendRotation( - _rotationY, Vector3D.Y_AXIS);
            
            var length:int = _dropList.length;
            var i:int = _dropList.length;
            while (i--) {
                var drop:Drop = _dropList[i];
                var v:Vector3D = drop.vertex;
                
                if (drop.t.isPlaying) {
                    // tween中は角度により座標を計算
                    var r:Number = _RADIUS * Math.cos(drop.angle1);
                    v.x = r * Math.cos(drop.angle2);
                    v.y = _RADIUS * Math.sin(drop.angle1);
                    v.z = r * Math.sin(drop.angle2);
                } else {
                    // tween後は落下運動
                    var vel:Vector3D = drop.velocity;
                    vel.x *= 0.96;
                    vel.y += _GRAVITY;
                    vel.z *= 0.96;
                    v.x += vel.x;
                    v.y += vel.y;
                    v.z += vel.z;
                }
                
                // 座標変換して投影する
                v = _matrix3D.transformVector(v);
                if (v.z < -_focalLength) break;
                var t:Number = _focalLength / (_focalLength + v.z);
                drop.x = _centerX + v.x * t;
                drop.y = _centerY + v.y * t;
                
                // 画面外に出たら消す
                if (drop.y > _stageHeight + _DROP_RADIUS) {
                    removeChild(drop);
                    _dropList[i] = _dropList[_dropList.length - 1];
                    _dropList.pop();
                    continue;
                }
                
                // 表示サイズに合わせて画像を差し替える
                var index:int = _IMAGE_COUNT * (_RADIUS - v.z) / (2 * _RADIUS) >> 0;
                index = index < 0 ? 0 : index >= _IMAGE_COUNT ? _IMAGE_COUNT - 1 : index;
                drop.image = _dropImages[index];
            }
        }
        
        private function _createDrops(count:int):void {
            for (var i:int = 0; i < count; i++) {
                var drop:Drop = addChild(new Drop(_dropImages[0])) as Drop;
                drop.angle1 = - Math.PI * (0.5 - Math.random() * 0.05);
                drop.angle2 = Math.random() * 2 * Math.PI;
                var toAngle:Number = Math.PI * (0.3 + Math.random() * 0.1);
                var time:Number = 1.5 + Math.random();
                var speed:Number = _RADIUS * (toAngle - drop.angle1) / (time * stage.frameRate) * 0.8;
                var r:Number = - speed * Math.sin(toAngle);
                // tween後の初速を予め計算しておく
                var v:Vector3D = drop.velocity;
                v.x = r * Math.cos(drop.angle2);
                v.y = speed * Math.cos(toAngle);
                v.z = r * Math.sin(drop.angle2);
                // angle1をtweenさせる
                drop.t = BetweenAS3.to(drop, {angle1:toAngle}, time, Linear.linear);
                drop.t.play();
                _dropList.push(drop);
            }
        }
        
        private function _createDropImages():Vector.<BitmapData> {
            // 表示に必要な最小から最大までの画像を_IMAGE_COUNTの数だけ描画する
            // _IMAGE_COUNTの値が小さいと大小の切り替わりが不自然になる
            var images:Vector.<BitmapData> = new Vector.<BitmapData>(_IMAGE_COUNT, true);
            var shape:Shape = new Shape();
            shape.filters = [new GlowFilter(_IMAGE_COLOR, 0.8, _BLUR_SIZE, _BLUR_SIZE, 2, 2), new BlurFilter(2, 2, 2)];
            var g:Graphics = shape.graphics;
            var offset:Number = Math.ceil(_DROP_RADIUS * _focalLength / (_focalLength - _RADIUS) + _BLUR_SIZE);
            var size:Number = offset << 1;
            for (var i:int = 0; i < _IMAGE_COUNT; i++) {
                var z:Number = _RADIUS * (1 - 2 * i / (_IMAGE_COUNT - 1));
                var r:Number = _DROP_RADIUS * _focalLength / (_focalLength + z);
                g.clear();
                g.beginFill(_IMAGE_COLOR);
                g.drawCircle(offset, offset, r);
                g.endFill();
                var image:BitmapData = new BitmapData(size, size, true, 0x00000000);
                image.draw(shape);
                images[i] = image;
            }
            return images;
        }
        
    }
    
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.Sprite;
import flash.geom.Vector3D;
import org.libspark.betweenas3.tweens.ITween;

class Drop extends Sprite {
    
    public var vertex:Vector3D = new Vector3D();
    public var velocity:Vector3D = new Vector3D();
    public var angle1:Number = 0;
    public var angle2:Number = 0;
    public var t:ITween;
    private var _content:Bitmap;
    
    public function Drop(image:BitmapData) {
        _content = addChild(new Bitmap(image, "auto", true)) as Bitmap;
        _content.x = - image.width * 0.5;
        _content.y = - image.height * 0.5;
        blendMode = BlendMode.ADD;
    }
    
    public function get image():BitmapData {
        return _content.bitmapData;
    }
    
    public function set image(value:BitmapData):void {
        _content.bitmapData = value;
    }
    
}