今回はthree.jsの三次元物理演算プラグインのPhysijsを使用して、ジャンプ台や、デコボコ道を通る、オフロードレースゲームサンプルを作成しました。
PhysijsはChandlerPrall氏による作成されたthree.jsの物理演算用のプラグインです。内部でammo.jsという物理演算ライブラリを使用していて、ammo.jsとthree.jsを簡単に連携させることができるようになっています。ammo.jsはBulletという有名なオープンソースの物理演算エンジンをJavaScriptに移植したものです。
このPhysijsを利用して、オフロードレースゲームのサンプルを作成しました。まずはサンプルをご覧ください。
ソースコード
※操作方法 : 前進「↑」キー、後退「↓」キー、旋回「←→」キー、カメラアングル切り替え「スペース」キー
※WebGLを使用したデモなのでChromeかFireFoxで閲覧してください。
前回の二次元物理エンジンBox2DJSでのサンプルと比べると、道のデコボコやジャンプ台が車の走行に影響を与えるようになっています。複雑なロジックを組んでいるように見えますが、Physijsはthree.jsのプラグインとして開発されていますので、Box2DJSを併用している時よりも、コードはシンプルなものとなっています。
簡単ですがコードの説明です。
まずはnew Physijs.Scene()でシーンを作成します。これはnew THREE.Scene()を三次元物理演算用にラップしたものです。そしてsetGravityメソッドでシーンに重力を与えます。
main.js(182行目~)
function _constructor() {
_scene = new Physijs.Scene();
if (!IS_DEBUG_MODE) _scene.fog = new THREE.FogExp2(0xaa8f46, 0.005);
_scene.setGravity(new THREE.Vector3(0, GRAVITY, 0));
}
次にデコボコした道を作ります。three.jsのPlaneGeometoryで平面を作成して、作成したジオメトリの頂点の位置をランダムに変更します。これでデコボコした平面ジオメトリが作成されました。
main.js(278行目~)
geometry = new THREE.PlaneGeometry(MAP_WIDTH, MAP_HEIGHT, MAP[0].length, MAP.length);
for (var i = 0; i < geometry.vertices.length; i++) {
var vertex = geometry.vertices[i];
vertex.z = Math.random() * ROAD_BUMP;
}
次にthree.jsでいつも通りマテリアルを作成しています。このマテリアルを第一引数に指定して、第二引数に摩擦係数、第三引数に反発係数を指定して、PhysijsのcreateMaterialメソッドで、three.jsのマテリアルに物理演算用のプロパティが付加されたPhysijsで使用するマテリアルを作成します。ちなみに摩擦係数は低いほど、よく滑るようになります。反発係数は高いほどスーパーボールの用に跳ねる物体となります。
main.js(278行目~)
material = Physijs.createMaterial(new THREE.MeshLambertMaterial({
map: texture,
bumpMap: texture,
bumpScale: 0.1,
specular: 0xFFFFFF,
shininess: 2000,
wireframe: WIRE_FRAME
}), 20, // 摩擦係数
0.1 // 反発係数
);
そして作成したジオメトリとマテリアルを元にPhysijsのメッシュを作成します。メッシュ作成時には第三引数に質量を指定します。このメッシュは地面は質量を0に設定し、この場に固定させます。これで重力の影響を受けない物体となります。
Physijs.HeightfieldMeshは、頂点を変更した平面ジオメトリをラップする事ができます。他にもPhysijs.BoxMeshやPhysijs.SphereMeshなど、three.jsのメッシュ形状に合わせて複数用意してありますので、必要に応じて選択します。Physijsにメッシュとして用意されているものは公式サイトで確認する事ができます。
main.js(299行目~)
mesh = new Physijs.HeightfieldMesh(geometry, material, 0, MAP[0].length, MAP.length);
このようにPhysijsではthree.js上のメッシュと物理演算で使用するオブジェクトを一致させる必要があります。いかにもプラグインらしいシンプルで使いやすい振る舞いですが、場合によっては制限事項となってしまうでしょう。
基本的にはこの流れで3Dオブジェクト生成していくこととなります。次に車を作るのですが、今回はタイヤを動かすために、回転する軸として使えるnew Physijs.DOFConstraint()を使用しています。物理エンジンには大抵、物体の動きにある制約も設ける機能が存在しています。Physijsで提供されている機能は公式サイトにて確認できます。
車を作成したらキー入力を監視して、タイヤを回す事で、車全体の重量とそれによって生じるタイヤと地面との摩擦で車を走らせる事ができます。三次元の物理演算にてゲームを制御していますので、重力、質量、摩擦係数、反発係数の関係でゲームバランスを調整する必要があり、実はここが一番難しいところなのかもしれません。疑似的に動きを再現したものだと動きのロジックに変化を与える事は簡単ですが、三次元物理演算では、重力、質量、摩擦係数、反発係数を、どう変更すれば、意図した結果を生むのか想定しながら調整する必要があり、それらのチューニングに神経を注ぐ事となります。
今回はthree.jsのプラグインとして気軽に利用できるPhysijsを利用しました。Physijsはthree.jsプラグインなのでthree.jsを使う感覚で、質量や摩擦係数、反発係数等を付加するだけで物理演算を行う事が出来ますが、利用できる機能はシンプルな分限られています。内部でammo.jsを利用しているので拡張は可能かと思います。
プラグインという形ではないのですが、JavaScript三次元物理エンジンは他にも複数あります。ammo.jsはもちろんですが、cannon.jsも、強力な三次元物理演算として有名です。cannon.jsは物理エンジンのデファクトスタンダードとも呼べる「Bullet(弾丸)」に対して、弾丸より強くしたいということでカノン(大砲)という名が付けられました。three.jsをインスパイアしていて、three.jsと非常に相性がよく出来ているところもポイントです。
当初はこちらを利用しようと考えていましたが、どうもthree.jsの最新バージョン(r64)と合わず、使いにくかったので(具体的には物理演算対象のオブジェクトと3D表示オブジェクトの座標がずれる)とりあえずPhysijsを使用する事としました。
最近急加熱した三次元熱はさめやらぬですが、ロジック云々よりも、モデリングをある程度出来るようになりたくなります。モデリングの方は全く素人ですが、まずはBlenderを使って初めて見ようかと思いました。