サルでもわかるパーティクル・システム開発入門

# Flash でパーティクルシステムの開発に挑戦しよう

パーティクル・システムはグラフィック表現のひとつ。炎、爆発、煙とか光跡や呪文の視覚効果の制作に役立ちます。私の管理しているサイトの一つ「[Beautifl](https://beautifl.net/category/particle/)」を見て頂ければわかりますが、昔は「これでもか！」というぐらい皆パーティクルを作っていました。

## After Effectsでパーティクルの表現力に魅せられて

私がペーペーの見習いFlasherだった頃の話。Adobe After Effectsにもパーティクルを実現する機能が搭載されていまして、「パーティクル・プレイ・グラウンド」や「Trapcode Particular」とかのエフェクトを触る機会がありました。[ayato@web](http://www.ayatoweb.com/ae_tips.html)のデモを見れば、パーティクル表現の可能性に触れることができますが、表現力の高さに随分興奮したものです。それと同時に、このエフェクトを開発した人は人類の叡智を超えた神々だと崇拝していました。

## wonderfl で知った意外と簡単だったパーティクルの実装

それから数年、[wonderfl build flash online](http://wonderfl.net/)の登場でパーティクルの実装コードが次々とパブリックに投稿されるようになりました。コード神と呼ばれる海外の凄腕クリエイターが投稿しているかとおもいきや、20代後半から学生の方たちがパーティクルを投稿しているんですね。

「えっ、自分と同じぐらいの年の人が？」

コードを読んでみると、神々でもなくても普通の社会人エンジニアが読める程度の難易度だったのです。

## 皆さんも挑戦しましょう

パーティクルの開発自体はそんな難しいものではないーということを多くの方に知ってもらいたく解説を書くことにしました。段階を踏んで、一つ一つ学んでいきましょう。解説は、約30分程度で学べる内容となっています。

## 1つだけのパーティクル制御を実装

![](https://ics-creative.github.io/tutorial-createjs/imgs/particle_single.html.png)

- [サンプルを再生する](http://ics-creative.github.io/151222_flash_particle/FlashBuilder/bin-release/particle_step1.swf)
- [サンプルのソースコードを確認する](https://github.com/ics-creative/151222_flash_particle/blob/gh-pages/FlashBuilder/src/particle_step1.as)

パーティクルは`MovieClip`インスタンスとして作成します(`Shape`クラスでもいいのですが、この後の解説のため`MovieClip`で解説を続けます)。このパーティクルに対して、速度の計算を行います。

```as3
private const size:int = 10;
private var particle:Shape;
private var vx:Number;
private var vy:Number;

public function particle_step1()
{
	// 赤い丸を作成
	particle = new Shape();
	// (省略)

	// 速度情報
	vx = 0;
	vy = 0;

	this.addChild(particle);

	// 時間経過
	this.addEventListener(Event.ENTER_FRAME, handleTick);

}

private function handleTick(event):void
{
	// 重力
	vy += 1;
	// 摩擦
	vx *= 0.95;
	vy *= 0.95;
	// 反映
	particle.x += vx;
	particle.y += vy;
	// 地面の作成
	// (省略)
}
```

`vx`と`vy`あたりの制御は速度情報をX軸とY軸で管理している基本的な実装です。詳しく知っておきたいテクニックですが、このことは「神の書」と呼ばれかつて全てのFlasherのバイブルだった「[ActionScript 3.0 アニメーション: Keith Peters](http://www.amazon.co.jp/dp/4862460496)」を参考にするといいでしょう。

## 配列で複数のパーティクルを制御

![](https://ics-creative.github.io/tutorial-createjs/imgs/particle_multi.html.png)

- [サンプルを再生する](http://ics-creative.github.io/151222_flash_particle/FlashBuilder/bin-release/particle_step2.swf)
- [サンプルのソースコードを確認する](https://github.com/ics-creative/151222_flash_particle/blob/gh-pages/FlashBuilder/src/particle_step2.as)

まずは複数のパーティクルを管理する配列を作成しましょう。

```as3
private var particleList:Array = [];
```

※ `[]`と記述しても`new Array()`と記述しても同じです。多くのコーディング規約で`[]`と記述することが推奨されているので、本サイトでは配列は`[]`として作成します。


`for`文を使って、複数のパーティクルを作成し、この配列に保存します。パーティクルの発生座標は視覚的にわかりやすくするために、`Math.random()`メソッドを使ってランダムな座標にしています。

```as3
// for文を作成 (上限数はパーティクルの個数)
for (var i:int = 0; i < 20; i++)
{
	// 赤い丸を作成
	var particle:MovieClip = new MovieClip();
	// (省略)
	particle.vx = 0;
	particle.vy = 0;
	// 配列に保存
	particleList[i] = particle;
}
```

速度情報の`vx`と`vy`は`MovieClip`インスタンスのプロパティーとして設定しています(`particle.vx = 0;`)。ActionScript 3.0のMovieClipクラスはダイナミッククラスといい、自由にオブジェクトのプロパティーを追加できます。本来は`MovieClip`クラスに`vx`と`vy`プロパティーは存在しませんが、速度情報はパーティクル自身それぞれで管理するべきものなので、パーティクル自身に速度情報をもたせたほうがプログラムの見通しがよくなります。

```as3
particle.vx = 0;
particle.vy = 0;
```

次に`Event.ENTER_FRAME`イベントでは配列に保存した複数のパーティクルを制御します。`for`文では配列の長さ`particleList.length`に応じてループさせます。配列の制御では要素を変数に取り出し(`var particle = particleList[i];`)、一個のパーティクルを制御したときと同じ処理を実装します。

```js
for (var i:int = 0; i < particleList.length; i++)
{
	// i番目の要素を変数に代入
	var particle:MovieClip = particleList[i];
	// 重力
	particle.vy += 1;
	// 摩擦
	particle.vx *= 0.95;
	particle.vy *= 0.95;
	// 反映
	particle.x += particle.vx;
	particle.y += particle.vy;
	if (particle.y > stage.stageHeight - size)// 地面
	{ 
		particle.y = stage.stageHeight - size; // 行き過ぎ補正
		particle.vy *= -1; // Y軸の速度を反転
	}
}
```

## パーティクルを時間経過で発生させ、寿命を設ける

![](https://ics-creative.github.io/tutorial-createjs/imgs/particle_life.html.png)

- [サンプルを再生する](http://ics-creative.github.io/151222_flash_particle/FlashBuilder/bin-release/particle_step3.swf)
- [サンプルのソースコードを確認する](https://github.com/ics-creative/151222_flash_particle/blob/gh-pages/FlashBuilder/src/particle_step3.as)


### プログラムの構造 : エンターフレームイベントで2つの関数を呼び出して制御

時間経過でパーティクルを発生させたいので、パーティクルの作成を`Event.ENTER_FRAME`イベントで行います。`emitParticles()`関数でパーティクルを発生させ、`updateParticles()`関数でパーティクルを動かします。

```as3
private var particleList:Array = [];

/** コンストラクター */
public function particle_step3()
{
	// 時間経過
	this.addEventListener(Event.ENTER_FRAME, handleTick);
}

private function handleTick(event):void
{
	// パーティクルを発生
	emitParticles();
	// パーティクルを更新
	updateParticles();
}
```

これらの関数の役割を掘り下げてみましょう。

#### パーティクルの発生を担当する`emitParticles()`関数

パーティクルは時間経過で次々と発生します。配列の大きさに制限はなく、いくらでも要素を追加することができます。今回は新しく発生したパーティクルは配列の最後に追加するため、`push()`メソッドを使ってパーティクルを保存しています。

```as3
/** パーティクルを発生させます */
private function emitParticles():void {
	// for文を作成 (上限数はパーティクルの個数)
	for (var i:int = 0; i < 4; i++)
	{
		// 赤い丸を作成
		var particle:MovieClip = new MovieClip();
		// (省略)

		// 寿命
		particle.life = 50;
		
		// 配列に保存
		particleList.push(particle);
	}
}
```

パーティクルには座標`x`、`y`や速度情報`vx`、`vy`を設定しますが、今回はパーティクルに寿命`life`を設定します。`MovieClip`クラスには`life`というプロパティーは本来存在しませんが、勝手に追加しておきます。

```as3
// 寿命
particle.life = 50;
```

#### パーティクルの更新を担当する`updateParticles()`関数

パーティクルの更新処理では寿命の更新をおこないます。寿命というと難しいように思いますが、処理としてはプロパティー`life`の値を`-1`するだけです。1回の`tick`イベントで`life`が1ずつ減っていきます。

```as3
/** パーティクルを更新します */
private  function updateParticles():void {
	for (var i:int = 0; i < particleList.length; i++)
	{
		// i番目の要素を変数に代入
		var particle:MovieClip = particleList[i];
		//(省略)
		
		// 寿命を減らす
		particle.life -= 1;
		// 寿命の判定
		if (particle.life <= 0) {
			// ステージから削除
			this.removeChild(particle);
			// 配列からも削除
			particleList.splice(i, 1);
		}
	}
}
```

寿命がつきたとき、つまり`life`が`0`になったときにパーティクルを消去しましょう。`if`文での判定は`life`が`0`になったかどうかを調べればわかります。削除処理には２つの実装が必要となり、画面から消す`removeChild()`と、保存されている配列からの消去`particles.splice()`を行います。

`removeChild()`はステージから消去する命令で画面からパーティクルを消すことができます。配列の`splice(a, b)`は配列の`a`番目から`b`個の要素を消すという命令になります。画面から消すだけでは不十分で、配列からもパーティクルを消しておかなければ、無駄に座標更新や物理演算の計算が行われ続けます。

```as3
// 寿命の判定
if (particle.life <= 0) {
  // ステージから削除
  stage.removeChild(particle);

  // 配列からも削除
  particles.splice(i, 1);
}
```


## カラフルなパーティクルシステムの実装

![](https://ics-creative.github.io/tutorial-createjs/imgs/particle_colorful.html.png)

- [サンプルを再生する](http://ics-creative.github.io/151222_flash_particle/FlashBuilder/bin-release/particle_step4.swf)
- [サンプルのソースコードを確認する](https://github.com/ics-creative/151222_flash_particle/blob/gh-pages/FlashBuilder/src/particle_step4.as)

最後に表現をブラッシュしていきましょう。

### パーティクルの色を時間経過で変える

`beginFill()`メソッドでパーティクルの色を設定しますが、これを時間経過で色をかえていきます。今回は時間経過で色相(赤→緑→青)をかえるためにHSVカラーを使います。HSVカラーはActionScript 3.0で簡単に使うために、AS3ライブラリのFrocessing ( [nutsu/Frocessing - Spark project](http://www.libspark.org/wiki/nutsu/Frocessing) )を利用します。

```as3
// HSLカラーを作成 (Frocessingを利用)
hsl = new ColorHSV(0, 0.7, 0); // 彩度は70%で指定
```

値(0〜360で色相環の一周になる)をかえるだけで色相が変わります。カラフルな表現をつくるときに便利な命令です。`Event.ENTER_FRAME`イベントが発生するたびに1.5ずつ色相をずらします。

```as3
hsl.h += 1.5; // 色相は時間経過で変化
hsl.v = 0.4 + 0.2 * Math.random(); // 明度は40%〜60%でランダム
var color:uint = hsl.value;
// 赤い丸を作成
var particle:MovieClip = new MovieClip();
particle.graphics.beginFill(color);
particle.graphics.drawCircle(0, 0, size);
```

### パーティクルの合成方法を変える

表示オブジェクトの重なり方を指示できる`blendMode`プロパティーを使って、レイヤーの合成方法を変更させておきます。パーティクルとパーティクルが重ねると、色が加算されて(`BlendMode.ADD`の指定によって)、明るくみえるようになります。

```as3
particle.blendMode = BlendMode.ADD;
```

### パーティクルのサイズを時間経過で小さくする

`life`プロパティーの数値に比例して、パーティクルのサイズを小さくさせてみましょう。大きさを変化させるには`scaleX`と`scaleY`プロパティーを使います。現在のライフが寿命の何%に相当するかを計算し(`particle.life / MAX_LIFE`)、その値が`0.0〜1.0`の範囲になるので`scaleX`と`scaleY`プロパティーに適用します。

```as3
private const MAX_LIFE:int = 40; // 寿命の最大値

/** パーティクルを発生させます */
private function emitParticles():void
{
	// for文を作成 (上限数はパーティクルの個数)
	for (var i:int = 0; i < 2; i++)
	{
		// 赤い丸を作成
		var particle:MovieClip = new MovieClip();
		//(省略)
		// 寿命
		particle.life = MAX_LIFE;
		//(省略)
	}
}

/** パーティクルを更新します */
private function updateParticles():void
{
	for (var i:int = 0; i < particleList.length; i++)
	{
		// i番目の要素を変数に代入
		var particle:MovieClip = particleList[i];
		//(省略)
		
		// パーティクルのサイズをライフ依存にする
		var scale:Number = particle.life / MAX_LIFE;
		particle.scaleX = particle.scaleY = scale;
		
		//(省略)
	}
}
```

## まとめ

いかがでしたでしょうか。パーティクルは難しそうなものに見えますが、一つ一つ分解してみるとシンプルな実装の組み合わせに過ぎません。パーティクルの移動方向や、パーティクル自体の形状を変更すると様々な表現に転換できます。ぜひ、いろいろパラメーターを調整してみてください。

応用技として、パーティクルのガベージコレクション対策に、「[ゲームにおけるガベージコレクションとの付き合い方](http://qiita.com/bkzen/items/d84312246061778ee870)」で紹介されているオブジェクトプールや、「[Stalingフレームワークの歩み](http://qiita.com/harayoki/items/7447cda5c3a423c485cd)」で紹介されているStarlingフレームワークでGPUをフル活用すると、パーティクル表現が極まっていくでしょう。

またHTML5 Canvas (CreateJS)でのパーティクルシステムの作り方を[CreateJS でパーティクルシステムの開発に挑戦しよう - CreateJS入門 - ICS MEDIA](https://ics.media/tutorial-createjs/particle.html)で解説しています。この記事と内容はほぼ同じなのですが、Flashと異なる言語でも考え方は通用するということがおわかり頂けると思います。

それではみなさんも良きパーティクルライフを！