POPSブログ

CreateJS BitmapData 1ピクセルに分解してパーティクル

278

  Category:  javascript2014/02/16 pops 

画像をBitmapDataで1ピクセルに分解して(100x100=10000個)、集合拡散を繰り返すパーティクルです。BitmapDataクラスを利用しました。まだ問題点は有りますが一応軽快に可動します。
easeljs-0.7 でのテストです。

 

CreateJS BitmapData パーティクル テスト


BitmapDataを扱いたいので kudox さんが配布されている BitmapDataクラス を使用しました。下記のページに詳細が有ります。サンプル、マニュアル(日本語)も完備されています。


【参照】kudox.jp記事: BitmapData for EaselJS ver1.00 リリースのお知らせ

EaselJSにActionScript3.0と同様のインターフェイスを備えたBitmapDataクラスを追加する「BitmapData for EaselJS」を作ってみました。MITライセンスで公開していますので、商用でも無料でお使い頂けます。

...と言うことなので早速利用してみました。


 

DEMO


CreateJS BitmapData パーティクル テスト、(createJS063.js)

このページはHTML5では有りませんので、デモページでご覧ください。「IE7.8」ではご覧いただけません。
/// 注意、ブラウザ、マシン性能により描画品質などに大きな差が有ります事了承下さい ///



Chrome Firefox Safari(Win) IE9、で動作確認済み。 Safari(Mac)、IE10、は未確認です。


 

HTML JS CSS


使用するライブラリ

easeljs preloadjs tweenjs

配布元 : CreateJS createjs.com


ライブラリの読み込み

ダウンロードしたJSを使用する場合。記述は一例です。(バージョン 0.7.0 使用)


<script type="text/javascript" src="js/easeljs-0.7.0.min.js"></script>
<script type="text/javascript" src="js/preloadjs-0.4.0.min.js"></script>
<script type="text/javascript" src="js/tweenjs-0.5.0.min.js"></script>
<script type="text/javascript" src="js/bitmapdata-1.0.0.min.js"></script>

重要、バージョン違いでは動かない場合が有りますので必ず合わせて下さい。
尚、別途にkudoxさんの bitmapdata-1.0.0.min.js が必要です。

このデモでは、tweenjs-0.5.0.min.jsは不要です。必要な処理方法も最後に記載。


HTML (HTML5)


<div id="demo-wrap">
	<div id="image-box" class="radius">
		<canvas id="mainCanvas" width="640" height="300"></canvas>
	</div>
</div>

JS

createJS063.js、JS名は任意に変更可。注意、easeljs-0.7用です。

Firefoxで パーティクルが消滅して表示出来なくなる不具合が有ります。ページ最後に対処方法を記載していますのでご覧下さい。
このJSは、2014/02/22/修正しました。



//日本語
//createJS063.js
//BitmapDataパーティクル
//easeljs-0.7用

//------------------------------------------------------
//初期設定
//タイマーの使用、true false
var timerUse=true;//true
//次ぎ画像切り替え時間タイマー値 2000-5000
var time=2000;

//out完了/Fade速度
var speed=1200;//Fade処理をする場合
//canvasの大きさ/全てこの値を使用
var canvasWidth=640;
var canvasHeight=300;
//画像の大きさ
var imageWidth=100;
var imageHeight=100;

//パーティクルOUTの使用 true false
var outUse=true;
//INパーティクル表示時間5000-10000
var pin_time=5000;

//パーティクルステージ内true、外false
var in_stage=false;
//内側、散らばす範囲 1-2
var range_v=1.5;
//外側、散らばす範囲 2-4
var range2_v=2;

//TEXT
var textUse=true;

//画像manifestリスト/idは利用していない
var manifest=[
{src:"/main/images/testImage101.jpg",id:"PHOTO1"},
{src:"/main/images/testImage102.jpg",id:"PHOTO2"},
{src:"/main/images/testImage103.jpg",id:"PHOTO3"},
{src:"/main/images/testImage104.jpg",id:"PHOTO4"},
{src:"/main/images/testImage105.jpg",id:"PHOTO5"},
{src:"/main/images/testImage106.jpg",id:"PHOTO6"}
]
//最初の画像0のこと
var image_no=0;
//画像数
var image_max;

//------------------------------------------------------

//ステージ
var stage;
//コンテナ
var overcontainer,loadingcontainer,progresscontainer;
//画像 Bitmapインスタンス
var welcomeImage,overImage;
//画像result
var mainImage;
//Loading
var loadingShape;
var progressbar;
//TEXT
var viewtext;

//読み込み画像URL保存容器
var assets=[];

