##これまでのあらすじ
PixiJSの基本となる仕組みを把握し、図形、スプライト、文字の描画を見てきました。(ざっくり)
次はアニメーション処理のメインループとなる、PIXI.Tickerの基本を押さえます。
##requestAnimationFrameについて
本題であるPIXI.Tickerについて語る前に、前提として押さえておきたい考え方が一つあります。
それはJavaScriptにおけるアニメーションループの基盤です。
JavaScriptでアニメーション処理を行う場合、たいていはrequestAnimationFrame
が利用されます。
それはPixiJSにおいても例外ではなく、PIXI.Tickerも中身を掘り下げて行くと、このrequestAnimationFrame
に行き着きます。
・requestAnimationFrame(callback)
(MDN:Window.requestAnimationFrame())
このrequestAnimationFrame
は引数としてコールバック関数を一つ受け取り、キューに追加します。
そしてディスプレイの次のリフレッシュが行われる直前に、渡されたコールバックのキューを一斉に一度だけ実行します。
一度だけ実行して終わってしまうとループにはなりませんので、通常は以下のようなイメージで再度自身をキューに追加することでループを構築します。
(※以下のコードは仕組みを大幅に単純化したイメージであり、実際にPixiJS内に以下のようなコードがあるわけではありません)
function updateMain() {
// 各種更新処理
updateA();
updateB();
updateC();
// 各種更新処理が終わったら、再度、リクエストキューに自身を追加
requestAnimationFrame(updateMain);
}
この状態でupdateMain
を実行すると、以下のように、ディスプレイのリフレッシュに同期する形でループが回り始めます。
- 各種更新処理が行われた後、
requestAnimationFrame
により再びupdateMain
がキューに追加される - ディスプレイでリフレッシュが行われるタイミングでキューに追加されていた
updateMain
が実行され、「1.」に戻る
このループにより毎フレーム毎に各描画オブジェクトの座標やゲーム情報などを更新し続けるのがJavaScriptにおけるアニメーション処理の定跡です。
なお、もちろん、各更新処理が次のリフレッシュフレームまでに終了しなければ、次に同期して更新がかかるのは次のフレームになります。
ディスプレイのリフレッシュレートに同期しているとは言っても、厳密に毎秒60フレームの更新が保証されているわけではない点は注意しましょう。
PixiJSのメインループを担うPIXI.Tickerは上記サンプルよりもはるかに多機能かつ高度なので私も把握しきれてはいませんが、基本的な仕組みは同様と考えて良いでしょう。
(気になる方はPIXI.Tickerのコンストラクター内、122行目辺りから_tick
の処理を軽く追ってみてください。
上記の仕組みを念頭に置いて眺めると、requestAnimationFrame
によってthis._tick
がぐるぐる回っていることがなんとなく伝わってくると思います。
(参考:PIXI.Ticker#constructor 122行目~))
要点1:JavaScriptのアニメーション処理の基本はrequestAnimationFrame
。
要点2:requestAnimationFrame
に渡したコールバック関数は、ディスプレイのリフレッシュと同期を取る形で呼び出される。
要点3:コールバック内で再びrequestAnimationFrame
を用いて自身をコールバックさせることでメインループが構築される。
##PIXI.Ticker
####tickerプロパティ
さて、JavaScriptによるアニメーション処理の基本を整理したところで、本題のPIXI.Tickerです。
実際の利用方法としては、PIXIアプリケーションのticker
プロパティにPIXI.Tickerがインスタンス化されているので、それを介して各種機能を使用します。
要点4:PixiJSにおいてはPIXI.Tickerのインスタンスであるticker
プロパティがメインループを担う。
####サンプルコード
今回はPlaygroundのデフォルトのサンプルコードをそのまま使わせてもらうこととします。
サンプルコードから該当箇所だけを抜き出した物が以下です。
// Listen for animate update
app.ticker.add(function(delta)
{
// Rotate mr rabbit clockwise
bunny.rotation += 0.1 * delta;
});
シンプルですね。
####addメソッド
・add(fn, context, priority)
PixiJSの描画ループに処理を追加するメソッドです。
引数として3つの値を受け取りますが、第一引数以外は任意引数です。
fn:メインループに追加するコールバック関数
context:コールバック関数を呼び出す際にbindするオブジェクト。実行時の「this」。
priority:優先順位。通常(省略時)は0。範囲は-50~+50(正が優先される)で設定するみたい。
というわけで、add
メソッドによりメインループ内で繰り返し呼び出されるコールバック関数を追加しました。
これでディスプレイのリフレッシュに合わせて、渡したコールバック関数による更新が行われます。
要点5:メインループに処理を追加するためにはadd
メソッドを使う。
####コールバック関数に渡されるdelta
add
したコールバック関数をよくよく見ると「delta」という引数を受け取るようになっていますね。
function(delta) {
// Rotate mr rabbit clockwise
bunny.rotation += 0.1 * delta;
}
この「delta」はPIXI.Tickerがコールバック関数を呼び出す際に渡してくる値であり、その意味は
「前フレームから今フレームまでの経過時間。
ただし単位は1フレームの通常の処理時間、つまり1/60秒(16.6666666…ミリ秒)を基準とした比率」
です。
つまり順当に60FPSが維持されていれば、deltaの値はおよそ1に、処理が重くて2倍の時間がかかっているようであれば2に近付きます。
実際にはCPU負荷状況やディスプレイのリフレッシュ精度などの影響で常にわずかにズレています。
今回のサンプルコードの場合、このdeltaの値を使って毎フレームにおおよそ0.1(単位:ラジアン)ずつ、バニーさんを回転させているわけです。
要点6:add
されたコールバック関数は、呼び出される際に経過時間(※)を受け取る。
(※:単位は1フレームの通常の処理時間を基準とした比率、処理が重くなっていなければおおよそ1)
####removeメソッド
addがあるならremoveも当然あります。利用場面はあまり多くなさそうですけど。
・remove(fn, context)
(リファレンス)
今回のサンプルでは無名関数を直接渡しているので識別子がないですが、add
する際に名前付き関数として定義して渡していればその識別子でremove
できます。
####speedプロパティ
PIXI.Tickerには面白いプロパティが用意されています。
以下のコードをサンプルの19行目辺りにでも入れてみてください。
app.ticker.speed = 3;
通常の三倍の速さで回転し始めたかと思います。
文字通り、更新処理のスピードを係数倍で調整するプロパティです。倍速の秒間120フレームなら2、半分の30フレームならば0.5という具合です。
ただし、speedを上げるということは処理負荷も上げることに直結しますので、ご利用は計画的に。
要点7:speed
プロパティでループの更新速度は変更可能。ただし負荷増大に注意!
####おまけ
ただぐるぐる回っているだけでは動きが少なくて寂しいので、もう少しダイナミックに動かしてみましょう。
今回のサンプルコードを以下に書き換えてみてください。バニーさんがダイナミックな遊泳をしてくれるようになります。
// Listen for animate update
let elapsedTime = 0;
app.ticker.add(function(delta)
{
// Rotate mr rabbit clockwise
bunny.rotation += 0.1 * delta;
elapsedTime += delta;
bunny.x = Math.sin(elapsedTime * 0.01) * app.renderer.width / 4 + app.renderer.width / 2;
bunny.y = Math.sin(elapsedTime * 0.005) * app.renderer.height / 4 + app.renderer.height / 2;
});
他にもコンテナそのものを回転させてみたり、拡大縮小してみたり、色々ためしてみると良い練習になりそうです。第二回の復習でもあります。
##今回のまとめ
要点1:JavaScriptのアニメーション処理の基本はrequestAnimationFrame
。
要点2:requestAnimationFrame
に渡したコールバック関数は、ディスプレイのリフレッシュと同期を取る形で呼び出される。
要点3:コールバック内で再びrequestAnimationFrame
を用いて自身をコールバックさせることでメインループが構築される。
要点4:PixiJSにおいてはPIXI.Tickerのインスタンスであるticker
プロパティがメインループを担う。
要点5:メインループに処理を追加するためにはadd
メソッドを使う。
要点6:add
されたコールバック関数は、呼び出される際に経過時間(※)を受け取る。
(※:単位は1フレームの通常の処理時間を基準とした比率、処理が重くなっていなければおおよそ1)
要点7:speed
プロパティでループの更新速度は変更可能。ただし負荷増大に注意!
今回はここまで!
次回はインタラクション要素でクリックしたりタップしてみたりするよ!