HANABI(yanbakaさん作)を勉強中。ランダムに色をつけてみた。
BitmapDataで3Dを表現してみる ver.挫折しました。
*
* HANABI(http://wonderfl.net/c/2PFV) yanbakaさん作
* に感動したので、別アプローチで作成中ですが、
* 動作部分はそのまま拝借したったし、負荷高いし、もう色々と挫折気味;
* 先人の知恵は偉大ですね!
* 素直にForkしておけばよかったと後悔しっぱなしです。
* 本当に勉強になります!
*
* perlineNoiseで花火の色をランダムで出すようにしました。
*
* 自分のに限界を感じたので、オリジナルをForkしてみました。
* http://wonderfl.net/c/R006
*
* 配列の出し入れがオブジェクトの場合Arrayの方が早いとのことでしたので、
* VectorからArrayに変更しました。
* どうなんでしょうか?
/**
* Copyright code ( http://wonderfl.net/user/code )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wou3
*/
/*
* BitmapDataで3Dを表現してみる ver.挫折しました。
*
* HANABI(http://wonderfl.net/c/2PFV) yanbakaさん作
* に感動したので、別アプローチで作成中ですが、
* 動作部分はそのまま拝借したったし、負荷高いし、もう色々と挫折気味;
* 先人の知恵は偉大ですね!
* 素直にForkしておけばよかったと後悔しっぱなしです。
* 本当に勉強になります!
*
* perlineNoiseで花火の色をランダムで出すようにしました。
*
* 自分のに限界を感じたので、オリジナルをForkしてみました。
* http://wonderfl.net/c/R006
*
* 配列の出し入れがオブジェクトの場合Arrayの方が早いとのことでしたので、
* VectorからArrayに変更しました。
* どうなんでしょうか?
*/
package
{
import flash.display.*;
import flash.events.*;
import flash.filters.BlurFilter;
import flash.geom.*;
import flash.text.TextField;
import flash.utils.Timer;
[SWF(width = "500", height = "500", backgroundColor = "0x000000", frameRate = "30")]
public class main_HANABI extends Sprite
{
//変数
private var fromPoint:Vector3D; //出発地点
private var canvas:BitmapData; //ビットマップを描写するカンバス
private var glow:BitmapData; //キラキラ発生用ビットマップデータ
private var beemBMD:BitmapData; //花火のビットマップデータ
private var alphaBMD:BitmapData; //深度調整用のビットマップデータ
private var dammy:Sprite; //ダミーの3D空間
private const PI2:Number = Math.PI * 2; //phi
private var Beems:Array; //ビームのインスタンスを格納する配列
private var BeemPool:Array; //ビームのインスタンスをプールしておくための配列
private var debugTxt:TextField; //デバッグ用のテキスト
private const size:Number=1.5; //ビームの大きさ
private const ADD_NUM:uint = 200; //1フレームで追加するビームの数
private const RADIUS:uint = 70; //球体の半径
private var myTimer:Timer;
private var startPosX:Number;
private var startPosY:Number;
private var colorTransform:ColorTransform;
private var time:Number = 500; //花火を発生させる頻度
//コンストラクタ
public function main_HANABI()
{
//初期化
setInit();
//空間情報を格納するスプライト登録
setCanvas();
//ビームbitmapData作成
createBEEMBMD();
//ループ処理
addEventListener(Event.ENTER_FRAME, loopHandler);
//花火作成
myTimer = new Timer(time);
myTimer.addEventListener(TimerEvent.TIMER, createHANABI);
myTimer.start();
}
//色々初期化
private function setInit():void
{
//ステージの情報
stage.quality = StageQuality.MEDIUM;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//出発地点
fromPoint = new Vector3D(0, 0, 0);
//消失点設定
this.transform.perspectiveProjection.projectionCenter = new Point(stage.stageWidth / 2, stage.stageHeight / 2);
//ダミー用スプライト
dammy = new Sprite();
addChild(dammy);
dammy.x = 0;
dammy.y = 0;
dammy.z = 3000; //2次元へ変換する際の基本深度
//BeemManagerインスタンスをプールさせておく配列の初期化
BeemPool =[];
//実際に動いているBeemManagerインスタンスを格納しておく配列の初期化
Beems = [];
//モーションブラー 軌跡をオレンジ色ぽく
colorTransform= new ColorTransform (0.9, 0.9, 0.9);
}
//bitmapデータを描くカンバス作成
private function setCanvas():void
{
canvas = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
addChild(new Bitmap(canvas));
}
//ビームのBitmapData作成
private function createBEEMBMD():void
{
//ビットマップデータ作成 perlineNoiseで色を作成
beemBMD = new BitmapData(100,100, true, 0);
beemBMD.perlinNoise(100, 100, 7, 1, true, true);
//キラキラマップ
glow = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
var bmp:Bitmap = new Bitmap(glow, PixelSnapping.NEVER, true);
addChild(bmp);
bmp.blendMode = BlendMode.ADD;
bmp.scaleX = bmp.scaleY = 10;
//BitmapDataで、深度α値適用させるためのBitmapDataを作成
var beem:Shape = new Shape();
var beemG:Graphics = beem.graphics;
var gType:String = GradientType.LINEAR;
var gColor:Array = [0x000000, 0x000000];
var gAlpha:Array = [0.1, 1];
var gRatio:Array = [0, 100];
//グラデーションをかける
beemG.beginGradientFill(gType, gColor, gAlpha, gRatio);
beemG.drawRect(0,0,100,size*2);
beemG.endFill();
alphaBMD = new BitmapData(100,size*2, true,0xffffff);
alphaBMD.draw(beem);
}
private function loopHandler(e:Event):void
{
//描画ロック
canvas.lock();
//軌跡をオレンジ色へ
canvas.colorTransform(canvas.rect, colorTransform);
//ループ処理
for (var i:uint = 0; i < Beems.length; i++)
{
var beem:BeemManager = Beems[i];
//抵抗値計算
setFriction(beem);
//3D座標を2Dへコンバート
convert2D(beem);
//画面外にでたら、または、移動量が少量になったらオブジェクトをプールさせる。
if ((beem.toPoint2D.x > stage.stageWidth || beem.toPoint2D.x < 0) || (beem.toPoint2D.y < 0 || beem.toPoint2D.y > stage.stageHeight) || Math.abs(beem.toPoint3D.x) < 0.01 || Math.abs(beem.toPoint3D.y) < 0.01 || Math.abs(beem.toPoint3D.z) < 0.01)
{
poolObject(i);
continue;
}
//カンバスにコピー
canvas.copyPixels(beemBMD, beem.rect, beem.toPoint2D, alphaBMD, new Point(beem.depth, 0), true);
}
//これが無いと始らない すてきなキラキラ
glow.draw(canvas,new Matrix(0.1,0,0,0.1));
//描画ロック解除
canvas.unlock();
}
private function getAbs(n:Number):Number
{
return (n ^ n>>31) - (n>>31);
}
private function createHANABI(e:TimerEvent):void
{
//新しくビームを作成
createBEEM();
}
//ビームインスタンスをプールする
private function poolObject(i:uint):void
{
BeemPool.push(Beems[i]);
Beems.splice(i, 1);
}
//新しくビームを作成
private function createBEEM():void
{
//発射地点 もうね、ほんと行き当たりばったりな設定
startPosX = (stage.stageWidth+2000) *( Math.random()-0.5);
startPosY = -stage.stageHeight*2.5 * Math.random();
//球体の半径
var radius:uint = RADIUS * (Math.random() + 0.8);
//奥行き
var depth:Number = 1000 * Math.random();
//色決定 perlineNoiseビットマップデータの場所指定
var u:uint = Math.random() * 100 | 0;
var v:uint = Math.random() * 100 | 0;
//新しく追加するビームの初期化
for (var i:uint = 0; i < ADD_NUM; i++)
{
//新しくビームを作成
var newBeem:BeemManager;
if ( BeemPool.length != 0){
//プールしているBeemManagerインスタンスがあったら。そこから持ってくる。
newBeem = BeemPool.pop();
}else{
//プールしているBeemManagerインスタンスが無かったら新しく作成。
newBeem = new BeemManager();
}
//座標を決める要素の初期化
var angleAlpha:Number = Math.random()*PI2;
var angleBeta:Number = Math.random()*PI2;
//初期位置設定
newBeem.myPoint3D.x = startPosX;
newBeem.myPoint3D.y = startPosY;
newBeem.myPoint3D.z = depth;
//後で抵抗値で変化させるけど、最初のターゲットポイントを決める。
var posX:Number = radius * Math.cos(angleBeta) * Math.sin(angleAlpha);
var posY:Number = radius* Math.sin(angleBeta);
var posZ:Number = radius * Math.cos(angleBeta) * Math.cos(angleAlpha);
//3D座標へ格納
newBeem.toPoint3D = new Vector3D(posX, posY, posZ);
//作ったビームインスタンスを格納
Beems.push(newBeem);
//色決定
newBeem.rect=new Rectangle(u, v, size, size);
}
}
//抵抗値計算
private function setFriction(beem:BeemManager):void
{
//加速度
beem.toPoint3D.y++;
//抵抗値
beem.toPoint3D.scaleBy(0.9);
//現在位置更新
beem.myPoint3D.incrementBy(beem.toPoint3D);
}
//3D座標を2D座標へコンバート
private function convert2D(beem:BeemManager):void
{
//2D座標へコンバート はっきり言って、ほぼ無意味です 負荷高めるだけかも
beem.toPoint2D = dammy.local3DToGlobal(beem.myPoint3D);
//深度計算 100分割
var myDepth:Number = (beem.toPoint3D.z + RADIUS) / RADIUS*0.5;
beem.depth = myDepth*100 | 0;
}
}
}
import flash.geom.*;
class BeemManager
{
public var toPoint3D:Vector3D;
public var myPoint3D:Vector3D;
public var toPoint2D:Point;
public var depth:uint;
public var rect:Rectangle;
//コンストラクタ
public function BeemManager()
{
toPoint3D = new Vector3D();
myPoint3D = new Vector3D();
toPoint2D = new Point();
rect = new Rectangle();
}
}