//変数
var globalflag=false,timerID=null;
//ProgressBar変数
var bar_v=0;
//BitmapData
var bitmapdata;
var set_bmd;

//最大値
var bmd_max;
//位置補正値
var posX_v;
var posY_v;
var maxflag=0;
//Particle
var particles=[];

//shadowフィルター
var shadow=new createjs.Shadow("#000000",0,0,4);

//------------------------------------------------------

//ステージ周りセット
function init() {

	//STAGE
	stage=new createjs.Stage('mainCanvas');

	//バックRect/最下位色背景層、無くとも良い
	var backrect=new createjs.Shape();
	backrect.graphics.beginFill("#000000").drawRect(0,0,canvasWidth,canvasHeight);
	stage.addChild(backrect);

	//welcome画像層画像表示/必要なら下に画像を表示
	//画像層確保/Firefox対策
	welcomeImage=new createjs.Bitmap();
	stage.addChild(welcomeImage);
	//表示
	welcomeImage.visible=true;

	//簡易Loader/Firefox対策
	var img=new Image();
	img.src="/main/images/welcome_back4.jpg";
	img.onload=function() {
		//Bitmap流し込み
		welcomeImage.image=new createjs.Bitmap(img).image;
	}

	//overImage/BitmapData表示領域
	overcontainer=new createjs.Container();
	//最重要、BitmapDataは最初からなければならない
	set_bmd=new createjs.BitmapData(null,canvasWidth,canvasHeight);
	overImage=new createjs.Bitmap(set_bmd.canvas);
	overcontainer.addChild(overImage);
	stage.addChild(overcontainer);

	//loadingコンテナを作る
	loadingcontainer=new createjs.Container();
	stage.addChild(loadingcontainer);
	//LOADINGを作る3
	loadingShape=loadingIndicator3();
	loadingShape.x=canvasWidth/2;
	loadingShape.y=canvasHeight/2;
	//tickを設定
	loadingShape.tick=function (){
		loadingShape.rotation +=5;
	}
	//loading addEventListenerを設定
	createjs.Ticker.addEventListener('tick',loadingShape.tick);
	//コンテナに貼り付け
	loadingcontainer.addChild(loadingShape);

	//ProgressBar
	progresscontainer=new createjs.Container();
	progressbar=new createjs.Shape();
	progtext=new createjs.Text('0','12px Arial','#FFFFFF');
	progtext.x=0;
	progtext.y=15;
	progtext.maxWidth=80;
	progtext.textAlign='center';
	progtext.shadow=shadow;//shadow
	//alpha
	progressbar.alpha=0.5;

	//bar_v判定tickを設定
	//90度是正-Math.PI/2
	progressbar.tick=function (){
		if(bar_v > 0) {
			progressbar.graphics.clear();
			progressbar.graphics.setStrokeStyle(8,'butt').beginStroke('#FF69B4');
			progressbar.graphics.arc(0,0,40,-Math.PI/2,Math.PI*2*bar_v-Math.PI/2);
			progtext.text=Math.floor(bar_v*100);
		}
	}
	//Ticker.Listener設定
	createjs.Ticker.addEventListener('tick',progressbar.tick);
	//addChild
	progresscontainer.x=canvasWidth/2;
	progresscontainer.y=canvasHeight/2;
	progresscontainer.addChild(progressbar,progtext);
	stage.addChild(progresscontainer);

	//簡易TEXT
	viewtext=new createjs.Text("","12px Arial","#FFFFFF");
	viewtext.x=20;
	viewtext.y=15;
	viewtext.maxWidth=canvasWidth-40;
	viewtext.lineHeight=20;
	viewtext.textBaseline="bottom";
	viewtext.shadow=shadow;//SHADOW処理
	stage.addChild(viewtext);
	set_text("Loading Now!");

	//Ticker設定
	createjs.Ticker.setFPS(20);
	createjs.Ticker.addEventListener('tick',tick);

	//遅延
	setTimeout(function() {

		//画像ロードに進む
		bulkload();

	},2000);

}

//progressBar
function progress(event) {

	//loadedのみ効く
	bar_v=event.loaded;
}

