Beautifl - Flash Gallery

Thumbnail : Pyramids
Pyramids
anatolyzenkov 2009-11-25 see code comments

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

package {
    /**
     * @author Anatoly Zenkov
     * http://anatolyzenkov.com/
     */
     // CLICK TO REGENERATE
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.DisplayObject;
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.MouseEvent;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;

    [SWF(backgroundColor=0x000000,frameRate=41)]
    public class Pyramids extends Sprite {
        private var _bitmap : Bitmap;
        private var _pyramids : Array;
        static public const DOUBLE_PI : Number = 2 * Math.PI;
        static public const HALF_PI : Number = .5 * Math.PI;
        static public var OFFSET_X : Number;
        static public var OFFSET_Y : Number;
        private var _pyramidLayer : Shape;
        private var _gradient : BitmapData;
        private var _currentBitmap : BitmapData;
        private const REFLECTIONS : int = 4;
        private const MAX_PYRAMIDS : int = 6;
        private const SIDES : int = 7;

        public function Pyramids() {
            addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        }

        private function addedToStageHandler(event : Event) : void {
            removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            addChild(_bitmap = new Bitmap());
            _gradient = new BitmapData(600, 600, false);
            _currentBitmap = _gradient;
            var rect : Rectangle = new Rectangle(0, 0, 600, 600 / 255);
            for (var i : int = 0;i < 255;i++) {
                rect.y = i / 255 * 600;
                _currentBitmap.fillRect(rect, i << 16 | i << 8 | i);
            }
            _bitmap.bitmapData = _currentBitmap.clone();
            alignBitmap();
            load("http://assets.anatolyzenkov.com/misc/pool.jpg");
            
            _pyramidLayer = new Shape();
            
            stage.addEventListener(MouseEvent.CLICK, addPyramids);
            addPyramids(null);
            addEventListener(Event.ENTER_FRAME, updatePyramids);
        }

        private function updatePyramids(event : Event) : void {
            _bitmap.bitmapData.copyPixels(_currentBitmap, _currentBitmap.rect, new Point());
            var rects : Array = [];
            var p : Pyramid;
            for each (p in _pyramids) {
                p.update((stage.stageWidth * .5 - mouseX) / stage.stageWidth * 2, (stage.stageHeight * .5 - mouseY) / stage.stageHeight * 2);
                rects[rects.length] = p.getBoundRect();
            }
            var m : Number;
            for (var i : int = 0;i < REFLECTIONS;i++) {
                m = 0.9 + .1 * i / REFLECTIONS;
                var j : int = 0;
                var colortrans : ColorTransform = new ColorTransform(m, m, m);
                for each (p in _pyramids) {
                    _pyramidLayer.graphics.clear();
                    p.draw(_pyramidLayer.graphics, _bitmap.bitmapData);
                    _bitmap.bitmapData.draw(_pyramidLayer, new Matrix(1, 0, 0, 1, -OFFSET_X, -OFFSET_Y), colortrans, BlendMode.NORMAL, rects[j]);
                    j++;
                }
            }
        }

        private function addPyramids(event : MouseEvent) : void {
            _pyramids = [];
            var r : Number;
            var p : Pyramid;
            for (var i : int = 0;i < 2 + (MAX_PYRAMIDS - 2) * Math.random();i++) {
                var points : Array = [];
                for (var j : Number = 0;j < DOUBLE_PI;j += DOUBLE_PI / (2 + (SIDES - 2) * Math.random())) {
                    r = 100 + Math.random() * 50;
                    points[points.length] = new Point(r * Math.cos(j), r * Math.sin(j));
                }
                p = new Pyramid(points);
                p.x = 50 + (stage.stageWidth - 100) * Math.random();
                p.y = 50 + (stage.stageHeight - 100) * Math.random();
                p.scale = .6 + .6 * Math.random();
                p.scale *= p.scale;
                _pyramids[_pyramids.length] = p;
            }
            _pyramids.sortOn("scale");
        }

        private function alignBitmap() : void {
            _bitmap.x = OFFSET_X = int((stage.stageWidth - _bitmap.width) * .5);
            _bitmap.y = OFFSET_Y = int((stage.stageHeight - _bitmap.height) * .5);
        }

        ///////////////////////////////////////////////////////////////////////////////
        // imageLoader stuff
        ///////////////////////////////////////////////////////////////////////////////
        private function load(url : String) : void {
            var imageLoader : Loader = new Loader();
            imageLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, imageLoader_ioErrorEventHandler);
            imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoader_compelteEventHandler);
            imageLoader.load(new URLRequest(url), new LoaderContext(true));
        }

        private function imageLoader_compelteEventHandler(event : Event) : void {
            var content : DisplayObject = (event.target as LoaderInfo).content;
            _currentBitmap = (content as Bitmap).bitmapData;
            _bitmap.bitmapData = _currentBitmap.clone();
            alignBitmap();
            clearLoader(event.target as LoaderInfo);
        }

        private function imageLoader_ioErrorEventHandler(event : IOErrorEvent) : void {
            clearLoader(event.target as LoaderInfo);
        }

        private function clearLoader(loaderInfo : LoaderInfo) : void {
            loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, imageLoader_ioErrorEventHandler);
            loaderInfo.removeEventListener(Event.COMPLETE, imageLoader_compelteEventHandler);
        }
        ///////////////////////////////////////////////////////////////////////////////
    }
}

