forked from: 【AS100本ノック】11回目:ろうそく
AS100本ノック
* 11回目のお題は「ろうそく」
* あなたなりの「ろうそく」を表現してください。
ろうそくの影がきれいだと思ったんです。
クリックでろうそく追加
ドラッグでろうそく移動
/**
* Copyright mex_md ( http://wonderfl.net/user/mex_md )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/zX3D
*/
/**
* 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;
}
}