//bulk-load、画像一括ロード
function bulkload() {

	//Loaderを作る
	var loader=new createjs.LoadQueue(false);

	//全体、progressがあれば先に設定
	loader.addEventListener("progress",progress);

	//loader EventListener設定
	loader.addEventListener("fileload",fileload);
	loader.addEventListener("complete",complete);

	//Manifestを使用、manifest読み込み開始
	loader.loadManifest(manifest);

}
//各画像読み込み完了
function fileload (event) {

	assets.push(event.result);
}
//全ての画像読み込み完了
function complete (event) {

	//画像数確認、再計算
	image_max=assets.length;
	//簡易TEXT
	set_text("Loading End!");

	//loader Listener削除
	event.target.removeEventListener("fileload",fileload);
	event.target.removeEventListener("complete",complete);

	//loading EventListener削除
	createjs.Ticker.removeEventListener('tick',loadingShape.tick);
	//非表示でも良い
	loadingcontainer.visible=false;

	//画像があれば、最初の画像表示
	if (image_max) {

		//早すぎるので調整
		setTimeout(function() {

			//遅延progressbar最後の前にcompleteが反応する
			event.target.removeEventListener("progress",progress);
			//progressTicker削除
			createjs.Ticker.removeEventListener('tick',progressbar.tick);
			//progress非表示
			progresscontainer.visible=false;
			//簡易TEXTクリア
			set_text("");

			//welcome表示中なら削除、遅延して削除している
			if(welcomeImage.visible) {
				//stage.removeChild(welcomeImage);
			}

			//画像表示に進む
			make_particle();

		},1000);//500-1000
	}

}

//make-particle
function make_particle () {

	//画像分割数
	bmd_max=imageWidth*imageHeight;

	//位置補正値中央
	posX_v=(canvasWidth-imageWidth)/2;
	posY_v=(canvasHeight-imageHeight)/2;

	//range_v散らばす範囲設定
	//Particle
	particles=[];

	var k=0;
	for (var i=0;i < imageWidth;i++) {
		for (var j=0;j < imageHeight;j++) {

			var rs=Math.random()*(360);
			var rv=Math.random()*100;
			//中心補正
			if (in_stage) {
				//内
				var x=((Math.random()*canvasWidth*2)-canvasWidth+imageWidth*2)*range_v;
				var y=((Math.random()*canvasHeight*2)-canvasHeight+imageHeight)*range_v;
			} else {
				//外
				//適当計算
				var x=Math.floor(Math.cos(rs)*(canvasWidth*0.75+rv*range2_v))+canvasWidth/2;
				var y=Math.floor(Math.sin(rs)*(canvasWidth*0.75+rv*range2_v))+canvasHeight/2;
			}

			var color=0x00000000;
			particles[k]=new Particle(1,x,y,i+posX_v,j+posY_v,x,y,color);//ID付き

			k ++;

		}
	}

	//画像表示に進む
	draw();
}

//DRAW、アニメ
function draw() {

	set_text("IN");

	globalflag=false;
	maxflag=0;

	//画像result取得
	mainImage=assets[image_no];

	//色取得のため画像BitmapData変換
	bitmapdata=new createjs.BitmapData(mainImage);

	//overImage bitmapdata保存処理
	var c;
	var k=0;
	for (var i=0;i < imageWidth;i++) {
		for (var j=0;j < imageHeight;j++) {

			var p=particles[k];
			//要素の色を取得保存
			c=bitmapdata.getPixel32(i,j);
			p.color=c;
			k ++;
		}
	}

	//alpha/Fadeのため
	overImage.alpha=1;

	//Ticker
	createjs.Ticker.addEventListener('tick',move_particles);
}

//集合particles-IN
function move_particles (event) {

	//BitmapData canvasクリア
	set_bmd.clearRect(0,0,canvasWidth,canvasHeight);

	var k=0;
	for (var i=0;i < bmd_max;i++) {

		var p=particles[k];
		//ID
		var id=p.id

		//現在値
		var x=p.x;
		var y=p.y;

		//集合位置
		var sx=p.sx;
		var sy=p.sy;

		//集合速度
		x +=(sx-x)*.1;
		y +=(sy-y)*.1;

		//接近
		if (Math.abs(x-sx) < 0.5 && Math.abs(y-sy) < 0.5) {
			if(id) {
				p.id=0;
				x=sx;y=sy;
				maxflag ++;
			}
		}

		//要素の色を付ける
		if (x > 0) {
			set_bmd.setPixel32(x,y,p.color);
		}

		//保存
		p.x=x;
		p.y=y;

		k ++;

	}

	//setPixelのupdate
	set_bmd.updateContext();

	//終了
	if (maxflag == bmd_max) {
		finsh_move();
	}

}

//OUT拡散
function out_set () {

	maxflag=0;

	//ここで拡散位置を計算しても良い

	set_text("OUT");
	//OUT表示に進む
	//パーティクルステージ内
	if (in_stage) {createjs.Ticker.addEventListener('tick',out_particles);}
	//パーティクルステージ外
	if (!in_stage) {createjs.Ticker.addEventListener('tick',out_particles2);}

}

