Cannon.js + Three.js + React.jsで、
- マウス座標に応じて床を傾ける
- 四方を見えない壁で囲う
という空間を作って、そのな簡易3Dの球を配置してみました。
ソースコード(抜粋)
function handleMouseMove(evt) { const deg = 12; const x = (evt.clientX / windowWidth * 2) - 1; const y = (evt.clientY / windowHeight * 2) - 1; cannonObjectList[0].body.quaternion.setFromEuler( (-90 + deg * y) * Math.PI / 180, (deg * x) * Math.PI / 180, 0 ); }
床の傾きはこんな感じで実装しました。
画面の中心が基準で、
-12° ⬆️ -12° ⬅️ ➡️ 12° ⬇️ 12°
という感じで傾くようにしています。
今回の気づきとしては、CANNON.Planeに向きがあるということです。
A plane, facing in the Z direction. The plane has its surface at z=0 and everything below z=0 is assumed to be solid plane. To make the plane face in some other direction than z, you must put it inside a RigidBody and rotate that body. See the demos.
https://schteppe.github.io/cannon.js/docs/classes/Plane.html より引用
と、ドキュメントに書いてあるのですが、翻訳すると、
A plane, facing in the Z direction. The plane has its surface at z=0 and everything below z=0 is assumed to be solid plane. To make the plane face in some other direction than z, you must put it inside a RigidBody and rotate that body. See the demos.
Z方向を向いている平面。平面の表面はz = 0にあり、z = 0より下のすべてはソリッド平面であると見なされます。平面をz以外の方向に向けるには、平面をRigidBody内に配置し、そのボディを回転させる必要があります。デモをご覧ください。
という感じで、まさにこのことな気がします。
CANNON.Planeを地面として使う際、z = 0より下にオブジェクトがめり込むと高く飛び跳ねます。
つまり、CANNON.Planeはペラペラなわけではなくて、そこを通過すると逆向きの力が発生するわけです。今回壁を作るとき、当初は回転方向を間違えていてボールが吹っ飛んで行った時に気づきました。
壁は、
ソースコード(抜粋)
[ [0, 0, -size, 0, 0, 0], [0, 0, size, 0, Math.PI, 0], [-size, 0, 0, 0, Math.PI / 2, 0], [size, 0, 0, 0, -Math.PI / 2, 0] ].forEach((arr) => { const wallBody = new CANNON.Body({ mass: 0, shape: new CANNON.Plane() }); wallBody.position.set(...arr.splice(0, 3)); wallBody.quaternion.setFromEuler(...arr); const wall = new THREE.Mesh( new THREE.PlaneGeometry(1, 1, 1, 1), new THREE.MeshNormalMaterial() ); wall.material.visible = false; addCannonObject({ body: wallBody, mesh: wall }); scene.add(wall); });
こんな感じのコードで生成しました。
本当は、座標とオイラー角の配列を分けた方が良いと思うのですが、横着してまとめています。