three.jsでゲーム設計するときにやったこと1

稚拙な出来で恐縮なのですが、three.jsを使って3Dのオセロを作りました。
その際にやったことを書きたいと思います。

Meshを継承する

例えば、球体のメッシュをもつテニスボールというオブジェクトを作るとしましょう。その際に、

class TennisBall{
  constructor(){
    this.mesh = new Mesh(new SphereGeometry(), new MeshPhongMaterial());
  }
}

という風にメンバとしている方もいるかと思います(僕はこうしていました)
しかし、このようにすると次のような問題点があります。

  1. メッシュからTennisBallオブジェクトにアクセスできない
  2. メッシュが非同期に読み込まれるときに、メッシュがあることが保証できない

1番目の問題についてですが、three.jsにはgetObjectByPropertyなどのシーンからオブジェクトを取り出せる便利なメソッドがありますが、この実装ではメッシュからTennisBallオブジェクトにアクセスできないので、活かすことができません。メッシュにTennisBallへの参照を持たせればアクセスできなくもないですが、避けたいです。
2番目については、three.jsでは外部オブジェクトを読み込む際には非同期の処理になっています。なのでTennisBallオブジェクトとMeshオブジェクトの存在の時間にラグが生まれます。つまり、TennisBallオブジェクトからMeshオブジェクトにアクセスするときに存在の確認する手間が必要になります。
以上の理由より、次のようにMeshを継承する形でTennisBallクラスを作るのが良いのではないかと思います。

class TennisBall extends Mesh{
  constructor(geo, mat){
    super(geo, mat);
  }
}

このようにすれば、three.jsが提供する便利な関数も使えますし、非同期に読み込まれるメッシュにも気にしなくてすみます。

onBeforeRenderを活用する

r82よりObject3DにonBeforeRenderが追加されました。onBeforeRenderは文字どおり、レンダリング前に呼び出されるコールバックを登録できる機能ですが、依存関係を減らすのにとても有効です。
例として、一定速度で先ほど書いたTennisBallを動かす処理を、普通に書くと以下のようになります。

const tennisBall = new TennisBall(new SphereGeometry(), new MeshPhongMaterial());

function animate(){
  requestAnimationFrame(animate);
  tennisBall.translateX(10);
  renderer.render(scene, camera);
}

これくらいなら全く問題はありませんが、ゲームが複雑になり色々なオブジェクトを動かそうとすると、animate関数は瞬く間に複雑になるでしょう。これを解決するのがonBeforeRenderです。コードとしては次のようにかけるでしょう。

class TennisBall extends Mesh{
  constructor(geo, mat){
    super(geo, mat);
  }

  onBeforeRender(renderer, scene, camera){
    this.translateX(10);
  }
}
const tennisBall = new TennisBall(new SphereGeometry(), new MeshPhongMaterial());

function animate(){
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

見てわかるように、オブジェクトを動かすtranslateXがTennisBallクラスのonBeforeRenderに移動しました。こうすることによってオブジェクトが増えてもanimate関数が肥大化することはなくなります。

この投稿へのコメント

コメントはありません。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

この投稿へのトラックバック

トラックバックはありません。

トラックバック URL