//拡散内部用particles-OUT
function out_particles (event) {

	//BitmapData canvasクリア
	set_bmd.clearRect(0,0,canvasWidth,canvasHeight);

	var len=particles.length;
	var k=0;
	for (var i=0;i < len;i++) {

		var p=particles[k];

		//ID
		var id=p.id;
		//現在値
		var x=p.x;
		var y=p.y;
		var ox=p.ox;
		var oy=p.oy;

		//適当な拡散
		x +=(p.ox-x)*.02;
		y +=(p.oy-y)*.02;

		//接近
		if (Math.abs(ox-x) < 100 && Math.abs(oy-y) < 100) {
			if(id == 0) {
				p.id=1;
				x=ox;y=oy;
				maxflag ++;
				len --;
				particles.splice(i,1);
				len=particles.length;
				//消す
				set_bmd.setPixel32(x,y,0x00000000);
			}
		}

		//要素の色を付ける
		if (id == 0) {
			if (x > 0) {
				set_bmd.setPixel32(x,y,p.color);
			}
		}

		//保存
		p.x=x;
		p.y=y;

		k ++;
	}

	//setPixelのupdate
	set_bmd.updateContext();

set_text(""+len);

	//終了
	if (len == 0){finsh_out();}

}


//拡散外部用particles-OUT
function out_particles2 (event) {

	//canvasクリア
	set_bmd.clearRect(0,0,canvasWidth,canvasHeight);

	var len=particles.length;
	var k=0;
	for (var i=0;i < len;i++) {

		var p=particles[k];

		//現在値
		var x=p.x;
		var y=p.y;
		var ox=p.ox;
		var oy=p.oy;

		//適当な拡散
		x +=(x-p.ox)*.02;
		y +=(y-p.oy)*.02;

		//要素の色を付ける
		if (x > 0 && Math.abs(x-p.ox) > 10) {
			set_bmd.setPixel32(x,y,p.color);
		}

		//保存
		p.x=x;
		p.y=y;

		//ステージの外に出た
		if ((x <= 0) || (x > canvasWidth) || (y < 0) || (y > canvasHeight)) {
			len --;
			particles.splice(i,1);
			len=particles.length;
		}

		k ++;
	}

	//setPixelのupdate
	set_bmd.updateContext();

set_text(""+len);

	//終了
	if (len == 0){finsh_out();}

}

//move完了
function finsh_move () {

	set_text("finsh-IN");
	createjs.Ticker.removeEventListener('tick',move_particles);

	if (!outUse) {
		finshtween ();
	}
	if (outUse) {
		//INパーティクル表示時間
		setTimeout(function() {
			out_set();
		},pin_time);
	}

}

//out完了
function finsh_out () {

	//パーティクルステージ内
	if (in_stage) {createjs.Ticker.removeEventListener('tick',out_particles);}
	//パーティクルステージ内外
	if (!in_stage) {createjs.Ticker.removeEventListener('tick',out_particles2);}

	//TWEENなし
	finshtween ();

}

//全て完了
function finshtween () {

	set_text("FINISH");

	//アニメ作業中である、現在は未使用
	globalflag=true;

	//画像処理に時間がかかるので、少し遅延させる、あったほうが良い
	setTimeout(function() {

		//タイマー次ぎ開く
		if (timerUse) {
			set_timer();
		}
	},500);

}

//tick
function tick() {
	stage.update();
}

//次ぎの開く要素を計算
function next_set() {

	//次ぎの番号
	image_no +=1;
	if (image_no > (image_max-1)) {image_no=0;}

	set_text("AUTO");

	//TWEENの実行なし
	make_particle ();

}

//タイマー
function set_timer() {

	//タイマー再セット
	if (timerUse) {

		//一旦切ってからセット
		clearTimeout(timerID);
		timerID=setTimeout(next_set,time);
	}

}

//VIEWTEXT
function set_text(t) {

	if (textUse) {
		viewtext.text=t;
		stage.update();
	}
}

//TEXT付きcanvasを作る
//幅、高さ、色、文字種、サイズ、文字色、ストリング
function createTextCanvas (w,h,c,font,fsize,fcolor,text) {

	var canvas=document.createElement("canvas");
	canvas.width=w;
	canvas.height=h;
	var ctx=canvas.getContext("2d");
	ctx.fillStyle=c;
	ctx.fillRect(0,0,w,h);

	var font_v=fsize +" "+ font;

	ctx.fillStyle=fcolor;
	ctx.font=font_v;
	ctx.textAlign="center";
	ctx.textBaseline="middle";
	ctx.fillText(text,w/2,h/2);

	return canvas;
}

