forked from: forked from: 【AS100本ノック】11回目:ろうそく

by es335dotr forked from forked from: 【AS100本ノック】11回目:ろうそく (diff: 1)
♥0 | Line 245 | Modified 2011-09-27 09:47:29 | MIT License
play

ActionScript3 source code

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

// forked from mex_md's forked from: 【AS100本ノック】11回目:ろうそく
/**
 * AS100本ノック
 * 11回目のお題は「ろうそく」
 * あなたなりの「ろうそく」を表現してください。
 **/
 //ろうそくの影がきれいだと思ったんです。
 //クリックでろうそく追加
 //ドラッグでろうそく移動
package 
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.GradientType;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.BlurFilter;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import net.hires.debug.Stats;
    
    [SWF(width = "465", height = "465", frameRate = "30")]
    
    public class FlashTest extends Sprite
    {
        private const ZERO:Point = new Point();
        private const BLUR_FILTER:BlurFilter = new BlurFilter(4, 4, 1);
        private const LIGHT_GRAD:Array = [0xffdaa5, 0xbbaa88, 0x000000];
        private const LIGHT_GRAD_ALPHA:Array = [1,0.7,0];
        private const LIGHT_GRAD_RATIO:Array = [15, 60, 255];
        private const FLAME_GRAD:Array = [0xCCAA88, 0xDD8833, 0xffffff]
        
        private var scaleMat:Matrix = new Matrix(0.5, 0, 0, 0.5, 0, 0);
        private var candles:Vector.<Candle> = new Vector.<Candle>();
        private var draggingCandle:Candle;
        private var shadowCanvas:Sprite = new Sprite();
        private var shadowBitmap:Bitmap;
        private var shadowBMD:BitmapData;
        private var lightCanvas:Bitmap;
        private var lightBMD:BitmapData;
        private var tempLightSprite:Sprite;
        private var lightDrawMt:Matrix = new Matrix();
        private var flameSprite:Sprite = new Sprite();
        private var flames:Vector.<Sprite> = new Vector.<Sprite>();
        private var lightGradMtx:Matrix = new Matrix();
        private var shadowGradArr:Array = [0x333333, 0x000000];
        
        public function FlashTest():void
        {
            createCanvases();//createCanvas
            stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
        }
        
        private function createCandle(xPos:Number, yPos:Number, h:Number, r:Number, power:Number):void
        {
            candles.push(new Candle(xPos, yPos, h, r, power));
            var flameShape:Sprite = flameSprite.addChild(new Sprite()) as Sprite;
            flameShape.blendMode = BlendMode.ADD;
            flameShape.buttonMode = true;
            flames.push(flameShape);
        }
        
        private function createCanvases():void
        {
            tempLightSprite = new Sprite();
            lightBMD = new BitmapData(465, 465, false, 0x000000);
            lightCanvas = new Bitmap(lightBMD);
            lightCanvas.scaleX = lightCanvas.scaleY = 1;
            addChild(lightCanvas);
            shadowBMD = new BitmapData(465 / 2, 465 / 2, true, 0x00000000);
            shadowBitmap = new Bitmap(shadowBMD);
            shadowBitmap.smoothing = true;
            shadowBitmap.blendMode = BlendMode.SUBTRACT;
            shadowBitmap.scaleX = shadowBitmap.scaleY = 2;
            addChild(shadowBitmap);
            addChild(flameSprite);
        }
        
        private function mouseDownHandler(evt:MouseEvent):void 
        {
            var draggable:Sprite = getObjectsUnderPoint(new Point(mouseX, mouseY))[2];
            if (draggable)
            {
                draggingCandle= candles[flames.indexOf(draggable)]
                stage.addEventListener(MouseEvent.MOUSE_MOVE, drag);
                stage.addEventListener(MouseEvent.MOUSE_UP, endDrag)
            }else
            {
                createCandle(mouseX, mouseY, 20 + Math.random() * 15, 7, 350 + Math.random() * 20);
            }
        }
        
        private function endDrag(evt:MouseEvent):void 
        {
            stage.removeEventListener(MouseEvent.MOUSE_UP, endDrag);
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, drag);
        }
        
        private function drag(evt:MouseEvent):void 
        {
            draggingCandle.x = mouseX;
            draggingCandle.y = mouseY;
        }
        
        private function enterFrameHandler(evt:Event):void 
        {
            var l:int = candles.length;
            for (var i:int = 0; i < l; i++ )
            {
                var t:Candle = candles[i];
                if (!t.update())
                {
                    candles.splice(i, 1);
                    flames[i].graphics.clear();
                    flames.splice(i, 1);
                    l--;
                    i--;
                }
            }
            loop();
        }
        
        /*-----------------------------------------//
        //Mainloop
        //------------------------------------------*/
        private function loop(evt:Event = null ):void 
        {
            lightBMD.lock();
            shadowBMD.lock();
            //resetCanvases
            shadowCanvas.graphics.clear();
            lightBMD.fillRect(lightBMD.rect, 0x000000);
            shadowBMD.fillRect(shadowBMD.rect, 0x00000000);
            var l:int = candles.length;
            for (var i:int = 0; i < l; i++ )
            {
                var c:Candle = candles[i];
                //shineLight
                tempLightSprite.graphics.clear();
                lightGradMtx.createGradientBox(c.lightPower, c.lightPower, 0, 0);
                tempLightSprite.graphics.beginGradientFill(GradientType.RADIAL, LIGHT_GRAD, LIGHT_GRAD_ALPHA, LIGHT_GRAD_RATIO,lightGradMtx,"pad","rgb",0);
                tempLightSprite.graphics.drawRect(0,0,c.lightPower, c.lightPower);
                tempLightSprite.graphics.endFill();
                lightDrawMt.createBox(1,1, 0, c.x-c.lightPower*0.5,c.y-c.lightPower*0.5);
                lightBMD.draw(tempLightSprite, lightDrawMt, null, BlendMode.ADD,new Rectangle(c.x-c.lightPower*0.5,c.y-c.lightPower*0.5,c.lightPower,c.lightPower), true);
                //flame
                var flame:Sprite = flames[i];
                flame.graphics.clear();
                flame.x = c.x;
                flame.y = c.y;
                var fCenter:Point = new Point(Math.random()*2-1-20,Math.random()*2-1-20) 
                lightGradMtx.createGradientBox(40, 40,0,fCenter.x ,fCenter.y);
                flame.graphics.beginGradientFill(GradientType.RADIAL,FLAME_GRAD,[1,0.2,0],[25,100,200],lightGradMtx );
                flame.graphics.drawCircle(fCenter.x+20, fCenter.y+20, 40);
                flame.graphics.endFill();
                
                //castShadow
                for (var j:int = 0; j < l; j++ )
                {
                    if (j != i)//自分以外
                    {
                        var anotherCandle:Candle = candles[j];
                        
                        var a:Point = new Point(anotherCandle.x + Math.random() * 28-14, anotherCandle.y + Math.random() * 28-14);//光源の位置にゆらぎを加えとく
                        var vec:Point = c.subtract(a);
                        var dis:Number = vec.length;
                        
                        //接点ポイント計算
                        var tPs:Vector.<Point> = calcTangPoint(anotherCandle, c, c.radius, vec);
                        
                        if (anotherCandle.height > c.height) vec.normalize(dis * (c.height / (anotherCandle.height - c.height)))
                        else vec.normalize(465);//無限になるのでステージサイズの長さに制限
                        
                        //接点
                        var tP1:Point = tPs[0];//接点1(光源point基準)
                        var tP2:Point = tPs[1];//接点1(光源point基準)
                        
                        //影のポイントを作成
                        var sc:Number = 1 + vec.length / dis;
                        //MainShadow
                        var mt:Matrix = new Matrix();
                        var translateX:Number = anotherCandle.x + c.x * sc;
                        var translateY:Number= anotherCandle.y + c.y * sc;
                        mt.createBox(sc, sc, 0, translateX, translateY);
                        var cP1:Point = mt.transformPoint(tP1);//接点1の影がcastされるポイント(ステージ基準)
                        var cP2:Point = mt.transformPoint(tP2);//接点2の影がcastされるポイント(ステージ基準)
                        //SubShadow1
                        mt.createBox(sc, sc, 2 * Math.PI / 180, translateX, translateY);
                        var cP1_l:Point = mt.transformPoint(tP1);//接点1の影がcastされるポイント(ステージ基準)
                        var cP2_l:Point = mt.transformPoint(tP2);//接点2の影がcastされるポイント(ステージ基準)
                        //SubShadow2
                        mt.createBox(sc, sc, -2 * Math.PI / 180, translateX, translateY);
                        var cP1_r:Point = mt.transformPoint(tP1);//接点1の影がcastされるポイント(ステージ基準)
                        var cP2_r:Point = mt.transformPoint(tP2);//接点2の影がcastされるポイント(ステージ基準)
                        
                        tP1.offset(anotherCandle.x+c.x,anotherCandle.y+c.y)//接点1(ステージ基準に変換)
                        tP2.offset(anotherCandle.x + c.x, anotherCandle.y + c.y)//接点2(ステージ基準に変換)
                        
                        //drawShadowShape
                        var alphaArr:Array = [1 - dis / (anotherCandle.lightPower * 0.8), 0];
                        lightGradMtx.createGradientBox(vec.length * 2, vec.length * 2, 0, c.x - vec.length, c.y - vec.length);
                        
                        //MainShadow
                        shadowCanvas.graphics.beginGradientFill(GradientType.RADIAL, shadowGradArr, alphaArr, [0, 127],lightGradMtx);
                        shadowCanvas.graphics.moveTo(tP1.x, tP1.y);
                        shadowCanvas.graphics.lineTo(cP1.x, cP1.y);
                        shadowCanvas.graphics.lineTo(cP2.x, cP2.y);
                        shadowCanvas.graphics.lineTo(tP2.x, tP2.y);
                        shadowCanvas.graphics.lineTo(tP1.x, tP1.y);
                        shadowCanvas.graphics.endFill();
                        //subShadow1
                        shadowCanvas.graphics.beginGradientFill(GradientType.RADIAL,shadowGradArr, alphaArr, [0, 100],lightGradMtx);
                        shadowCanvas.graphics.moveTo(tP1.x, tP1.y);
                        shadowCanvas.graphics.lineTo(cP1_l.x, cP1_l.y);
                        shadowCanvas.graphics.lineTo(cP2_l.x, cP2_l.y);
                        shadowCanvas.graphics.lineTo(tP2.x, tP2.y);
                        shadowCanvas.graphics.lineTo(tP1.x, tP1.y);
                        shadowCanvas.graphics.endFill();
                        //subShadow2
                        shadowCanvas.graphics.beginGradientFill(GradientType.RADIAL, shadowGradArr, alphaArr, [0, 100],lightGradMtx);
                        shadowCanvas.graphics.moveTo(tP1.x, tP1.y);
                        shadowCanvas.graphics.lineTo(cP1_r.x, cP1_r.y);
                        shadowCanvas.graphics.lineTo(cP2_r.x, cP2_r.y);
                        shadowCanvas.graphics.lineTo(tP2.x, tP2.y);
                        shadowCanvas.graphics.lineTo(tP1.x, tP1.y);
                        shadowCanvas.graphics.endFill();
                    }
                }
            }
            shadowBMD.draw(shadowCanvas, scaleMat, null, null, null, true);
            shadowBMD.applyFilter(shadowBMD, shadowBMD.rect, ZERO, BLUR_FILTER);
            lightBMD.unlock();
            shadowBMD.unlock();
        }
        
        /*-----------------------------------------//
        //任意の点と円の接点を求める
        //------------------------------------------*/
        private function calcTangPoint(p:Point, cP:Point, cR:Number,vec:Point):Vector.<Point>
        {
            var returnPoints:Vector.<Point> = new Vector.<Point>();
            var angle:Number = Math.acos(cR / vec.length);
            var offsetAngle:Number = Math.atan2(vec.y, vec.x);
            
            var tP1:Point = Point.polar(cR, offsetAngle+angle);
            var tP2:Point = Point.polar(cR, offsetAngle-angle);
            tP1.offset(-p.x, -p.y);
            tP2.offset(-p.x, -p.y);
            returnPoints.push(tP1);
            returnPoints.push(tP2);
            
            return returnPoints;
        }
    }
}

import flash.geom.Point;
class Candle extends Point
{
    private var fading:Boolean = false;
    private var max_power:Number;
    
    private var _height:Number;
    public function get height():Number { return _height; }
    public function set height(value:Number):void {_height = value;}
    
    private var _radius:Number;
    public function get radius():Number { return _radius; }
    public function set radius(value:Number):void {_radius = value;}
    
    private var _lightPower:Number;
    public function get lightPower():Number { return _lightPower; }
    public function set lightPower(value:Number):void { _lightPower = value;}
    
    public function Candle(xPos:Number, yPos:Number, height:Number,radius:Number, power:Number):void
    {
        super(xPos, yPos);
        this.height = height;
        this.radius = radius;
        this.max_power = power;
        this.lightPower = power;
    }
    
    public function update():Boolean
    {
        if (!fading)
        {
            this.height -= 0.03;
            
            if (height <= 3) fading = true;
        }else
        {
            max_power -= (16 * Math.random() + 2);
            if (max_power <= 0) return false;
        }
        lightPower = max_power*(0.95+0.1*Math.random());
        return true;
    }
}