Help us understand the problem. What is going on with this article?

Javascript で動く軽量物理エンジン Cannon.js と3Dレンダラ Three.js で書いた短いサンプルコード

物理エンジンを使って、ゲームを作ってみたくなった。

前回、書かせていただいた記事がこちら。
「Javascript で動く軽量物理エンジン OimoPhysics と3Dレンダラ Three.js で書いた短いサンプルコード」
https://qiita.com/yamazaki3104/items/797b28bba833c06f5f25

その後、OimoPhysicsの続きというか、ジョイントのコードをひたすら書いていたのだが、、、どうも、うまく書けない、、、というかコードと実際の動きが付合しない。
ので、遠回りかもしれないが、他の物理エンジン cannon.js でも書いてみようと思った。

cannon.js
http://schteppe.github.io/cannon.js/

今回、写経させていただいたコードがこちら。前回といい、今回といい、お世話になりっぱなしです。ありがとうございます!!
http://jsdo.it/cx20/qM1k
(なんか、最近よく止まっている気がする>jsdo.it)

jsdo.itは 2019/10/31 を持ちまして終了いたしました。

写経した結果がこちら。

なんか、摩擦係数がちがうみたいで、、、非常にもどかしい。(その後、摩擦係数を指定してなめらかに動くようになりました。おさわがせしました。)


See the Pen
cannon.js + three.js example code
by yamazaki.3104 (@yamazaki3104)
on CodePen.


前回より、若干短くなって、149行。

<html style='margin: 0;height: 100%;'>
<!-- Three.js r106        --><script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/106/three.js"></script>
<!-- TrackballControls.js --><script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r106/examples/js/controls/TrackballControls.js"></script>
<!-- cannon.js v0.6.2     --><script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.js"></script>
<body style='margin: 0;height: 100%;'>
<script>

class THREEJS
{
    constructor()
    {
        const w = document.body.clientWidth
        const h = document.body.clientHeight

        this.renderer = new THREE.WebGLRenderer()
        this.renderer.setClearColor( 0x8888dd )
        this.renderer.setSize( w, h )

        this.camera = new THREE.PerspectiveCamera( 40, w / h, 0.1, 1000 )
        this.camera.position.x =  0
        this.camera.position.y = 20
        this.camera.position.z = 30
        this.trackball = new THREE.TrackballControls( this.camera )

        this.scene = new THREE.Scene()

        let directionalLight = new THREE.DirectionalLight( 0xffffff, 1 )
        directionalLight.position.set( 0.2, 0.5, 0.3 )
        this.scene.add( directionalLight )

        // this.scene.add( new THREE.AmbientLight( 0x101020 ) )

        document.body.appendChild( this.renderer.domElement )
    }

    add_mesh( _arg )
    {
        let mesh = new THREE.Mesh(
            new THREE.BoxGeometry( _arg.w, _arg.h, _arg.d ),
            new THREE.MeshLambertMaterial( { color: _arg.color } )
        )
        mesh.cannon_rigid_body = _arg.body
        this.scene.add( mesh )
    }

    render()
    {
        for ( let mesh of this.scene.children )
        {
            if ( ! mesh.cannon_rigid_body ) continue

            mesh.position.copy(   mesh.cannon_rigid_body.position   )
            mesh.quaternion.copy( mesh.cannon_rigid_body.quaternion )
        }

        this.trackball.update()
        this.renderer.render( this.scene, this.camera )
    }
}

class CANNON_PHYSICS
{
    constructor( _threejs )
    {
        this.cannon_world = new CANNON.World()
        this.cannon_world.gravity.set( 0, -9.80665, 0 )
        this.cannon_world.broadphase = new CANNON.NaiveBroadphase()
        this.cannon_world.solver.iterations = 10

        this.threejs = _threejs
    }

    create_rigid_body( _arg )
    {
        const body  = new CANNON.Body( {
            mass:       _arg.mass,
            shape:      new CANNON.Box( new CANNON.Vec3( _arg.w/2, _arg.h/2, _arg.d/2 ) ),
            position:   new CANNON.Vec3( _arg.x, _arg.y, _arg.z ),
            material:   new CANNON.Material( { friction: 0.1, } ), // 摩擦係数 0.1 マテリアルを作成
        } )
        this.cannon_world.add( body )
        this.threejs.add_mesh( { body: body, w: _arg.w, h: _arg.h, d: _arg.d, color: _arg.color } )
    }