//------------------------------------------------------
//簡単なLOADING
function loadingIndicator3 () {

	//graphicのスタイル
	var graphics=new createjs.Graphics();
	graphics.setStrokeStyle(2,"round");//round

	//描画データ
	var alpha_v=1;//透明度
	var alphaback;

	var cx,cy;
	var numNeedles=12;
	var innerR=15;
	var outerR=10;
	var cAngle=-Math.PI/2;
	var nAngle;

	//ライン描画
	nAngle=Math.PI*2/numNeedles;
	for (var i=0; i < numNeedles; i++){

		//回転補正
		rotateflag=cAngle -=nAngle;
		//透明度を描画毎に変更
		if (i > 0) {alpha_v -=0.05;}

		//#CCCCCC
		alphaback=createjs.Graphics.getRGB(204,204,204,alpha_v);
		cx=Math.cos(cAngle)*innerR;
		cy=Math.sin(cAngle)*innerR;
		graphics.beginStroke(alphaback).moveTo(cx,cy);
		cx=Math.cos(cAngle)*outerR;
		cy=Math.sin(cAngle)*outerR;
		graphics.lineTo(cx,cy);

	}
	//Shapeに格納
	var s=new createjs.Shape(graphics);
	return s;
}
//------------------------------------------------------

//Particleクラス
var Particle=(function () {
	function Particle(id,x,y,sx,sy,ox,oy,color) {
		this.id=id;
		this.x=x;
		this.y=y;
		this.sx=sx;
		this.sy=sy;
		this.ox=ox;
		this.oy=oy;
		this.color=color;
	}
	var p=Particle.prototype;
	p.id=0;
	p.x=0;
	p.y=0;
	p.sx=0;
	p.sy=0;
	p.ox=0;
	p.oy=0;
	p.color=0x00000000;
	return Particle;
}());

//------------------------------------------------------

//START
init();

注釈文を削除すれば、幾分早くなります。
画像使用の場合、登録画像パスは当方の例です。使用の際は環境に合わせて下さい。


CSS

createJS063.css、CSS名は任意に変更可


/*日本語createJS063.css*/

#demo-wrap {
text-align:center;
}

#image-box {
position:relative;
top:0;left:0;
width:640px;
height:300px;
margin:0 auto;
padding:0;
box-shadow:0 0 10px #000;
-moz-box-shadow:0 0 10px #000;
-webkit-box-shadow:0 0 10px #000;
-o-box-shadow:0 0 10px #000;
-ms-box-shadow:0 0 10px #000;
background-color:#000000;
}

#image-box #mainCanvas {
border-radius:10px;
}
canvas {
border-style:none;
background-color:transparent;
}

.radius {
border-radius:10px;
-moz-border-radius:10px;
-webkit-border-radius:10px;
-o-box-border-radius:10px;
-ms-border-radius:10px;
}

当方のサンプルの例です。


簡単な説明


[説明図]、事件なのか?、単なる仕様なのか?

 

簡単なBitmapData画面での1ピクセル単位、setPixel32着色パーティクル集合拡散サンプルです。


1. 予めに「透明BitmapData画面(set_bmd)」を作り「使い回し」します。(特殊な形かも知れません)
2. tick毎、setPixel32で着色しupdateContext()で更新表示します。
3. 表示の着色部分は毎回BitmapData画面のclearRect()で削除します。
4. draw()などは使用していません。
5. X値がBitmapData画面左側(X値マイナス)の場合、画面右に表示するため(タタリ...?)修正しています。
...仕様の様な気もするし、私はまだわからない!?
6. 現在大きな画像を処理する能力は有りません。(Canvasが進化すれば将来は可能かも)
7. [重要]、Firefoxで Bitmap('画像URL') の画像取得失敗でパーティクルが消滅して表示出来なくなる?!。
(ページ最後に対処方法を記載していますのでご覧下さい)
8. 一応 easeljs-0.7.1でも可動します。


透明BitmapData画面の作成

最初に、透明BitmapData画面を入れたBitmap()を作成して、パーティクル移動毎にBitmapDataのみ更新します
空Bitmap()で、後でBitmapDataを入れるより簡単になります。全体をレーヤー代わりのコンテナに収容。

サンプルでは、draw()を使用していませんが、draw()を行なう事も可能です。



//overImage
overcontainer=new createjs.Container();
//最重要、BitmapDataは最初からなければならない
set_bmd=new createjs.BitmapData(null,canvasWidth,canvasHeight);
overImage=new createjs.Bitmap(set_bmd.canvas);
overcontainer.addChild(overImage);
stage.addChild(overcontainer);

