前回の第25回「楕円軌道に残像を描きながら回るパーティクル」では、黒い背景に残像が残るパーティクルを楕円軌道で重ねた(再掲第25回図3)。そして、楕円軌道の中心はCanvasの真ん中に定めた。今回は、違った方程式で楕円軌道を描きたい。
楕円軌道を速度から導く
前回のサンプルの楕円軌道は、第25回コード1「パーティクルを定めるクラス」にメソッド(move())としてつぎのように定めた。
このコードでインスタンスが楕円軌道を動くのは、つぎのような円周上の座標を導く方程式にもとづく。円の中心座標と半径が与えられると、現行の角度を変えれば座標が円周上を動く。そして、半径を水平と垂直で違う長さにすると、軌道が楕円になった。なお、角速度は描画のたびに加える定数の角度だ。
上記の方程式は、現行角度から直ちに軌道上の座標を求めた。しかし、一般に物体の運動は、現在の座標に速度を加えても導ける。円軌道を速度から定めたのが、つぎの方程式だ。この場合、中心座標が要らないことに注目してほしい。また、半径を水平と垂直で変えれば、やはり楕円軌道が描ける。
細かい説明より先に、この方程式でパーティクルのクラス(Particle)に定めるメソッドを書き替えてみよう。クラスの定め全体は後にコード1としてまとめた。抜き書きしたJavaScriptコードがつぎのとおりだ。アニメーションのメソッド(move())だけでなく、パーティクルのインスタンスにプロパティを定めるメソッド(reset())にも手が加わっている。
先に、パーティクルのアニメーションのメソッド(move())から見よう。ほぼ上記の方程式にしたがって書き替えただけだ。ただ、sinとcosの値に乗じる「半径×角速度」の値は、アニメーションを始めたら変わることがない。そこで、プロパティを定めるメソッド(reset())で、値はプロパティ(speedXとspeedY)とした(後述「ランダムな楕円軌道のバランスをとる」参照)。
さらに、プロパティを定めるメソッド(reset())では、前述のとおり軌道の中心座標をプロパティにもたなくて済む。また、軌道の半径も、速度の係数に使うだけなので、プロパティには要らない。また、現行角度(angle)は0から始めることにした。
クラス(Particle)からパーティクルをつくってアニメーションさせる第25回コード4「楕円軌道の残像に重なったパーティクルが輝きながら消えてゆく」にもひとつ手が加わる。インスタンスにプロパティを与える関数(resetParticle())から渡すランダムな半径(radius)の値の範囲はつぎのように変えた。楕円軌道の半径そのものでなく、速度を変える係数として用いられるからだ。
楕円軌道で動くパーティクルをつくるクラス(Particle)は、つぎのコード1のように書き替えた。初めにインスタンスが置かれた座標から、速度を決めて、それぞれの楕円軌道で回る(図1)。
前掲コード1のクラス(Particle)からパーティクルのインスタンスを10個つくって、ランダムな楕円軌道で回すJavaScriptコードは、前述のとおり1行インスタンスに与えるランダムな係数値が変わるだけだ。だが、動きの違いが確かめやすいように、つぎのコード2にスクリプト全体を掲げた。
ランダムな楕円軌道のバランスをとる
前記の速度を求める方程式の中で「半径×角速度」の値には、とくに三角関数は含まれない。クラス(Particle)のプロパティを定めるメソッド(reset())で用いた三角関数(Math.cos()とMath.sin()メソッド)が果たすのは、ランダムな引数(angle)値から±1の範囲の係数を定めるだけの役割だ。
したがって、引数値は使わずに、たとえばつぎのようにランダムに±1の範囲の値を決めても構わない。ただ、この式から得られるパーティクル10個の楕円軌道は、縮こまった感じになる(図2)。
xとy方向それぞれ独立に±1の範囲のランダムな値を決めると、両方とも0に近い値になることが起こりうる。それに対して、ランダムな引数(angle)からcosとsinで求める値は、一方が0に寄ると、他方は1または-1に近づく。軌道の長さが縮こまることはない。つまり、ランダムに定めた楕円軌道のバランスがとれるのだ。
100個のパーティクルを使い回して再設定する
パーティクルの数をさらに増やそう。ただ、インスタンスを新たにつくり続けるのではなく、ある程度経ったら設定を変えることにして、オブジェクトは使い回す。そこで、アニメーションが描かれる(move())たびにカウントダウンするプロパティ(lifetime)を、つぎのようにパーティクルのクラス(Particle)に加える。値はプロパティを定めるメソッド(reset())の引数とした。
つぎに、クラス(Particle)からパーティクルをつくってアニメーションさせるJavaScriptコードもつぎのように手直しする。インスタンスの数(total)は大幅に増やす。また、パーティクルにプロパティを与えるメソッド(reset())呼出しのとき、前述のカウントダウンの値を引数(lifetime)として加えた。この数値はインスタンス数の範囲までのランダムな整数だ[1]。
そして、インスタンスをアニメーションさせる関数(moveParticle())は、カウントダウンのプロパティ(lifetime)値が0になっていなければ、アニメーションのメソッド(move())を呼び出して回す。値が0までカウントダウンされたインスタンスは、プロパティを設定す関数(resetParticle())の呼出しによって使い回している。
これで、100個のパーティクルがつくられ、Canvasの真ん中からさまざまな楕円軌道で残像を描きながら回る(図3)。そして、ランダムに定めたカウントダウンのプロパティ値が0になるたび、インスタンスは設定し直される。ここまで書き替えたクラス(Particle)の定めが以下のコード3で、クラスのインスタンスをつくってアニメーションさせるスクリプトはコード4にまとめて掲げた。
jsdo.itにもサンプルとしてコードを掲載した。アニメーションの見た目は、ほぼでき上がったといってよい。だが、さらにパーティクルを増やすと、込み入った感じになる。もう少し、パーティクルの動きにばらつきを加えたい。それは次回としよう。また、楕円運動の速度を用いた方程式についても、少し数学的な説明を補うつもりだ。