この解説はThree.jsでES2015のclassを利用する(継承)からの続きです。クラスのメソッドを呼び出すベスト・プラクティスな例を学んでいきましょう。
クラスのメソッドを利用する
時間経過でグループのアニメーションをさせたい場合の方法を紹介します。

時間経過はrequestAnimationFrame()メソッドを使いたいところですが、いたる所にrequestAnimationFrame()メソッドを記述するのはベストプラクティスとは言えません。複数のrequestAnimationFrame()メソッドがあったときに、どれがはじめに実行されるのか、処理の実行順がわかりにくいからです。また、負荷の観点からも複数のrequestAnimationFrame()メソッドを定義するのは最適とは言えません。
悪い例
良くないコード例から見てみます。
/** メッシュを継承した独自グループのクラスです。 */
class MyGroup extends THREE.Object3D {
/** コンストラクターです。 */
constructor() {
super();
// 任意の処理
this.update();
}
/** 更新命令を定義します。 */
update() {
requestAnimationFrame(this.update);
}
}
// 独自グループを作る
const myGroup = new MyGroup();
scene.add(myGroup);
tick();
// 毎フレーム時に実行されるループイベントです
function tick() {
// レンダリング
renderer.render(scene, camera);
requestAnimationFrame(tick);
}
良くないのは親となるコードにも、子供のクラスにもrequestAnimationFrame()が使われているところです。うまく動くと思いますが、どちらのrequestAnimationFrame()が先に実行されるのか、明示的にわからなくなります。メインコードにレンダリングのためのrenderer.render(scene, camera);処理がありますが、その処理の実行前後で子供のMyGroupが実行されるか、保証されません。
改善例
メインとなるコードに一つだけrequestAnimationFrame()メソッドを用意し、そこからツリー構造で独自メソッドを叩いていくといいでしょう。
良い例
/** メッシュを継承した独自グループのクラスです。 */
class MyGroup extends THREE.Object3D {
/** コンストラクターです。 */
constructor() {
super();
// 任意の処理
}
/** 更新命令を定義します。 */
update() {
}
}
// 独自グループを作る
const myGroup = new MyGroup();
scene.add(myGroup);
tick();
// 毎フレーム時に実行されるループイベントです
function tick() {
// 更新命令を実行します。
myGroup.update();
// レンダリング
renderer.render(scene, camera);
requestAnimationFrame(tick);
}
こうすれば、requestAnimationFrame()メソッドが実行されるのはメインコードの一箇所のみになります。メインコードにレンダリングのためのrenderer.render(scene, camera);処理の前に子供のMyGroupクラスのupdate()メソッドが実行されることが保証されます。