空Bitmap()で構成する場合はEventListenerの中で透明BitmapData画面をその都度作り、BitmapにBitmapDataを挿入する形になりますから面倒です。負荷などに変化はない様ですが....


画像の色情報を取得

Load画像のresult値より画像大のBitmapDataを作成して、1ピクセル単位での色情報を取得します。
色情報をパーティクル情報として書き込みます。(あとでこの情報を取り出しsetPixel32する)


//画像result取得
mainImage=assets[image_no];

//画像BitmapData変換
bitmapdata=new createjs.BitmapData(mainImage);

//overImage bitmapdata保存処理
var c;
var k=0;
for (var i=0;i < imageWidth;i++) {
	for (var j=0;j < imageHeight;j++) {

		var p=particles[k];
		//要素の色を取得
		c=bitmapdata.getPixel32(i,j);
		p.color=c;
		k ++;
	}
}

パーティクルの作成

1ピクセルの、BitmapDataを動かすために、パーティクル情報のみを持つパーティクルを作り、その情報を元にBitmapDataを動かしました。(移動先の場所の色を替えているだけですが...)
パーティクルはクラス化していますので、new Particle()で作成します。


ID値は、各パーティクルが目的位置に到達したかの判定用です。
posX_v、posY_v は画像の表示位置の修正用です。 色情報の初期値は 0x00000000 です。透明ですから、これで染めれば画面から消えることにもなります。


//位置補正値中央
posX_v=(canvasWidth-imageWidth)/2;
posY_v=(canvasHeight-imageHeight)/2;
-------------------------------------------------------------------------------

var color=0x00000000;
particles[k]=new Particle(1,x,y,i+posX_v,j+posY_v,x,y,color);//ID付き

パーティクルの移動

OUTは、1つに纏めることは可能ですが、繁雑になるので、out_particles、out_particles2 に分離しています。
拡散内部用はパーティクル処理終了の手がかりとなる、ID(名前などは何でも良い)などで判定するので工夫が必要だ。

拡散外部用はステージ外に出た場合に判定するので、こちらは簡単で時間も早い。
拡散内部用で、out_particles の場合広範囲に散らばっているため少々完了まで時間がかかります。(内部のみではキレイに見えないので、一部、外部にも描画しているのが遅くなる原因です)

デモJSでは、FadeOutしていませんので tweenjs-0.5.0.min.js は不要です。


● IN

徐々に目的位置に移動させるが永久に合致しないので、適当な距離で目的位置に合わせる。
パーティクル情報を書き換えて、カウントをUPする。全数処理すれば終了させる。


//集合particles-IN
function move_particles (event) {

	//BitmapData canvasクリア
	set_bmd.clearRect(0,0,canvasWidth,canvasHeight);

	略す

	徐々に目的位置に移動させる

	//接近
	if (Math.abs(x-sx) < 0.5 && Math.abs(y-sy) < 0.5) {
		if(id) {
			p.id=0;
			x=sx;y=sy;
			maxflag ++;
		}
	}

	略す

	//終了
	if (maxflag == bmd_max) {
		finsh_move();
	}
}

● OUT

パーティクル個別の処理が終了する毎にループ処理を減じ、ループ処理が0で全てを終了させる。
ステージ外に散らばっているので、処理は大まかです。


//OUT拡散
function out_set () {

	maxflag=0;

	//ここで拡散位置を計算しても良い

	set_text("OUT");
	//OUT表示に進む
	//パーティクルステージ内
	if (in_stage) {createjs.Ticker.addEventListener('tick',out_particles);}
	//パーティクルステージ外
	if (!in_stage) {createjs.Ticker.addEventListener('tick',out_particles2);}

}

-------------------------------------------------------------------

//拡散内部用particles-OUT
function out_particles (event) {

	略す

	ID情報で処理した、ステージ内部にも残るので透明で染めて消す

	//消す
	set_bmd.setPixel32(x,y,0x00000000);

}
//拡散外部用particles-OUT
function out_particles2 (event) {

	略す

	ステージ外に出たらループ処理を減じる

}

パーティクルのX値がマイナスの場合 [重要]

上記の図参照のごとく、パーティクルのX値がマイナスの場合、画面右に描画される?、原因などワタシには判りません。
修正のため、いろんな事を試してみましたが解決しません。リピートしているのか? ...仕様としたら、別BitmapDataでパーティクルの操作をしてステージ範囲のBitmapDataをdraw()するのも面倒である。

応急処置として、パーティクルのX値がマイナスの場合は描画しないようにしています。(出た!、原因わからずの得意のゴマカシ)


//要素の色を付ける
if (x > 0) {
	set_bmd.setPixel32(x,y,p.color);
}