    render( _sec )
    {
        this.cannon_world.step( _sec )
        this.threejs.render()
    }
}

// MAIN
let cannon_phy = new CANNON_PHYSICS( new THREEJS() )

cannon_phy.create_rigid_body( {
    mass: 0, x: 0, y: -0.2, z: 0, w: 50, h: 0.4, d: 50, color: 0x333333,
} )


const dataSet = [
    0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,
    0,0,0,0,0,0,3,3,3,3,3,0,0,1,1,1,
    0,0,0,0,0,3,3,3,3,3,3,3,3,3,1,1,
    0,0,0,0,0,2,2,2,1,1,2,1,0,3,3,3,
    0,0,0,0,2,1,2,1,1,1,2,1,1,3,3,3,
    0,0,0,0,2,1,2,2,1,1,1,2,1,1,1,3,
    0,0,0,0,2,2,1,1,1,1,2,2,2,2,3,0,
    0,0,0,0,0,0,1,1,1,1,1,1,1,3,0,0,
    0,0,3,3,3,3,3,5,3,3,3,5,3,0,0,0,
    0,3,3,3,3,3,3,3,5,3,3,3,5,0,0,2,
    1,1,3,3,3,3,3,3,5,5,5,5,5,0,0,2,
    1,1,1,0,5,5,3,5,5,4,5,5,4,5,2,2,
    0,1,0,2,5,5,5,5,5,5,5,5,5,5,2,2,
    0,0,2,2,2,5,5,5,5,5,5,5,5,5,2,2,
    0,2,2,2,5,5,5,5,5,5,5,0,0,0,0,0,
    0,2,0,0,5,5,5,5,0,0,0,0,0,0,0,0
]

const box_size = 1.5
for ( let y=0 ; y<16; y++ ) {
    for ( let x=0 ; x<16; x++ ) {
        cannon_phy.create_rigid_body( {
            mass: 1,
            x: (x-7) * box_size * 0.95, y: box_size * 0.5, z: (y-7) * box_size * 1.2,
            w: box_size*0.1, h: box_size*1, d: box_size*1,
            color: [ 0xDCAA6B, 0xffcccc, 0x800000, 0xff0000, 0xffff00, 0x0000ff ][ dataSet[ y * 16 + x ] ],
        })
    }
}

for ( let i=0 ; i<16; i++ ) {
    cannon_phy.create_rigid_body({
        mass: 3,
        x: -7 * box_size, y: box_size * 3, z: (i-7) * box_size * 1.2,
        w: box_size, h: box_size, d: box_size,
        color: 0xeeeeee
    })
}

function animate()
{
    cannon_phy.render( 1 / 60 )
    window.requestAnimationFrame( animate )
}
window.requestAnimationFrame( animate )

</script>
</body>
</html>

Three.js のコードは、ほぼほぼ前回といっしょ。

OimoPhysics の部分を cannon.js に変えただけ。割と容易にできました。

摩擦の設定に関しては以下のコードを参考にさせていただきました!!ありがとうございました。

「Three.jsとCANNON.jsで作る「VR3D脱出迷路アプリ」作成(その1)」
https://qiita.com/DAI788/items/4d7397e7918eb9be6d81

var groundMat = new CANNON.Material('groundMat');    //マテリアルを作成
groundMat.friction = 0.3;       //摩擦係数
groundMat.restitution = 0.5;    //反発係数

phyPlane = new CANNON.Body({mass: 0});      //ボディを作成
phyPlane.material = groundMat;              //ボディにマテリアルを設定

次こそ、ジョイントのコードを書く!!

追記です。
ジョイント(ヒンジだけど)のコード⬇️を参考にして、くるまらしきモノを乱入させてみた。
https://github.com/schteppe/cannon.js/blob/master/demos/hinge.html

コードはちょっと長くなってしまって、短くはないかな。コードが見たいひとは、CodePenからどうぞ。

See the Pen cannon.js + three.js example code 2 by yamazaki.3104 (@yamazaki3104) on CodePen.

みなさまのおかげで、だいぶ理解できてきた気がする。

この調子で、ゲームにしていこう!!

hearts-tech
ソフトウェアの企画・開発及び販売・保守や広報・セールスプロモーションの企画・立案・実施を行ってます。
https://www.hearts-tech.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away