import flash.display.BitmapData;
import flash.display.Graphics;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;

class Pyramid {
    private var _points : Array;
    private var _centralPoint : Point;
    private var _matrix : Matrix;
    private var _targetAngle : Number;
    public var scale : Number;
    public var angle : Number;
    public var x : Number;
    public var y : Number;
    private var _easyAngle : Number;
    private var _transformedPoints : Array;
    private var _targetMouseX : Number;
    private var _targetMouseY : Number;

    public function Pyramid(points : Array) {
        _centralPoint = new Point();
        _points = points;
        _matrix = new Matrix();
        _targetAngle = Pyramids.DOUBLE_PI * Math.random();
        _easyAngle = Pyramids.DOUBLE_PI * Math.random();
        _targetMouseX = 0;
        _targetMouseY = 0;
        scale = 1;
        angle = Pyramids.DOUBLE_PI * Math.random();
        x = 0;
        y = 0;
    }

    public function draw(graphics : Graphics, bitmapData : BitmapData) : void {
        _transformedPoints = [];
        for each (var p : Point in _points) {
            _transformedPoints[_transformedPoints.length] = _matrix.transformPoint(p);
        }
        var cp : Point = _matrix.transformPoint(_centralPoint);
        cp.x -= 50 * _targetMouseX * scale * scale;
        cp.y -= 50 * _targetMouseY * scale * scale;
        p = new Point();
        var p0 : Point = _transformedPoints[0];
        var p1 : Point;
        var sp : Point = new Point();
        var mtrx : Matrix = new Matrix();
        for (var i : int = 1;i <= _transformedPoints.length;i++) {
            p1 = _transformedPoints[i % _transformedPoints.length];
            sp.x = p0.x - Pyramids.OFFSET_X;
            sp.y = p0.y - Pyramids.OFFSET_Y;
            var a0 : Number = Math.atan2(sp.y, sp.x);
            var a1 : Number = Math.atan2(p0.y - p1.y, p0.x - p1.x);
            var d : Number = 2 * sp.length * Math.cos(Pyramids.HALF_PI - a1 + a0);
            var a : Number = a1 - Pyramids.HALF_PI;
            p.x = Math.cos(a) * d;
            p.y = Math.sin(a) * d;
            
            mtrx.identity();
            mtrx.scale(-1, 1);
            mtrx.rotate(2 * a);
            mtrx.translate(p.x + Pyramids.OFFSET_X, p.y + Pyramids.OFFSET_Y);
            with (graphics) {
                beginBitmapFill(bitmapData, mtrx, true, true);
                moveTo(p0.x, p0.y);
                lineTo(p1.x, p1.y);
                lineTo(cp.x, cp.y);
                lineTo(p0.x, p0.y);
                endFill();
            }
            p0 = p1;
        }
    }

    public function update(tx : Number, ty : Number) : void {
        if (Math.random() < .005) _targetAngle = (6 - 12 * Math.random()) * Pyramids.DOUBLE_PI;
        
        var da : Number = correctAngle(_targetAngle, _easyAngle);
        _easyAngle -= Math.min(Math.abs(da), 0.6) * .1 * sign(da);
        angle -= correctAngle(_easyAngle, angle) * .05;
        tx = Math.max(Math.min(tx, .7), -.7);
        ty = Math.max(Math.min(ty, .7), -.7);
        _targetMouseX += (tx - _targetMouseX) * .1;
        _targetMouseY += (ty - _targetMouseY) * .1;
        _matrix.identity();
        _matrix.scale(scale, scale);
        _matrix.rotate(angle);
        _matrix.translate(x - 300 * _targetMouseX * scale * scale, y - 300 * _targetMouseY * scale * scale);
    }

    public function getBoundRect() : Rectangle {
        var r : Rectangle = new Rectangle(Infinity, Infinity, -Infinity, -Infinity);
        for each (var p : Point in _transformedPoints) {
            if (p.x < r.x) r.x = p.x;
            if (p.y < r.y) r.y = p.y;
            if (p.x > r.width) r.width = p.x;
            if (p.y > r.height) r.height = p.y;
        }
        r.width = r.width - r.x + 2;
        r.height = r.height - r.y + 2;
        r.x -= Pyramids.OFFSET_X + 1;
        r.y -= Pyramids.OFFSET_Y + 1;
        return r;
    }

    public static function sign(n : Number) : Number {
        if (!n) return 0;
        return n > 0 ? 1 : -1;
    }

    public static function correctAngle(a0 : Number, a1 : Number) : Number {
        var d : Number = a1 - a0;
        if (d > Pyramids.HALF_PI) return d % Pyramids.DOUBLE_PI;
        if (d < -Pyramids.HALF_PI) return d % (-Pyramids.DOUBLE_PI);
        return d;
    }
}