-------------------------------------------------------------------

以下の様にすれば状況がわかります

//if (x > 0) {
	set_bmd.setPixel32(x,y,p.color);
//}

パーティクルの要素数

パーティクルの要素数は10000-20000個です、FLASH並の処理能力は有りませんがマシン環境で大きく変わります。
TEST結果からダイタイの値は以下のようです。


1. 古いマシン環境、10000個 (100x100画像)
2. マアマア新しいマシン環境、20000個
3. 高性能なマシン環境、20000個以上でも可能とは思います。


各種設定

JSの先頭をご覧下さい。


案内用TEXT表示

画面の推移毎に状態など表示しています、削除下さい。(または、textUse=false で表示しない)


特定の設定位置に近づく処理

「デモ」では「特定の設定位置に近づく」作りにしていますので、パーティクルに保存した「ID」などの判定で処理終了のタイミングを得ています。この辺AS3の処理方法が参考に成ります。


特定の設定位置に近づかない処理の場合などでは

パーティクル毎にTickerを設定していませんので、ステージ外に出た場合の判定は容易いのですが、
パーティクル移動終了のタイミングなど判定が出来ない事も有ります。そんな時は適当な時間の経過で終了させて、BitmapData画面をFadeアウトさせるなりの処置を取ります。ここではID値は参照していません。

カウント数など利用して、適当な時間を設定して強制終了させます。


終了のタイミングを正確に判定出来ないために、強制終了して、FadeOutする(サンプルでは分離して処理、FadeOutはしていないので注意下さい)
FadeOutのために tweenjs-0.5.0.min.js が必要です。

[一例] 拡散内部用、拡散外部用をout_particlesにまとめている。


//OUT拡散
function out_set () {

	maxflag=0;

	//ここで拡散位置を計算しても良い

	set_text("OUT");
	//OUT表示に進む
	createjs.Ticker.addEventListener('tick',out_particles);

}

-------------------------------------------------------------------

//拡散particles-OUT
//適当なところでFadeアウト終了
function out_particles (event) {

	//canvasセット
	set_bmd.clearRect(0,0,canvasWidth,canvasHeight);

	var len=particles.length;
	var k=0;
	for (var i=0;i < len;i++) {

		var p=particles[k];
		//現在値
		var x=p.x;
		var y=p.y;
		var ox=p.ox;
		var oy=p.oy;

		//拡散速度
		x +=(x-p.ox)*.02;
		y +=(y-p.oy)*.02;

		//要素の色を付ける
		//内部の場合
		if (x > 0 && Math.abs(x-p.ox) > 10) {
			set_bmd.setPixel32(x,y,p.color);
		}

		//保存
		p.x=x;
		p.y=y;

		//ステージの外に出た、一応機能
		if ((x <= 0) || (x > canvasWidth) || (y < 0) || (y > canvasHeight)) {
			maxflag ++;
			if(!in_stage){
				len --;
				particles.splice(i,1);
				len=particles.length;
			}
		}
		maxflag ++;
		k ++;
	}

	//setPixelのupdate
	set_bmd.updateContext();

	//終了
	//in_stageは全て外側ではないので適当な時間に終了
	if(in_stage) {
		//適当時間
		if(maxflag > bmd_max*50){finsh_out();}
	}
	if(!in_stage) {
		//0
		if(len == 0){finsh_out();}
	}
}

-------------------------------------------------------------------

//out完了/Fadeの方がキレイ
function finsh_out () {

	//リスナー削除
	createjs.Ticker.removeEventListener('tick',out_particles);

	//FadeOutTWEENの実行
	var tw=createjs.Tween.get(overImage)
	.to({alpha:0},speed)
	.call(function(){
		finsh_outtween();
	});
}

この辺の処理は使用者の考え方などで違いがあると思います。


OUTを使用しない

設定、outUse=false でINのみの実行となります。
INのみでOUTを使用しない場合、現在の「デモ」では画像がパッと消えますが、Fadeさせたい場合は、next_set()にTWEEN処理を付ければ良い。


//次ぎの開く要素を計算
function next_set() {

	//次ぎの番号
	image_no +=1;
	if (image_no > (image_max-1)) {image_no=0;}

	set_text("AUTO");

	//TWEENの実行
	var tw=createjs.Tween.get(overImage)
	.to({alpha:0},speed)
	.call(function(){
		make_particle ();
	});

}

Canvas要素でテキスト画像を作る

テキスト画像を作るのが面倒な場合は次ぎの様に、Canvas要素でテキスト画像を作る事が可能です。画像のresult値と同等に扱えるのが便利です。CreateJS Textクラスで文字を作る方法もありますが、より簡単と思います。
背景の色は「rgba形式」で指定します。文字の大きさなどは下記の様に指定します。

