前回の第26回「パーティクルを使い回しながらさまざまな楕円軌道で回す」では、速度からランダムに導いた楕円軌道でパーティクルを回してみた。今回は、そのランダムをさらにばらつかせる。そして、楕円運動の速度から位置を求める方程式についても、数学的な説明を補おう。
パーティクルの動き始めもランダムにする
前回できあがりの第26回コード4「パーティクル100個を使い回しながらさまざまな楕円軌道で回す」では、すべてのパーティクルが一斉に動き出す。そのため、パーティクルの動きが揃って同じ位置に集まってしまう(図1)。つぎのようにパーティクルの数(total)を増やしてみるとわかりやすい。ただし、オブジェクトを使い回して設定し直す関数(resetParticle())により、つぎの再設定時(lifetime)がランダムに定められるため、動きのばらつきはやがて広がる(第26回「100個のパーティクルを使い回して再設定する」参照)。
ここはやはり、動き始めについても、ランダムな時間差を与えることにする。クラス(Particle)のパーティクル設定のメソッド(reset())に加える引数(delay)で、動き出すまでにタメを与える。引数に与えられるランダムな正数値は、プロパティ(delay)にもつ。そして、カウンタのプロパティ(index)をアニメーションのたびに加算して、タメの値を超えたら動かす。カウントアップしながらふたつのプロパティ値を比べるメソッド(isMovable())は、クラスに新たに備えた。
アニメーションの関数(tick())は以下のように、パーティクルを動かしてよいかどうか、上記で加えたメソッド(isMovable())により確かめたうえで動かすようにした。
タメの値(delay)は、パーティクルを設定する関数(resetParticle())から、ランダムに定めてオブジェクト(particle)のメソッド(reset())に渡す。ただし、もとになる値を関数が引数として受け取っている。これは初期設定の関数(initialize())がパーティクルを予め定めた数(total)つくるとき、forループのカウンタ変数(i)がもつ値だ。すると、ループの初めにつくられたオブジェクトは早めに動き出す。これで、パーティクルが揃ってタメすぎることを防げる。
これらの書替えをおこなったパーティクルのクラス(Particle)と楕円軌道でアニメーションさせるJavaScriptコードは、それぞれコード1およびコード2としてまとめた。これで、パーティクルの動き始めにそれぞれランダムなタメが加わる(図2)。オブジェクトが使い回されて再設定されるときにも、このタメは利いているはずだ。わかりづらいだろうが、画面の真ん中に一瞬留まるパーティクルができている。
メソッドを動的に切換える
パーティクルのアニメーション表現そのものは、これで決まりとする。その代わりにもうひと手間加えたいのは、処理の組立ての改善だ。前掲コード1では、それぞれのパーティクルを動かし始めてよいかどうかは、ブール値を返すクラス(Particle)のメソッド(isMovable())として備えた。そして、前掲コード2のパーティクルをアニメーションさせる関数(tick())で、メソッドの戻り値を確かめて動かした。
しかし、ひとたびタメ終わったら、その後もいちいち動かしていいかメソッド(isMovable())に尋ねるのは煩わしい。動かし始めるかどうか教えて済ますのでなく、実際にパーティクルを楕円軌道で回すところまで、クラス(Particle)で扱ってしまえないだろうか。つまり、前掲コード2のアニメーションの関数(tick())から、つぎのようにパーティクルを動かす関数(moveParticle())につないでオブジェクト(particle)のメソッド(move())を呼び出してしまい、メソッド側でタメるか回すかを切り換えたい。
さて、前掲コード1のパーティクルのクラス(Particle)を書き替えよう。上記のパーティクルを動かす関数(moveParticle())から呼び出すメソッド名は、以下のようにプロパティ(move)とし、メソッド名(_move())は変えた。そして、パーティクル設定のメソッド(reset)で、プロパティにはカウンタプロパティ(index)加算のメソッド(_movable)を代入した。
そして、カウントアップした値がタメのプロパティ値(delay)を超えたら、上記パーティクルを動かす関数(moveParticle())から呼出すメソッド(move)の参照先は、楕円軌道を回るメソッド(_move)に置き換える。これで、動き始めはタメてたうえで、楕円軌道を回るパーティクルのふるまいがクラス(Particle)で扱えるようになった。
これらの手直しをしたパーティクルのクラスの定めとそれを用いたJavaScriptコードは、それぞれコード3とコード4にまとめた。あわせて、同じコードをjsdo.itにもサンプルとして掲げた。
等速円運動と速度
結びとして、前回「楕円軌道を速度から導く」やり方としてご紹介したつぎの式について、数学的な説明を補おう。興味がある読者向けの解説なので、数学が苦手あるいは結論だけわかれば理屈は気にしないという方はここまでお読みいただいただけで構わない。
速度とは、時間あたりで動く位置の変化だ。たとえば秒速が与えられたら、1秒後の位置は速度の値を加えれば求まる。等速直線運動なら、毎秒つぎのように一定値(定数)を加えればアニメーションが表せる。なお、水平(x)も垂直(y)も考え方は同じなので、ひとつの式で示した(ベクトルと考えればよい)。
等速直線運動でない場合、速度は時々刻々変わる。そのときは、時間の関数として表す。たとえば、自由落下運動(初速は0とされる)であれば、時間が経つにしたがって重力加速度が加わる[1]。なお、重力加速度は定数だ。
数学では、自由落下は位置(x)の時間(t)に対する2次方程式で表される。そして、速度(v)は一般に、位置の方程式を時間で微分した導関数(x')として求める。したがって、自由落下の速度は時間に比例する。比例係数が加速度だ。
第25回「楕円軌道に残像を描きながら回るパーティクル」の「楕円軌道を描いて動かす」でご紹介した円軌道の位置(x, y)は、半径(r)と時間(t)あたりに回る角度(ω)にもとづいてつぎの方程式で与えられる(原点を中心とする)。
これらの方程式を微分すれば速度(x', y')が求まる。これが第26回「パーティクルを使い回しながらさまざまな楕円軌道で回す」の「楕円軌道を速度から導く」でご紹介した速度の式だ。さらに詳しく知りたい読者は、「等速円運動を三角関数の微分で表す」をお読みいただきたい。
時間の単位をフレームとし(※1参照)、フレームあたりの回転角を角速度と定めれば、フレームごとに現在位置に速度を加えることで円運動のアニメーションが表せる。それが本項の初めに示した式だ。