12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-07-20

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

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

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

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)」

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

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

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

追記です。
ジョイント(ヒンジだけど)のコード⬇️を参考にして、くるまらしきモノを乱入させてみた。

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

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

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

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

12
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?