大きさ300x60、bold 32px、文字色「白」、背景「赤」透明度1とした場合。


1. 指定なし 32px
2. Bold指定 bold 32px
3. ItalicBold指定 italic bold 32px
4. 但し、関数createTextCanvas()は html5 canvas 仕様の書き方に成ります。
5. 画像を読み込めない場合の代替画像にもなります。
6. 現在の関数では、文字は1列で描画しますので改行は出来ません。
7. 関数改造の工夫次第で色々と出来ると思います。
8. 「デモ」で表示出来ますので状況を確認下さい。



//幅、高さ、色("rgba(0,0,0,0)")、文字種、サイズ、文字色、ストリング
//createTextCanvas (w,h,c,font,fsize,fcolor,text)//300x60
assets=[];
assets[0]=createTextCanvas (300,60,"rgba(255,0,0,1)","Arial","bold 32px","#FFFFFF","WELCOME");
assets[1]=createTextCanvas (300,60,"rgba(255,0,255,0.5)","Arial","bold 32px","#FFFFFF","KOKEKOKKOU");
.
.
-------------------------------------------------------------------

//TEXT付きcanvasを作る
//幅、高さ、色、文字種、サイズ、文字色、ストリング
function createTextCanvas (w,h,c,font,fsize,fcolor,text) {

	var canvas=document.createElement("canvas");
	canvas.width=w;
	canvas.height=h;
	var ctx=canvas.getContext("2d");
	ctx.fillStyle=c;
	ctx.fillRect(0,0,w,h);

	var font_v=fsize +" "+ font;

	ctx.fillStyle=fcolor;
	ctx.font=font_v;
	ctx.textAlign="center";
	ctx.textBaseline="middle";
	ctx.fillText(text,w/2,h/2);

	return canvas;
}

背景色の要らない場合は rgba(0,0,0,0) とすれば良い。背景色が無い場合は処理をスキップする仕組みにすればより効率的と思います。


通常のCreateJSテキストを分解する

可能ですが、省略します。上記の方法が簡単です!


他に要素など配置する

大変重く成る場合が有りますので、状況に合わせて下さい。
(もう少し加工して....とは当初考えていたが重すぎてやめた)


使用画像

パーティクル用画像、100x100、枚数は任意です。

背景用画像、640x300、必要な場合。


Firefoxとwelcome画像について[重要]

背景用welcome画像読み込めず、パーティクル消滅事件発生。

通常は下記のような画像読み込みでは、Firefoxで画像関連の重大「エラー」は起こらないはずです。
画像読み込みが出来ず、意に反して重大「エラー?」が起こった。(パーティクルが消滅した、魚魚魚!)


修正前


//welcome画像層画像表示/必要なら下に画像を表示
welcomeImage=new createjs.Bitmap('/main/images/welcome_back4.jpg');
stage.addChild(welcomeImage);
//表示
welcomeImage.visible=true;
--------------------------------------------------------------------

但し、非表示ではエラーにならない
//非表示
welcomeImage.visible=false;

よって、以下の様な「エラー」を回避する処理をして下さい。

1. welcome画像表示部分を削除する。
2. 画像表示階層を確保して、Loaderなどを介して確実に取得できた画像を表示する。
3. 画像取得の出来ない場合は「代替画像」をキャンバス要素で作りそれを表示する。


BitmapData画面との相乗的な不具合の様なので、よって「表示エラー」回避のために次のようにした。これで画像取得に失敗しても正常に動作表示する。
● 先に、空Bitmap()をaddChild()して重なり順を確保。
● 画像をLoad出来たら、Bitmap()に流し込む。


修正後


//welcome画像層画像表示/必要なら下に画像を表示
//画像層確保/Firefox対策
welcomeImage=new createjs.Bitmap();
stage.addChild(welcomeImage);
//表示
welcomeImage.visible=true;

//簡易Loader/Firefox対策
var img=new Image();
img.src="/main/images/welcome_back4.jpg";
img.onload=function() {
	//Bitmap流し込み
	welcomeImage.image=new createjs.Bitmap(img).image;
}

これらの改造などは自由です。



 

一応、完動しますが全てテストです。効率化のため、予告無くJSなど修正する場合がありますので了承下さい。

CreateJSは結構「仕様」が変わりますので特に注意が必要です。


毎度おなじみ不具合含有!、AS3技法パクリの寄せ集めの感じがする。
以上です。

 


[ この記事のURL ]


 

ブログ記事一覧

年別アーカイブ一覧



[1]