Three.jsでゲーム

スマホのプラウザ上で遊べる3Dゲームはあまり見かけません。そこで、matter.jsとthree.jsを組み合わせて作ったプラウザゲームのソースリストを載せました。 スマートフォンでも動作します。

①3DCGエンジンThree.jsのサンプルゲーム
three.min.jsを用意します。
https://threejs.org/のメニュー「download]リンクからライブラリをダウンロードします。ダウンロードしたthree.js-master.zipを展開して、その中のフォルダ「build」のthree.min.jsをコピーします。
新規作成で新しいフォルダを作り、「testgame」など名前を付けて下さい。そこにthree.min.jsをコピーして保存して下さい。メモ帳を開き、下記のソースリスト2つもコピーして「index.html」、「main.js」の名前を付けて文字コードUTF8でペーストして、作成したフォルダに保存して下さい。このフォルダだけでゲームを実行出来ます。
three.jsは、ローカルの環境では画像を貼り付ける事が出来ません。
three.jsは3Dグラフィックスを描画するためのエンジンで、他のゲームエンジンと共に使うと効果的です。出来上がったものは下記からも実行できます。スマートフォンでも動作します。
threetest
index.html

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>three.js game</title>
</head>
<body ontouchmove="event.preventDefault()">
<script src="three.min.js"></script>
<div id="js-engine" class="engine"></div>
<script src="main.js"></script>
</body>
</html>

main.js

(function () {
    var MAP = [//コースの2次元配列
        [1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2],
        [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2],
        [1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 2, 2],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 0, 1, 1, 0, 3, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2],
        [1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 2, 2],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2],
        [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 2, 2, 0, 2, 2, 2, 0, 3, 2, 2],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2],
        [1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 4, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 4, 1, 1, 1, 0, 1, 1, 0, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 3, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2],
        [1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 0, 3, 0, 2],
        [1, 0, 1, 1, 0, 3, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 0, 2],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 2, 3, 2, 3, 2, 0],
        [1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2],
        [1, 0, 2, 0, 2, 0, 1, 0, 1, 0, 2, 0, 2, 0, 1, 0, 3, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 4, 0, 0, 3, 3, 0, 3, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 3],
        [1, 0, 0, 3, 0, 0, 1, 0, 1, 0, 0, 3, 0, 0, 1, 0, 2, 0, 0, 4, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 4, 0, 4, 0, 2, 0, 2, 0, 0, 4, 0, 0, 2],
        [1, 0, 2, 0, 2, 0, 1, 0, 1, 0, 2, 0, 2, 0, 1, 0, 3, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 4, 0, 0, 3, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 3],
        [1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2],
        [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 2, 3, 2, 3, 2, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 2, 3, 2, 0, 2, 0, 0, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 2, 3, 2, 3, 2, 0],
        [1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2],
        [1, 0, 0, 2, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 1, 0, 3, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 3],
        [1, 0, 2, 3, 2, 0, 1, 0, 1, 0, 2, 3, 2, 0, 1, 0, 0, 0, 0, 4, 0, 0, 0, 0, 2, 0, 4, 0, 4, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 4, 0, 0, 0],
        [1, 0, 0, 2, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 1, 0, 3, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 0, 4, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3],
        [1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2],
        [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 2, 0, 2, 3, 2, 0, 0, 0, 0, 2, 3, 2, 3, 2, 0, 0, 0, 2, 3, 2, 3, 2, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 1, 1, 0, 1, 2, 1, 0, 2, 1, 1, 0, 2, 1, 2, 0, 1, 1, 1, 0, 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1],
        [1, 0, 0, 0, 2, 0, 2, 0, 4, 2, 2, 2, 3, 0, 1, 0, 1, 2, 0, 0, 2, 0, 1, 0, 2, 0, 0, 2, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 1, 0, 2, 2, 2, 3, 0, 0, 1],
        [0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1],
        [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 2, 0, 0, 2, 2, 2, 0, 2, 0, 2, 0, 2, 2, 0, 2, 2, 2, 0],
        [1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 2, 0, 0, 1, 0, 2, 0, 2, 0, 1, 0, 1, 2, 0, 2, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 2, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 2, 0, 0, 2, 2, 2, 0, 2, 2, 1, 0, 2, 2, 0, 2, 2, 1, 2]
    ];
    //自機
    const playerCar = Car();//ファンクションで定義
    //地面
    const geometry = new THREE.PlaneGeometry(48 * 26, 48 * 26);
    const material = new THREE.MeshBasicMaterial({ color: "floralwhite", side: THREE.BackSide });//裏返しに張り付けなければ、透明になってしまう
    const plane = new THREE.Mesh(geometry, material);

    let right = false;//右回転
    let left = false;//左回転
    let up = false;//上前進む
    let down = false;//下前進む
    let one_quarter = window.innerWidth / 4;//画面横幅の4分の1

    //three.jsシーン
    const scene = new THREE.Scene();

    //light環境光源
    const ambient = new THREE.AmbientLight(0xffffff, 1.0);
    scene.add(ambient);
    //camera
    var camera = new THREE.PerspectiveCamera(45,innerWidth / window.innerHeight, 1, 2000);//THREE.PerspectiveCamera(視野角, アスペクト比, near, far)
    camera.position.y = 100;//カメラの地面からの高さ
    //rendering
    const renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0x87CEEB, 1);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMapEnabled = false;
    document.body.appendChild(renderer.domElement);

    //キー入力
    document.onkeydown = function (e) {
        e.preventDefault();//規定の動作をキャンセル
        if (e.key == 'ArrowUp') { up = true }
        if (e.key == 'ArrowRight') { right = true }
        if (e.key == 'ArrowLeft') { left = true }
        if (e.key == 'ArrowDown') { down = true }
    };
    document.onkeyup = function (e) {
        e.preventDefault();//規定の動作をキャンセル
        if (e.key == 'ArrowUp') { up = false }
        if (e.key == 'ArrowRight') { right = false }
        if (e.key == 'ArrowLeft') { left = false }
        if (e.key == 'ArrowDown') { down = false }
    };

    //スマホ入力
    window.addEventListener('touchstart', (e) => {
        e.preventDefault();
        for (var i=0;i<e.changedTouches.length;i++) {
            if (e.changedTouches[i].pageX > one_quarter * 3) { right = true }//画面幅3/4より大きい
            if (e.changedTouches[i].pageX < one_quarter) { left = true }//画面幅1/4より小さい
            if (e.changedTouches[i].pageX > one_quarter * 2 && e.changedTouches[i].pageX < one_quarter * 3) { up = true }//画面幅1/2から3/4
            if (e.changedTouches[i].pageX < one_quarter * 2 && e.changedTouches[i].pageX > one_quarter) { down = true }//画面幅1/4から1/2
        }
    },{passive: false});
    window.addEventListener('touchend', (e) => {
        e.preventDefault();
        for (var i=0;i<e.changedTouches.length;i++) {
            if (e.changedTouches[i].pageX > one_quarter * 3) { right = false }
            if (e.changedTouches[i].pageX < one_quarter) { left = false }
            if (e.changedTouches[i].pageX > one_quarter * 2 && e.changedTouches[i].pageX < one_quarter * 3) { up = false }
            if (e.changedTouches[i].pageX < one_quarter * 2 && e.changedTouches[i].pageX > one_quarter) { down = false }
        }
    },{passive: false});

    //最初にここから実行する
    plane.position.set(24 * 26, 0, 24 * 26);//地面をセットする
    plane.rotation.x = Math.atan2(1, 0);//地面を水平にする
    scene.add(plane);
    scene.add(playerCar);
    Initialset();//ファンクションInitialset()を実行
    playerCar.position.z = 26 * 4.5;
    playerCar.position.x = 26 * 4;
    playerCar.rotation.y = 0;
    renderer.setAnimationLoop(animation);//レンダラーにループ関数animationを登録

    //フレーム毎に繰り返し実行
    function animation() {
        if (right) { playerCar.rotation.y = playerCar.rotation.y - Math.PI / 36 }//右に回転
        if (left) { playerCar.rotation.y = playerCar.rotation.y + Math.PI / 36 }//左に回転
        if (up) {
            if (playerCar.position.y < 300) {playerCar.position.y = playerCar.position.y + 10};
            playerCar.position.x = playerCar.position.x + Math.cos(playerCar.rotation.y) * 10;
            playerCar.position.z = playerCar.position.z - Math.sin(playerCar.rotation.y) * 10;
        }//上前進む
        if (down) {
            if (playerCar.position.y > 0) {playerCar.position.y = playerCar.position.y - 10};
            playerCar.position.x = playerCar.position.x + Math.cos(playerCar.rotation.y) * 10;
            playerCar.position.z = playerCar.position.z - Math.sin(playerCar.rotation.y) * 10;
            }//下前進む
        camera.position.x = playerCar.position.x - Math.cos(playerCar.rotation.y) * 50;//カメラをplayerCarの後ろ上にセット
        camera.position.z = playerCar.position.z + Math.sin(playerCar.rotation.y) * 50;
        camera.position.y = playerCar.position.y + 100;
        camera.lookAt(playerCar.position);//playerCarにカメラを向ける
        renderer.render(scene, camera);//シーンとカメラで描画
    };

    function Initialset() {
        for (i = 0, max = MAP.length; i < max; i++) {
            for (j = 0, max2 = MAP[i].length; j < max2; j++) {
                //ビル1
                if (MAP[j][i] == 1) {
                    //loader = new THREE.TextureLoader(); texture = loader.load("build11.jpg"); texture2 = loader.load("build12.jpg");
                    const matebrock1 = new THREE.Mesh(new THREE.BoxBufferGeometry(26, 80, 26), [
                        new THREE.MeshBasicMaterial({ color: 'chocolate' }),//new THREE.MeshBasicMaterial({ map: texture });
                        new THREE.MeshBasicMaterial({ color: 'darkorange' }),
                        new THREE.MeshBasicMaterial({ color: 0xa5756b }), ,
                        new THREE.MeshBasicMaterial({ color: 'sienna' }),
                        new THREE.MeshBasicMaterial({ color: 'saddlebrown' })
                    ]);
                    scene.add(matebrock1);
                    matebrock1.position.z = j * 26 + 13;
                    matebrock1.position.x = i * 26 + 13;
                    matebrock1.position.y = 40;
                }
                //ビル2
                if (MAP[j][i] == 2) {
                    const matebrock2 = new THREE.Mesh(new THREE.BoxBufferGeometry(26, 140, 26), [
                        new THREE.MeshBasicMaterial({ color: 'dimgray' }),
                        new THREE.MeshBasicMaterial({ color: 'gray' }),
                        new THREE.MeshBasicMaterial({ color: 0x7c7c7a }), ,
                        new THREE.MeshBasicMaterial({ color: 'silver' }),
                        new THREE.MeshBasicMaterial({ color: 'darkgray' })
                    ]);
                    scene.add(matebrock2);
                    matebrock2.position.z = j * 26 + 13;
                    matebrock2.position.x = i * 26 + 13;
                    matebrock2.position.y = 70;
                }
                //ビル3
                if (MAP[j][i] == 3) {
                    const matebrock3 = new THREE.Mesh(new THREE.BoxBufferGeometry(26, 200, 26), [
                        new THREE.MeshBasicMaterial({ color: 'steelblue' }),
                        new THREE.MeshBasicMaterial({ color: 'royalblue' }),
                        new THREE.MeshBasicMaterial({ color: 0x928e3e }), ,
                        new THREE.MeshBasicMaterial({ color: 'midnightblue' }),
                        new THREE.MeshBasicMaterial({ color: 'navy' })
                    ]);
                    scene.add(matebrock3);
                    matebrock3.position.z = j * 26 + 13;
                    matebrock3.position.x = i * 26 + 13;
                    matebrock3.position.y = 100;
                }
                //ビル4
                if (MAP[j][i] == 4) {
                    const matebrock4 = new THREE.Mesh(new THREE.BoxBufferGeometry(26, 280, 26), [
                        new THREE.MeshBasicMaterial({ color: 'darkmagenta' }),
                        new THREE.MeshBasicMaterial({ color: 'purple' }),
                        new THREE.MeshBasicMaterial({ color: 0xc2c7cb }), ,
                        new THREE.MeshBasicMaterial({ color: 'indigo' }),
                        new THREE.MeshBasicMaterial({ color: 'darkslateblue' })
                    ]);
                    scene.add(matebrock4);
                    matebrock4.position.z = j * 26 + 13;
                    matebrock4.position.x = i * 26 + 13;
                    matebrock4.position.y = 140;
                }
            }
        }
    }

    function Car() {//自機定義
        const car = new THREE.Group();

        const geomain = new THREE.BoxBufferGeometry(10, 2, 20);
        //loader = new THREE.TextureLoader();texture = loader.load("wall01.jpg");
        const matemain = new THREE.MeshBasicMaterial({ color: "red" });//new THREE.MeshBasicMaterial({ map: texture });
        const main = new THREE.Mesh(geomain, matemain);
        main.position.set( 0, 0, 0);
        car.add(main);

        const geocabin = new THREE.BoxBufferGeometry( 8, 10, 6);
        //loader = new THREE.TextureLoader();texture = loader.load("wall01.jpg");
        const matecabin = new THREE.MeshBasicMaterial({ color: "deepskyblue" });//new THREE.MeshBasicMaterial({ map: texture });
        const cabin = new THREE.Mesh(geocabin, matecabin);
        cabin.position.set(0, 2, 0);
        car.add(cabin);
        return car;
    }

    //three.js表示の上に文字を表示する
    container = document.createElement('div');
    document.body.appendChild(container);
    var info = document.createElement('div');
    info.style.position = 'absolute';
    info.style.left = '10%';
    info.style.top = '20%';
    info.style.width = '80%';
    info.style.color = "navy";
    info.style.fontWeight = "bold";
    info.style.fontSize = '3vw';
    info.innerHTML = 'PC:[→]右回転[←]左回転[↑]上前進む[↓]下前進む<br>スマホ:タッチ[左回転][下前進む][上前進む][上前進む]';
    container.appendChild(info);
    window.setTimeout(function () { info.innerHTML = ' ' }, 4000);//一定時間で表示を消す
})();

②Three.jsとMatter.jsのサンプルゲーム1
matter.js をダウンロードします。 https://brm.io/matter-js/ で Latest Buildを選ぶとGitHubに行くので、登録してサインインします。そうすると右の方のボタン「Clone or download」が選択可能になるので、「Download ZIP」を選択してZIPファイルをダウンロードします。解凍した「matter-js-master」の中のフォルダ「build」 のなかのmatter.min.jsだけ使います。続いてthree.min.jsを用意します。
https://threejs.org/のメニュー「download]リンクからライブラリをダウンロードします。ダウンロードしたthree.js-master.zipを展開して、その中のフォルダ「build」のthree.min.jsをコピーします。
新規作成で新しいフォルダを作り、「testgame」など適当に名前を付けて下さい。メモ帳を開き、下記の2つをコピーして、「index.html」、「main.js」の名前で、文字コードUTF8で作成したフォルダ「testgame」 に保存して下さい。 matter.min.jsthree.min.jsもコピーして保存して下さい。このフォルダだけでゲームが実行出来ます。スマートフォンでも動作します。出来上がったものは下記からも実行できます。
matter+threetest1
index.html

<!doctype html>
<html>
<head>
<meta charset="UTF-8"/>
<style type="text/css">
* {margin: 0;padding: 0;background-color:#808080;}
html, body { width:100%; height:100%; }
.view {
  position: absolute;
  left: 0;
  width: 800px;
  height: 800px; }
  .view canvas {
    width: 100%;
    height: 100%; }
</style>
</head>
<body ontouchmove="event.preventDefault()">
<script src="matter.min.js"></script>
<script src="three.min.js"></script>
<div id="js-view" class="view"></div>
<script src="main.js"></script>
</body>
</html>

main.js

(function() {
    const MAP = [
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage1
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage2
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage3
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 8, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage4
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage5
        [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage6
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage7
        [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 7, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage8
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 2, 8, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 6, 0, 2, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],//stage9
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    ];
    let brock = [];//matter.js壁1の配列
    let brockno = 0;//壁1の連番
    let enebrock = [];//three.js壁1の配列
    let brock2 = [];//matter.js壁2の配列
    let brock2no = 0;//壁2の連番
    let enebrock2 = [];//three.js壁2の配列
    let large = [];//matter.js敵大の配列
    let largeno = 0;//敵大の連番
    let enelarg = [];//three.js敵大の配列
    let lcount = [];//敵大の連番の中身がある1かない0か
    let medium = [];//matter.js敵中の配列
    let mediumno = 0;//敵中の連番
    let enemedi = [];//three.js敵中の配列
    let mcount = [];//敵中の連番の中身がある1かない0か
    let small = [];//matter.js敵小の配列
    let smallno = 0;//敵小の連番
    let enesma = [];//three.js敵小の配列
    let scount = [];//敵小の連番の中身がある1かない0か
    let remain = 25;//残機
    let stage = 0;//ステージ
    let timer = 0;//敵中が敵小に分かれてから描き替えられた回数(分かれてすぐにくっつかないため)
    let timer1 = 0;//敵大が敵中に分かれてから描き替えられた回数(分かれてすぐにくっつかないため)
    let order1 = 0;//一度の衝突判定で二回衝突と見なされない為
    let order2 = 0;//一度の衝突判定で二回衝突と見なされない為
    let order3 = 0;//一度の衝突判定で二回衝突と見なされない為
    let order4 = 0;//一度の衝突判定で二回衝突と見なされない為
    let game = false;//入力までステージ開始を待つ
    let RIGHT = false;//右に力を加える
    let LEFT = false;//左に力を加える
    let UP = false;//上に力を加える
    let DOWN = false;//下に力を加える
    let wide = 800;//ゲーム画面の大きさ
    let centerX = 0;//スマホの一つ前の入力x座標
    let centerY = 0;//スマホの一つ前の入力y座標
    let power = 0.00014;//自機の入力のmatter.jsのapplyForce

    //3D敵
    const geomedium = new THREE.SphereGeometry(17, 20, 20);
    const matemedium = new THREE.MeshPhongMaterial({color: 'deeppink'});
    //3D敵小
    const geosmall = new THREE.SphereGeometry(13, 20, 20);
    const matesmall = new THREE.MeshPhongMaterial({color: 'orange'});
    //3D敵大
    const geolarge = new THREE.SphereGeometry(21, 20, 20);
    const matelarge = new THREE.MeshPhongMaterial({color: 'green'});

    const Engine = Matter.Engine,
        World = Matter.World,
        Bodies = Matter.Bodies;
    const scene = new THREE.Scene();//three.jsシーン作成

    if (window.innerHeight < window.innerWidth) {
        wide = window.innerHeight;
    } else {
        wide = window.innerWidth;
    }

    // create engine
    let container = document.getElementById('js-engine');
    const engine = Engine.create(container, {//matter.jsエンジン設定
        render: {
            options: {
                wireframes: true,
                width: 800,
                height: 800,
            }
        }
    });
    //重力ゼロ
    engine.world.gravity.y = 0;

    //enemy移動
    function movB(body, force) {//playerの方向に敵を移動する
        if ((body.position.x - player.position.x) < 0) {
            Matter.Body.applyForce(body, {x: body.position.x,y: body.position.y}, {x: force,y: 0});
        }
        if ((body.position.x - player.position.x) > 0) {
            Matter.Body.applyForce(body, {x: body.position.x,y: body.position.y}, {x: -force,y: 0});
        }
        if ((body.position.y - player.position.y) < 0) {
            Matter.Body.applyForce(body, {x: body.position.x,y: body.position.y}, {x: 0,y: force});
        }
        if ((body.position.y - player.position.y) > 0) {
            Matter.Body.applyForce(body, {x: body.position.x,y: body.position.y}, {x: 0,y: -force});
        }
    }

    //衝突判定
    Matter.Events.on(engine, 'collisionStart', function(event) {
        order1 = 0;//一度の衝突判定で二回衝突と見なされない為
        order2 = 0;
        order3 = 0;
        order4 = 0;
        pairs = event.pairs;
        for (i = 0; i < pairs.length; i++) {
            const pair = pairs[i];
            //small->medium敵小がくっついて敵中になる
            if (pair.bodyA.label == 'small' && pair.bodyB.label == 'small' && timer > 200) {//timer:敵中が敵小に分かれてすぐくっつかないため
                World.remove(engine.world, [pair.bodyA, pair.bodyB]);//matter.js敵小消す
                scene.remove(enesma[small.indexOf(pair.bodyA)], enesma[small.indexOf(pair.bodyB)]);//three.js同じ連番の敵小消す
                scount[small.indexOf(pair.bodyA)] = 0;//同じ連番のscountの中身を0にする
                scount[small.indexOf(pair.bodyB)] = 0;
                medium[mediumno] = Bodies.circle(pair.bodyA.position.x, pair.bodyA.position.y, 17, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'medium'});
                World.add(engine.world, [medium[mediumno]]);//matter.js敵中を加える
                //3D
                enemedi[mediumno] = new THREE.Mesh(geomedium, matemedium);
                scene.add(enemedi[mediumno]);//three.js敵中を加える
                mcount[mediumno] = 1;//敵中の番号配列の中身を1存在に変える
                mediumno += 1;//連番を一つ足す
            }
            //medium->large敵中がくっついて敵大になる
            if (pair.bodyA.label == 'medium' && pair.bodyB.label == 'medium' && timer1 > 200) {
                World.remove(engine.world, [pair.bodyA, pair.bodyB]);
                scene.remove(enemedi[medium.indexOf(pair.bodyA)], enemedi[medium.indexOf(pair.bodyB)]);
                mcount[medium.indexOf(pair.bodyA)] = 0;
                mcount[medium.indexOf(pair.bodyB)] = 0;
                large[largeno] = Bodies.circle(pair.bodyA.position.x, pair.bodyA.position.y, 21, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'large'});
                World.add(engine.world, [large[largeno]]);
                //3D
                enelarg[largeno] = new THREE.Mesh(geolarge, matelarge);
                scene.add(enelarg[largeno]);
                lcount[largeno] = 1;
                largeno += 1;
            }
            //medium-brock敵中がブロックにぶつかって敵小二つになる
            if (pair.bodyA.label == 'medium' && pair.bodyB.label == 'brock' && order1 === 0) {
                bx = pair.bodyA.position.x;
                by = pair.bodyA.position.y;
                World.remove(engine.world, [pair.bodyA]);//matter.js敵中を消す
                scene.remove(enemedi[medium.indexOf(pair.bodyA)]);//three.js同じ連番の敵中消す
                mcount[medium.indexOf(pair.bodyA)] = 0;//同じ連番のmcountの中身を0にする
                small[smallno] = Bodies.circle(bx, by, 13, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'small'});
                World.add(engine.world, [small[smallno]]);//matter.js敵小1を加える
                //3D
                enesma[smallno] = new THREE.Mesh(geosmall, matesmall);
                scene.add(enesma[smallno]);//three.js敵小1を加える
                scount[smallno] = 1;//敵小の番号配列の中身を1存在に変える
                smallno += 1;//連番を一つ足す
                small[smallno] = Bodies.circle(bx, by, 13, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'small'});
                World.add(engine.world, [small[smallno]]);//matter.js敵小2を加える
                //3D
                enesma[smallno] = new THREE.Mesh(geosmall, matesmall);
                scene.add(enesma[smallno]);//three.js敵小2を加える
                scount[smallno] = 1;//敵小の番号配列の中身を1存在に変える
                smallno += 1;//連番を一つ足す
                order1 = 1;
                timer = 0;//timer:敵中が敵小に分かれたので0にセット
            }
            //brock-medium敵中がブロックにぶつかって敵小二つになる
            if (pair.bodyB.label == 'medium' && pair.bodyA.label == 'brock' && order2 === 0) {
                bx = pair.bodyB.position.x;
                by = pair.bodyB.position.y;
                World.remove(engine.world, [pair.bodyB]);
                scene.remove(enemedi[medium.indexOf(pair.bodyB)]);
                mcount[medium.indexOf(pair.bodyB)] = 0;
                small[smallno] = Bodies.circle(bx, by, 13, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'small'});
                World.add(engine.world, [small[smallno]]);
                //3D
                enesma[smallno] = new THREE.Mesh(geosmall, matesmall);
                scene.add(enesma[smallno]);
                scount[smallno] = 1;
                smallno += 1;
                small[smallno] = Bodies.circle(bx, by, 13, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'small'});
                World.add(engine.world, [small[smallno]]);
                //3D
                enesma[smallno] = new THREE.Mesh(geosmall, matesmall);
                scene.add(enesma[smallno]);
                scount[smallno] = 1;
                smallno += 1;
                order2 = 1;
                timer = 0;
            }
            //large-brock敵大がブロックにぶつかって敵中二つになる
            if (pair.bodyA.label == 'large' && pair.bodyB.label == 'brock' && order3 === 0) {
                bx = pair.bodyA.position.x;
                by = pair.bodyA.position.y;
                World.remove(engine.world, [pair.bodyA]);
                scene.remove(enelarg[large.indexOf(pair.bodyA)]);
                lcount[large.indexOf(pair.bodyA)] = 0;
                medium[mediumno] = Bodies.circle(bx, by, 17, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'medium'});
                World.add(engine.world, [medium[mediumno]]);
                //3D
                enemedi[mediumno] = new THREE.Mesh(geomedium, matemedium);
                scene.add(enemedi[mediumno]);
                mcount[mediumno] = 1;
                mediumno += 1;
                medium[mediumno] = Bodies.circle(bx, by, 17, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'medium'});
                World.add(engine.world, [medium[mediumno]]);
                //3D
                enemedi[mediumno] = new THREE.Mesh(geomedium, matemedium);
                scene.add(enemedi[mediumno]);
                mcount[mediumno] = 1;
                mediumno += 1;
                order3 = 1;
                timer1 = 0;
            }
            //brock-large敵大がブロックにぶつかって敵中二つになる
            if (pair.bodyB.label == 'large' && pair.bodyA.label == 'brock' && order4 === 0) {
                bx = pair.bodyB.position.x;
                by = pair.bodyB.position.y;
                World.remove(engine.world, [pair.bodyB]);
                scene.remove(enelarg[large.indexOf(pair.bodyB)]);
                lcount[large.indexOf(pair.bodyB)] = 0;
                medium[mediumno] = Bodies.circle(bx, by, 17, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'medium'});
                World.add(engine.world, [medium[mediumno]]);
                //3D
                enemedi[mediumno] = new THREE.Mesh(geomedium, matemedium);
                scene.add(enemedi[mediumno]);
                mcount[mediumno] = 1;
                mediumno += 1;
                medium[mediumno] = Bodies.circle(bx, by, 17, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'medium'});
                World.add(engine.world, [medium[mediumno]]);
                //3D
                enemedi[mediumno] = new THREE.Mesh(geomedium, matemedium);
                scene.add(enemedi[mediumno]);
                mcount[mediumno] = 1;
                mediumno += 1;
                order4 = 1;
                timer1 = 0;
            }
            //small-brock敵小がブロックにぶつかって消滅する
            if (pair.bodyA.label == 'small' && pair.bodyB.label == 'brock' && timer > 3) {
                World.remove(engine.world, [pair.bodyA]);//matter.js敵小を消す
                scene.remove(enesma[small.indexOf(pair.bodyA)]);//three.js同じ連番の敵小消す
                scount[small.indexOf(pair.bodyA)] = 0;//敵小の番号配列の中身を0に変える
            }
            //brock-small敵小がブロックにぶつかって消滅する
            if (pair.bodyB.label == 'small' && pair.bodyA.label == 'brock' && timer > 3) {
                World.remove(engine.world, [pair.bodyB]);
                scene.remove(enesma[small.indexOf(pair.bodyB)]);
                scount[small.indexOf(pair.bodyB)] = 0;
            }
            //player-brock自機がブロックにぶつかる
            if (pair.bodyA.label == 'player' && pair.bodyB.label == 'brock' || pair.bodyB.label == 'player' && pair.bodyA.label == 'brock') {
                remain = remain - 1;//残機が一つ減る
                if (remain === 0) {//残機0でゲームオーバー
                    stage = 0;
                    remain = 25;
                    target = document.getElementById("textid");	
                    target.innerHTML = '[Game over]';
                    refresh();
                    Initialset();
                } else {
                    target = document.getElementById("textid");//ゲームを続行
                    target.innerHTML = '[Redoing] Stage:' + (stage + 1) + ' Remain:' + remain;
                    refresh();
                    Initialset();
                }
            }
            if (scount.indexOf(1) == -1 && mcount.indexOf(1) == -1 && lcount.indexOf(1) == -1) {//敵小敵中敵大がすべて0
                stage += 1;//次のステージ
                if (stage == 9) {//9面クリアで最初に戻る
                    stage = 0;
                    remain = 25;
                    target = document.getElementById("textid");	
                    target.innerHTML = '[Game clear]';
                    refresh();
                    Initialset();
                } else {
                    remain = remain + 1;//残機を一つ増やす
                    target = document.getElementById("textid");	
                    target.innerHTML = '[Next] Stage:' + (stage + 1) + ' Remain:' + remain;//画面に文字表示
                    refresh();
                    Initialset();
                }
            }
        }
    });

    //フレーム毎実行
    Matter.Events.on(engine, 'beforeUpdate', function() {
        if (game) {//ゲーム開始フラグ
            if (UP) {
                Matter.Body.applyForce(player, {x: player.position.x,y: player.position.y}, {x: 0,y: -power});//自機上
            }
            if (RIGHT) {
                Matter.Body.applyForce(player, {x: player.position.x,y: player.position.y}, {x: power,y: 0});//自機右
            }
            if (LEFT) {
                Matter.Body.applyForce(player, {x: player.position.x,y: player.position.y}, {x: -power,y: 0});//自機左
            }
            if (DOWN) {
                Matter.Body.applyForce(player, {x: player.position.x,y: player.position.y}, {x: 0,y: power});//自機下
            }
            for (i = 0; i < medium.length; i++) {
                movB(medium[i], 0.0001);//matter.js敵中移動
                enemedi[i].position.y = 17;//three.js敵中表示
                enemedi[i].position.z = medium[i].position.y;
                enemedi[i].position.x = medium[i].position.x;
                enemedi[i].rotation.y = -medium[i].angle;
            }
            for (i = 0; i < small.length; i++) {
                movB(small[i], 0.00002);//matter.js敵小移動
                enesma[i].position.y = 13;//three.js敵小表示
                enesma[i].position.z = small[i].position.y;
                enesma[i].position.x = small[i].position.x;
                enesma[i].rotation.y = -small[i].angle;
            }
            for (i = 0; i < large.length; i++) {
                movB(large[i], 0.0001);//matter.js敵大移動
                enelarg[i].position.y = 21;//three.js敵大表示
                enelarg[i].position.z = large[i].position.y;
                enelarg[i].position.x = large[i].position.x;
                enelarg[i].rotation.y = -large[i].angle;
            }
            machine.position.y = 17;//three.js自機表示
            machine.position.z = player.position.y;
            machine.position.x = player.position.x;
            machine.rotation.y = -player.angle;
            timer += 1;
            timer1 += 1;
        }
        renderer.render(scene, camera);
    });

    //リフレッシュ
    function refresh() {
       World.remove(engine.world, [player]);
       for (i = 0; i < medium.length; i++) {
                   World.remove(engine.world, [medium[i]]);//matter.js敵中削除
                   scene.remove(enemedi[i]);//three.js敵中削除
       }
       for (i = 0; i < small.length; i++) {
                   World.remove(engine.world, [small[i]]);//matter.js敵小削除
                   scene.remove(enesma[i]);//three.js敵小削除
       }
       for (i = 0; i < large.length; i++) {
                   World.remove(engine.world, [large[i]]);
                   scene.remove(enelarg[i]);
       }
       for (i = 0; i < brock.length; i++) {
                   World.remove(engine.world, [brock[i]]);
                   scene.remove(enebrock[i]);
       }
       for (i = 0; i < brock2.length; i++) {
                   World.remove(engine.world, [brock2[i]]);
                   scene.remove(enebrock2[i]);
       }
       brock = [];
       brockno = 0;
       enebrock = [];
       brock2 = [];
       brock2no = 0;
       enebrock2 = [];
       large = [];
       largeno = 0;
       enelarg = [];
       lcount = [];
       medium = [];
       mediumno = 0;
       enemedi = [];
       mcount = [];
       small = [];
       smallno = 0;
       enesma = [];
       scount = [];
       timer = 0;
       timer1 = 0;
       order1 = 0;
       order2 = 0;
       order3 = 0;
       order4 = 0;
       game = false;
    }

    //3D自機
    geometry = new THREE.SphereGeometry(17, 20, 20);
    material = new THREE.MeshPhongMaterial({color: 'steelblue'});
    const machine = new THREE.Mesh(geometry, material);
    scene.add(machine);
    //3D床
    geometry = new THREE.PlaneGeometry(800, 800);
    material = new THREE.MeshBasicMaterial({color: 'burlywood',side: THREE.BackSide});
    const plane = new THREE.Mesh(geometry, material);
    plane.position.set(400, 0, 400);
    plane.rotation.x = 90 * Math.PI / 180;
    scene.add(plane);

    //キー入力
    document.onkeydown = function(e) {
        e.preventDefault();
        if (e.key == 'ArrowLeft') {LEFT = true;}
        if (e.key == 'ArrowRight') {RIGHT = true;}
        if (e.key == 'ArrowUp') {UP = true;}
        if (e.key == 'ArrowDown') {DOWN = true;}
    };
    document.onkeyup = function(e) {
        e.preventDefault();
        if (!game) {game = true;power = 0.00014}//ステージ開始PCではapplyForceを強め
        if (e.key == 'ArrowLeft') {LEFT = false;}
        if (e.key == 'ArrowRight') {RIGHT = false;}
        if (e.key == 'ArrowUp') {UP = false;}
        if (e.key == 'ArrowDown') {DOWN = false;}
    };
    //スマホ入力
    window.addEventListener('touchstart', (e) => {
        e.preventDefault();
        if (!game) {game = true;power = 0.00013}//ステージ開始スマホではapplyForceを弱め
        ex = e.changedTouches[0].pageX;ey = e.changedTouches[0].pageY;
        centerX = ex;
        centerY = ey;
        RIGHT = false;LEFT = false;DOWN = false;UP = false;
    },{passive: false});
    window.addEventListener('touchmove', (e) => {//直前のタッチムーブの座標を起点としてどちらの方向かを調べる
        e.preventDefault();
        RIGHT = false;LEFT = false;DOWN = false;UP = false;
        ex = e.changedTouches[0].pageX;ey = e.changedTouches[0].pageY;
        x = ex - centerX;
        y = ey - centerY;
        centerX = ex;
        centerY = ey;
        if(Math.abs(x) > Math.abs(y)){
            if(x < 0){LEFT = true;}else{RIGHT = true;}
        }else{
            if(y < 0){UP = true;}else{DOWN = true;}
        }
    },{passive: false});
    window.addEventListener('touchend', function(e) {
        e.preventDefault();
        RIGHT = false;LEFT = false;DOWN = false;UP = false;
    },{passive: false});

    const fontsize = Math.round(window.innerHeight / 5);//画面に文字表示
    const title = document.createElement( 'div' );
    document.body.appendChild( title );
    const info = document.createElement( 'div' );
    info.id = "textid";
    info.style.position = 'absolute';
    info.style.left = '10%'; 
    info.style.top = '0%';
    info.style.width = '80%';
    info.style.color = "yellow";
    info.style.fontSize = String(fontsize) + "%";
    info.style.backgroundColor = 'transparent';
    info.innerHTML = '[Please tap] Stage:' + (stage + 1) + ' Remain:' + remain;
    title.appendChild( info );

    //マップ表示
    function Initialset() {
        for (i = stage * 20; i < 20 + stage * 20; i++) {
            for (j = 0; j < 20; j++) {
                //壁1
                if (MAP[i][j] == 1) {
                    brock[brockno] = Bodies.polygon((i - stage * 20) * 40 + 20, j * 40 + 20, 4, 27, {label: 'brock',isStatic: true});
                    World.add(engine.world, [brock[brockno]]);
                    //3D
                    enebrock[brockno] = new THREE.Mesh(new THREE.BoxBufferGeometry(40, 20, 40), [
                        new THREE.MeshBasicMaterial({ color: 'darkgoldenrod' }),
                        new THREE.MeshBasicMaterial({ color: 'darkorange' }),
                        new THREE.MeshBasicMaterial({ color: 'sienna' }), ,
                        new THREE.MeshBasicMaterial({ color: 'brown' }),
                        new THREE.MeshBasicMaterial({ color: 'darkred' })
                    ]);
                    scene.add(enebrock[brockno]);
                    enebrock[brockno].position.y = 10;
                    enebrock[brockno].position.z = brock[brockno].position.y;
                    enebrock[brockno].position.x = brock[brockno].position.x;
                    enebrock[brockno].rotation.y = brock[brockno].angle;
                    brockno += 1;
                }
                //壁2
                if (MAP[i][j] == 2) {
                    brock2[brock2no] = Bodies.polygon((i - stage * 20) * 40 + 20, j * 40 + 20, 4, 27, {label: 'brock2',isStatic: true});
                    World.add(engine.world, [brock2[brock2no]]);
                    //3D
                    enebrock2[brock2no] = new THREE.Mesh(new THREE.BoxBufferGeometry(40, 20, 40), [
                        new THREE.MeshBasicMaterial({ color: 'darkolivegreen' }),
                        new THREE.MeshBasicMaterial({ color: 'olive' }),
                        new THREE.MeshBasicMaterial({ color: 'limegreen' }), ,
                        new THREE.MeshBasicMaterial({ color: 'darkolivegreen' }),
                        new THREE.MeshBasicMaterial({ color: 'olive' })
                    ]);
                    scene.add(enebrock2[brock2no]);
                    enebrock2[brock2no].position.y = 10;
                    enebrock2[brock2no].position.z = brock2[brock2no].position.y;
                    enebrock2[brock2no].position.x = brock2[brock2no].position.x;
                    enebrock2[brock2no].rotation.y = brock2[brock2no].angle;
                    brock2no += 1;
                }
                //自機
                if (MAP[i][j] == 3) {
                    player = Bodies.circle((i - stage * 20) * 40 + 20, j * 40 + 20, 17, {density: 0.0004,frictionAir: 0.008,restitution: 1,friction: 0,label: 'player'});
                    World.add(engine.world, [player]);
                    machine.position.y = 17;
                    machine.position.z = player.position.y;
                    machine.position.x = player.position.x;
                }
                //敵
                if (MAP[i][j] == 6) {
                    medium[mediumno] = Bodies.circle((i - stage * 20) * 40 + 20, j * 40 + 20, 17, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'medium'});
                    World.add(engine.world, [medium[mediumno]]);
                    //3D
                    enemedi[mediumno] = new THREE.Mesh(geomedium, matemedium);
                    scene.add(enemedi[mediumno]);
                    enemedi[mediumno].position.y = 17;
                    enemedi[mediumno].position.z = medium[mediumno].position.y;
                    enemedi[mediumno].position.x = medium[mediumno].position.x;
                    enemedi[mediumno].rotation.y = medium[mediumno].angle;
                    mcount[mediumno] = 1;
                    mediumno += 1;
                }
                //敵小
                if (MAP[i][j] == 7) {
                    small[smallno] = Bodies.circle((i - stage * 20) * 40 + 20, j * 40 + 20, 13, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'small'});
                    World.add(engine.world, [small[smallno]]);
                    //3D
                    enesma[smallno] = new THREE.Mesh(geosmall, matesmall);
                    scene.add(enesma[smallno]);
                    enesma[smallno].position.y = 13;
                    enesma[smallno].position.z = small[smallno].position.y;
                    enesma[smallno].position.x = small[smallno].position.x;
                    enesma[smallno].rotation.y = small[smallno].angle;
                    scount[smallno] = 1;
                    smallno += 1;
                }
                //敵大
                if (MAP[i][j] == 8) {
                    large[largeno] = Bodies.circle((i - stage * 20) * 40 + 20, j * 40 + 20, 21, {density: 0.0004,frictionAir: 0.001,restitution: 1,friction: 0,label: 'large'});
                    World.add(engine.world, [large[largeno]]);
                    //3D
                    enelarg[largeno] = new THREE.Mesh(geolarge, matelarge);
                    scene.add(enelarg[largeno]);
                    enelarg[largeno].position.y = 21;
                    enelarg[largeno].position.z = large[largeno].position.y;
                    enelarg[largeno].position.x = large[largeno].position.x;
                    enelarg[largeno].rotation.y = large[largeno].angle;
                    lcount[largeno] = 1;
                    largeno += 1;
                }
            }
        }
    }
    Initialset(0);

    //light
    const light = new THREE.PointLight(0xFFFFFF, 1.7, 3000);
    light.position.set(400, 100, 400);
    scene.add(light);
    // camera
    const camera = new THREE.PerspectiveCamera(45, 1, 1, 30000);
    camera.position.set(400, 980, 400);
    camera.rotation.x = - 90 * Math.PI / 180;
    camera.rotation.y = Math.PI * 2;
    //rendering
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(wide,wide);
    renderer.setClearColor(0x000000, 1);
    renderer.shadowMapEnabled = true;
    document.getElementById("js-view").appendChild(renderer.domElement);

    //run the engine
    Engine.run(engine);
})();

③Three.jsとMatter.jsのサンプルゲーム2
新規作成で新しいフォルダを作り、「testgame」など適当に名前を付けて下さい。メモ帳を開き、下記の2つをコピーして、「index.html」、「main.js」の名前で、文字コードUTF8で作成したフォルダ「testgame」 に保存して下さい。すでに記載したダウンロード先より matter.min.jsthree.min.jsもコピーして保存して下さい。このフォルダだけでゲームが実行出来ます。
※ この画像2点「pad.png」「pad2.png」をマウスの右クリックでダウンロードして同じフォルダに保存すれば、スマートフォンでも動作します。

出来上がったものは下記からも実行できます。
matter+threetest2
index.html

<!doctype html>
<html>
<head>
<style>
.game {
  width: 360px;
  height: 640px;}
.engine {
  position: absolute;
  left: 0;
  width: 377px;
  height: 221px; }
  .engine canvas {
    width: 100%;
    height: 100%; }
.view {
  position: absolute;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%; }
  .view canvas {
    width: 100% !important;
    height: 100% !important; }
.guideimg {
  position: absolute;
  background-image: url('pad.png');
  background-size: 100% 100%;}
  .guideimg canvas {
    width: 100%;
    height: 100%;}
.guideimg2 {
  position: absolute;
  background-image: url('pad2.png');
  background-size: 100% 100%;}
  .guideimg2 canvas {
    width: 100%;
    height: 100%;}
</style>
<script src="matter.min.js"></script>
<script src="three.min.js"></script>
</head>
<body ontouchmove="event.preventDefault()">
<div id="js-view" class="view"></div>
<div id="js-engine" class="engine"></div>
<div id="js-guideimg" class="guideimg"></div>
<div id="js-guideimg2" class="guideimg2"></div>
<script src="main.js"></script>
</body>
</html>

main.js

(function () {
    // 配列でマップデータを用意する
    let MAP = [];
    let brock = [];//matter.js壁の配列
    let brockno = 0;//壁の連番
    let brock3D = [];//three.js壁の配列
    let right = false;
    let left = false;
    let game = false;//ゲームスタート
    let gameok = true;//ゲーム準備OK
    let speed = 0;//自機スピード
    const mapSize = 21;
    let ex = 0;
    let ey = 0;
    let ex0 = 0;//敵が移動方向を決めるタイミングを遅らせる
    let ey0 = 0;
    let ex1 = 0;
    let ey1 = 0;
    let ex2 = 0;
    let ey2 = 0;
    let ex3 = 0;
    let ey3 = 0;
    let ex4 = 0;
    let ey4 = 0;
    let eforcex = 0;//敵の移動速度
    let eforcey = 0;
    let oldex = 0;//敵の1つ前の位置
    let oldey = 0;
    let fire = false;//弾発射
    let fifrag = true;//発射準備OK
    let hit = false;//弾命中
    let countgem = 0;//宝物を取った数
    let vistime = 6000;//宝物を取った後迷路表示タイム
    let damage = false;//やられた後自機をぐるぐる回す

    //matter.js用設定
    const Engine = Matter.Engine,
        Render = Matter.Render,
        World = Matter.World,
        Bodies = Matter.Bodies;
    container = document.getElementById('js-engine');
    const engine = Engine.create(container, { render: { options: { wireframes: false, width: 420, height: 420 } } });
    //matter.js重力値
    engine.world.gravity.y = 0;

    let player = Matter.Bodies.polygon(0, 0, 8, 8, { restitution: 0.1, friction: 0, frictionAir: 0.2, label: 'player', render: { fillStyle: 'skyblue' } });
    let enemy = Matter.Bodies.circle(420, 420, 6, { friction: 0, frictionAir: 0.2, label: 'enemy', collisionFilter: { group: -1 }, render: { fillStyle: 'gold' } });
    let gem1 = Matter.Bodies.rectangle(10, -30, 5, 5, { isStatic: true, label: 'gem1', collisionFilter: { group: -1 }, render: { fillStyle: 'yellow' } });//enemyとぶつからない
    let gem2 = Matter.Bodies.rectangle(20, -30, 5, 5, { isStatic: true, label: 'gem2', collisionFilter: { group: -1 }, render: { fillStyle: 'yellow' } });
    let gem3 = Matter.Bodies.rectangle(30, -30, 5, 5, { isStatic: true, label: 'gem3', collisionFilter: { group: -1 }, render: { fillStyle: 'yellow' } });
    let gem4 = Matter.Bodies.rectangle(40, -30, 5, 5, { isStatic: true, label: 'gem4', collisionFilter: { group: -1 }, render: { fillStyle: 'yellow' } });
    let bullet = Matter.Bodies.circle(50, -20, 1, { frictionAir: 0, label: 'bullet', render: { fillStyle: 'white' } });
    World.add(engine.world, [player, enemy, bullet]);

    //three.js用設定
    const scene = new THREE.Scene();// シーンを作成
    const renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0x000000, 1);
    renderer.setSize(window.innerWidth, window.innerHeight);//画面いっぱい
    renderer.shadowMapEnabled = false;
    document.body.appendChild(renderer.domElement);
    // light
    var light = new THREE.PointLight(0xFFFFFF, 1.0, 80, 1.0);//懐中電灯の感じ遠くは暗い
    light.position.set(0, 10, 0);
    scene.add(light);
    var ambient = new THREE.AmbientLight(0xFFFFFF, 0.3);//環境光源
    scene.add(ambient);
    // カメラを作成
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1200);
    camera.position.y = 11;//カメラの地面からの高さ(自機の高さ10で少し下向き)

    let geometry = new THREE.PlaneGeometry(20 * 21, 20 * 21);//床のジオメトリ
    let material = new THREE.MeshLambertMaterial({ color: 'saddlebrown', side: THREE.BackSide });//床のマテリアル(裏側に色を付けなければ透明になる)
    const floor = new THREE.Mesh(geometry, material);
    floor.position.set(10 * 21, 0, 10 * 21);//MAPの真ん中
    floor.rotation.x = Math.atan2(1, 0);//床の向きを合わせる
    scene.add(floor);

    geometry = new THREE.PlaneGeometry(20 * 21, 20 * 21);//天井のジオメトリ
    material = new THREE.MeshLambertMaterial({ color: 'gray' });//天井のマテリアル
    const roof = new THREE.Mesh(geometry, material);
    roof.position.set(10 * 21, 20, 10 * 21);
    roof.rotation.x = Math.atan2(1, 0);
    scene.add(roof);

    //three.js敵
    const enemy3D = Monster();//ファンクションで定義
    scene.add(enemy3D);

    //three.js自機
    geometry = new THREE.CylinderGeometry(12, 12, 3, 6);//自機を大きくカメラは自機の内側に設置camera.lookAt(machine.position)自機は透過する
    material = new THREE.MeshBasicMaterial({ color: 'blue' });
    const machine = new THREE.Mesh(geometry, material);
    machine.position.y = 10;
    scene.add(machine);

    //three.js弾丸
    geometry = new THREE.SphereGeometry(1, 8, 8);
    material = new THREE.MeshPhongMaterial({ color: 'gold' });
    const sphere = new THREE.Mesh(geometry, material);
    sphere.position.y = 4;//弾はちょっと低め
    scene.add(sphere);

    //宝物1
    gemD1 = new THREE.Mesh(new THREE.BoxBufferGeometry(5, 5, 5), [
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' }), ,//底のマテリアルは要らない
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' })
    ]);
    //宝物2
    gemD2 = new THREE.Mesh(new THREE.BoxBufferGeometry(5, 5, 5), [
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' }), ,
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' })
    ]);
    //宝物3
    gemD3 = new THREE.Mesh(new THREE.BoxBufferGeometry(5, 5, 5), [
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' }), ,
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' })
    ]);
    //宝物4
    gemD4 = new THREE.Mesh(new THREE.BoxBufferGeometry(5, 5, 5), [
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' }), ,
        new THREE.MeshPhongMaterial({ color: 'gold' }),
        new THREE.MeshPhongMaterial({ color: 'gold' })
    ]);

    //転送台
    geometry = new THREE.CylinderGeometry(6, 6, 16, 20);
    material = new THREE.MeshPhongMaterial({
        color: 0x00ffff,
        transparent: true,//半透明にする
        opacity: 0.5
    });
    const cube = new THREE.Mesh(geometry, material);
    cube.position.set(30, 8, 30);
    scene.add(cube);

    //衝突チェック
    Matter.Events.on(engine, 'collisionStart', function (event) {
        pairs = event.pairs;
        for (i = 0; i < pairs.length; i++) {
            var pair = pairs[i];
            if (pair.bodyA.label == 'bullet' && pair.bodyB.label == 'enemy' || pair.bodyA.label == 'enemy' && pair.bodyB.label == 'bullet') {
                hit = true;//弾と敵が当ったらフラグを立てる
            }
            if (pair.bodyA.label == 'bullet' || pair.bodyB.label == 'bullet') {//弾が何かにぶつかったら速度をゼロ画面外に出す
                Matter.Body.setPosition(bullet,{x:50,y: -20});Matter.Body.setVelocity(bullet,{x:0, y:0});
            }
            if (pair.bodyA.label == 'player' && pair.bodyB.label == 'enemy' || pair.bodyA.label == 'enemy' && pair.bodyB.label == 'player') {//自機と敵ぶつかる
                info.innerHTML = 'GAME OVER';gameok = false;damage = true;
                window.setTimeout(function() {info.innerHTML = ' ';gameok = true;damage = false;vistime = 6000}, 2000);
                generateMaze();
                Initialset();
                setgem();
                refresh();
                break;
            }
            if (pair.bodyA.label == 'player' && pair.bodyB.label == 'gem1' || pair.bodyA.label == 'gem1' && pair.bodyB.label == 'player') {//宝物をゲット
                World.remove(engine.world, [gem1]);countgem++;//取った宝物の数
                scene.remove(gemD1);
                for (i = 0; i < brock.length; i += 1) { brock[i].render.visible = true }//迷路を表示する
                window.setTimeout(function () { for (i = 0; i < brock.length; i += 1) { brock[i].render.visible = false } }, vistime);//vistime後迷路を隠す
                break;
            }
            if (pair.bodyA.label == 'player' && pair.bodyB.label == 'gem2' || pair.bodyA.label == 'gem2' && pair.bodyB.label == 'player') {//宝物をゲット
                World.remove(engine.world, [gem2]);countgem++;
                scene.remove(gemD2);
                for (i = 0; i < brock.length; i += 1) { brock[i].render.visible = true }
                window.setTimeout(function () { for (i = 0; i < brock.length; i += 1) { brock[i].render.visible = false } }, vistime);
                break;
            }
            if (pair.bodyA.label == 'player' && pair.bodyB.label == 'gem3' || pair.bodyA.label == 'gem3' && pair.bodyB.label == 'player') {//宝物をゲット
                World.remove(engine.world, [gem3]);countgem++;
                scene.remove(gemD3);
                for (i = 0; i < brock.length; i += 1) { brock[i].render.visible = true }
                window.setTimeout(function () { for (i = 0; i < brock.length; i += 1) { brock[i].render.visible = false } }, vistime);
                break;
            }
            if (pair.bodyA.label == 'player' && pair.bodyB.label == 'gem4' || pair.bodyA.label == 'gem4' && pair.bodyB.label == 'player') {//宝物をゲット
                World.remove(engine.world, [gem4]);countgem++;
                scene.remove(gemD4);
                for (i = 0; i < brock.length; i += 1) { brock[i].render.visible = true }
                window.setTimeout(function () { for (i = 0; i < brock.length; i += 1) { brock[i].render.visible = false } }, vistime);
                break;
            }
        }
    });

    function shuffle(inputArray = []) {//Fisher–Yates shuffle
        for (i = inputArray.length - 1; i >= 0; i--) {
            let randomIndex = Math.floor(Math.random() * (i + 1));
            let itemAtIndex = inputArray[randomIndex];
            inputArray[randomIndex] = inputArray[i];
            inputArray[i] = itemAtIndex;
        }
        return inputArray;
    }
    // 壁延ばし法による迷路生成
    function generateMaze() {
        var wallPoints = [],
            point,
            // ゴール決定用
            min = Math.floor((mapSize + 1) * 3 / 4),
            max = mapSize - 1,
            pointsOnBottomRight = [],
            deadEndPoints = [],
            extendWall = (function () {
                var DIRECTION = [
                    [0, 1],
                    [0, -1],
                    [1, 0],
                    [-1, 0]
                ];
                return function extendWall(p) {
                    var indexes = shuffle([0, 1, 2, 3]),
                        dx, dy,
                        i;
                    for (i = 0; i < 4; i += 1) {
                        dx = DIRECTION[indexes[i]][0];
                        dy = DIRECTION[indexes[i]][1];
                        if (p[1] + dx >= 0 && p[1] + dx < mapSize && p[0] + dy >= 0 && p[0] + dy < mapSize) {
                            if (MAP[p[0] + dy * 2][p[1] + dx * 2] === 0) {
                                MAP[p[0] + dy][p[1] + dx] = 1;
                                MAP[p[0] + dy * 2][p[1] + dx * 2] = 1;
                                extendWall([p[0] + dy * 2, p[1] + dx * 2]);
                            }
                        }
                    }
                    if (wallPoints.length) {
                        point = wallPoints.pop();
                        extendWall(point);
                    }
                };
            }()),
            i, j;
        function isDeadEnd(p) {
            if (MAP[p[0]][p[1]] !== 0) {
                return false;
            }
            var countWall = 0,
                surroundingPoints = [
                    [p[0] - 1, p[1]], // 上
                    [p[0], p[1] + 1], // 右
                    [p[0] + 1, p[1]], // 下
                    [p[0], p[1] - 1] // 左];
                ];
            surroundingPoints.forEach(function (sp) {
                if (MAP[sp[0]][sp[1]] === 1) {
                    countWall += 1;
                }
            });
            return (countWall === 3);
        }
        do {
            // 迷路の初期化
            for (i = 0; i < mapSize; i += 1) {
                MAP[i] = [];
            }
            for (i = 0; i < mapSize; i += 1) {
                MAP[0][i] = 1; // 上
                MAP[mapSize - 1][i] = 1; // 下
                MAP[i][0] = 1; // 左
                MAP[i][mapSize - 1] = 1; // 右
                if (i % 2 === 0 && i !== 0 && i !== mapSize - 1) {
                    wallPoints.push([0, i]);
                    wallPoints.push([mapSize - 1, i]);
                    wallPoints.push([i, 0]);
                    wallPoints.push([i, mapSize - 1]);
                }
            }
            for (i = 1; i < mapSize - 1; i += 1) {
                for (j = 1; j < mapSize - 1; j += 1) {
                    MAP[i][j] = 0;
                }
            }
            shuffle(wallPoints);
            point = wallPoints.pop();
            extendWall(point);
            /*
             * ゴール決定
             */
            // 右下にある点を配列に追加する
            for (i = min; i < max; i += 1) {
                for (j = min; j < max; j += 1) {
                    pointsOnBottomRight.push([i, j]);
                }
            }
            // 行き止まりの点のみ残す
            deadEndPoints = pointsOnBottomRight.filter(isDeadEnd);
        } while (!deadEndPoints.length);
        var goal = shuffle(deadEndPoints).pop();
        var collision = MAP.map(function (cols) {
            return cols.map(function (chip) {
                return chip === 1 ? 1 : 0;
            });
        });
        collision[goal[0]][goal[1]] = 1;
    }

    //フレーム毎実行
    Matter.Events.on(engine, 'beforeUpdate', function () {//Matter.Events module
        if (game) {
            if (right) { Matter.Body.setAngularVelocity(player, Math.PI / 64) };//右回転
            if (left) { Matter.Body.setAngularVelocity(player, -Math.PI / 64) };//左回転
            Matter.Body.applyForce(player, { x: player.position.x, y: player.position.y }, { x: Math.cos(player.angle) * speed, y: Math.sin(player.angle) * speed });//進行方向に移動
            if (fire) {//自機の前向きに発射
                Matter.Body.setPosition(bullet,{x:player.position.x + Math.cos(player.angle) * 8,y:player.position.y + Math.sin(player.angle) * 8});
                Matter.Body.setVelocity(bullet,{x:0, y:0});
                Matter.Body.applyForce(bullet,{x:bullet.position.x,y:bullet.position.y}, {x: Math.cos(player.angle) * 0.00003,y: Math.sin(player.angle) * 0.00003});
                fire = false;
            }
            Saurus();//敵移動方向決定ルーチン
            Matter.Body.applyForce(enemy, { x: enemy.position.x, y: enemy.position.y }, { x: eforcex, y: eforcey });//敵移動
            if (player.position.x < 38 && player.position.y < 38 && countgem == 4) {//宝物が四つで転送台に戻った
                info.innerHTML = 'CLEAR';gameok = false;
                window.setTimeout(function() {info.innerHTML = ' ';gameok = true}, 2000);
                if (vistime > 3000) {vistime = vistime - 200};//宝物取った後迷路表示少し減らす
                generateMaze();
                Initialset();
                setgem();
                refresh();
            }
        }
        if (damage) { Matter.Body.setAngularVelocity(player, Math.PI / 32) }//自機と敵ぶつかったら自機回転アニメーション
        enemy3D.position.x = enemy.position.x;//matter.jsの敵表示をthree.jsの表示にする
        enemy3D.position.z = enemy.position.y;
        enemy3D.rotation.y = enemy.angle;
        machine.position.x = player.position.x;//matter.jsの自機表示をthree.jsの表示にする
        machine.position.z = player.position.y;
        machine.rotation.y = player.angle;
        sphere.position.z = bullet.position.y;//matter.jsの弾表示をthree.jsの表示にする
        sphere.position.x = bullet.position.x;
        light.position.x = machine.position.x - Math.cos(player.angle) * 6;//PointLightを自機の後方に配置
        light.position.z = machine.position.z - Math.sin(player.angle) * 6;
        light.lookAt(machine.position);//PointLightを自機の前に向ける
        camera.position.x = machine.position.x - Math.cos(player.angle) * 6;//カメラを自機の後方に配置
        camera.position.z = machine.position.z - Math.sin(player.angle) * 6;
        camera.lookAt(machine.position);//カメラを自機の前に向ける
        renderer.render(scene, camera);//レンダリング
    });
    //ゲームスタート
    generateMaze();
    Initialset();
    setgem();
    refresh();

    // ザウルス
    function Saurus() {//敵移動方向決定ルーチン
        ex = ex4;
        ey = ey4;
        ex4 = ex3;
        ey4 = ey3;
        ex3 = ex2;
        ey3 = ey2;
        ex2 = ex1;
        ey2 = ey1;
        ex1 = ex0;//移動方向を決めるタイミングを遅らせる
        ey1 = ey0;
        ex0 = Math.round((enemy.position.x + 10) / 20) - 1;//配列MAPの値0か1
        ey0 = Math.round((enemy.position.y + 10) / 20) - 1;
        if (Math.abs(enemy.velocity.x) < 0.0000000001 && Math.abs(enemy.velocity.y) < 0.0000000001) {oldex = 0;oldey = 0}//動けなくなれば移動方向探す
        if (ex != oldex || ey != oldey) {//移動中のMAP地点が変わった
            //弾丸当り
            if (hit) {//自機から離れる方向に移動
                if (eforcey == 0) { if (enemy.position.x - player.position.x > 0) {eforcex = 0.00002} else {eforcex = -0.00002}}
                if (eforcex == 0) { if (enemy.position.y - player.position.y > 0) {eforcey = 0.00002} else {eforcey = -0.00002}}
                oldex = ex; oldey = ey;hit = false;
                return
            }
            //突当り
            if (MAP[ex][ey - 1] == 1 && MAP[ex + 1][ey] == 0 && MAP[ex][ey + 1] == 1 && MAP[ex - 1][ey] == 1) { eforcex = 0.00002; eforcey = 0 }
            if (MAP[ex][ey - 1] == 1 && MAP[ex + 1][ey] == 1 && MAP[ex][ey + 1] == 0 && MAP[ex - 1][ey] == 1) { eforcex = 0; eforcey = 0.00002 }
            if (MAP[ex][ey - 1] == 1 && MAP[ex + 1][ey] == 1 && MAP[ex][ey + 1] == 1 && MAP[ex - 1][ey] == 0) { eforcex = -0.00002; eforcey = 0 }
            if (MAP[ex][ey - 1] == 0 && MAP[ex + 1][ey] == 1 && MAP[ex][ey + 1] == 1 && MAP[ex - 1][ey] == 1) { eforcex = 0; eforcey = -0.00002 }
            //二股
            if (MAP[ex][ey - 1] == 1 && MAP[ex + 1][ey] == 0 && MAP[ex][ey + 1] == 0 && MAP[ex - 1][ey] == 1) {//右下空き
                if (eforcex == 0) { eforcex = 0.00002; eforcey = 0 } else { eforcex = 0; eforcey = 0.00002 }//下からでは右もしくは下
            }
            if (MAP[ex][ey - 1] == 1 && MAP[ex + 1][ey] == 1 && MAP[ex][ey + 1] == 0 && MAP[ex - 1][ey] == 0) {//下左空き
                if (eforcex == 0) { eforcex = -0.00002; eforcey = 0 } else { eforcex = 0; eforcey = 0.00002 }//下からでは左もしくは下
            }
            if (MAP[ex][ey - 1] == 0 && MAP[ex + 1][ey] == 1 && MAP[ex][ey + 1] == 1 && MAP[ex - 1][ey] == 0) {//上左空き
                if (eforcex == 0) { eforcex = -0.00002; eforcey = 0 } else { eforcex = 0; eforcey = -0.00002 }//上からでは左もしくは上
            }
            if (MAP[ex][ey - 1] == 0 && MAP[ex + 1][ey] == 0 && MAP[ex][ey + 1] == 1 && MAP[ex - 1][ey] == 1) {//上右空き
                if (eforcex == 0) { eforcex = 0.00002; eforcey = 0 } else { eforcex = 0; eforcey = -0.00002 }//上からでは右もしくは上
            }
            //三股
            if (MAP[ex][ey - 1] == 1 && MAP[ex + 1][ey] == 0 && MAP[ex][ey + 1] == 0 && MAP[ex - 1][ey] == 0) {//右下左が空き
                if (eforcex == 0) {//下から来たので右か左
                    if (Math.floor(Math.random() * 2) == 0) { eforcex = 0.00002; eforcey = 0 } else { eforcex = -0.00002; eforcey = 0 }
                } else {//右か左から来たのでそのまま行くか下
                    if (Math.floor(Math.random() * 2) == 0) { eforcex = 0; eforcey = 0.00002 }
                }
            }
            if (MAP[ex][ey - 1] == 0 && MAP[ex + 1][ey] == 1 && MAP[ex][ey + 1] == 0 && MAP[ex - 1][ey] == 0) {//上下左が空き
                if (eforcey == 0) {//左から来たので上か下
                    if (Math.floor(Math.random() * 2) == 0) { eforcex = 0; eforcey = 0.00002 } else { eforcex = 0; eforcey = -0.00002 }
                } else {//上か下から来たのでそのまま行くか左
                    if (Math.floor(Math.random() * 2) == 0) { eforcex = -0.00002; eforcey = 0 }
                }
            }
            if (MAP[ex][ey - 1] == 0 && MAP[ex + 1][ey] == 0 && MAP[ex][ey + 1] == 1 && MAP[ex - 1][ey] == 0) {//上右左が空き??????
                if (eforcex == 0) {//上から来たので右か左
                    if (Math.floor(Math.random() * 2) == 0) { eforcex = 0.00002; eforcey = 0 } else { eforcex = -0.00002; eforcey = 0 }
                } else {//右か左から来たのでそのまま行くか上
                    if (Math.floor(Math.random() * 2) == 0) { eforcex = 0; eforcey = -0.00002 }
                }
            }
            if (MAP[ex][ey - 1] == 0 && MAP[ex + 1][ey] == 0 && MAP[ex][ey + 1] == 0 && MAP[ex - 1][ey] == 1) {//上右下が空き
                if (eforcey == 0) {//右から来たので上か下
                    if (Math.floor(Math.random() * 2) == 0) { eforcex = 0; eforcey = 0.00002 } else { eforcex = 0; eforcey = -0.00002 }
                } else {//上か下から来たのでそのまま行くか右
                    if (Math.floor(Math.random() * 2) == 0) { eforcex = 0.00002; eforcey = 0 }
                }
            }
            //四俣
            if (MAP[ex][ey - 1] == 0 && MAP[ex + 1][ey] == 0 && MAP[ex][ey + 1] == 0 && MAP[ex - 1][ey] == 0) {//上右下左が空き
                const move = Math.floor(Math.random() * 3);
                if (eforcex != 0) {//右か左から来たので上か下かそのまま行く
                    if (move == 0) { eforcex = 0; eforcey = 0.00002 }
                    if (move == 1) { eforcex = 0; eforcey = -0.00002 }
                    oldex = ex; oldey = ey; return
                }
                if (eforcey != 0) {//上か下から来たので右か左かそのまま行く
                    if (move == 0) { eforcex = 0.00002; eforcey = 0 }
                    if (move == 1) { eforcex = -0.00002; eforcey = 0 }
                }
            }
            oldex = ex; oldey = ey;
        }
    }

    //マップ表示
    function Initialset() {
        for (i = 0; i < brock.length; i++) {World.remove(engine.world, brock[i])}
        for (i = 0; i < brock3D.length; i++) {scene.remove(brock3D[i])}
        brockno = 0;//壁の連番の初期化
        for (i = 0; i < mapSize; i += 1) {
            for (j = 0; j < mapSize; j += 1) {
                //壁
                if (MAP[i][j] == 1) {
                    //matter.js当たり判定用でvisible: false見えない
                    brock[brockno] = Bodies.rectangle(i * 20 + 10, j * 20 + 10, 20, 20, { friction: 0, restitution: 0, isStatic: true, render: { visible: false } });
                    World.add(engine.world, [brock[brockno]]);
                    //3D壁
                    brock3D[brockno] = new THREE.Mesh(new THREE.BoxBufferGeometry(20, 20, 20), [
                        new THREE.MeshLambertMaterial({ color: 'powderblue' }),
                        new THREE.MeshLambertMaterial({ color: 'powderblue' }), , ,//底と天井はナシ
                        new THREE.MeshLambertMaterial({ color: 'plum' }),
                        new THREE.MeshLambertMaterial({ color: 'plum' })
                    ]);
                    brock3D[brockno].position.set(i * 20 + 10, 10, j * 20 + 10);
                    scene.add(brock3D[brockno]);
                    brockno += 1;
                }
            }
        }
        brock[0].render.fillStyle = 'royalblue';//スタート地点表示
    }

    function Monster() {//three.js敵
        const monster = new THREE.Group();
        geometry = new THREE.CylinderGeometry(6, 6, 16, 20);
        material = new THREE.MeshToonMaterial({ color: 'limegreen' });
        const main = new THREE.Mesh(geometry, material);//敵の胴体
        main.position.set(0, 0, 0);
        monster.add(main);
        geometry = new THREE.SphereGeometry(6, 32, 32);
        material = new THREE.MeshToonMaterial({ color: 'darkolivegreen' });
        const cabin = new THREE.Mesh(geometry, material);//敵の頭
        cabin.position.set(0, 8, 0);
        monster.add(cabin);
        return monster;
    }

    //リフレッシュ
    function refresh() {
        Matter.Body.setPosition(player, { x: 30, y: 30 });
        Matter.Body.setAngle(player, 0);
        Matter.Body.setPosition(enemy, { x: 390, y: 390 });
        eforcey = -0.00002;
        countgem = 0;
        game = false;
    }

    //宝物設置
    function setgem() {
        World.remove(engine.world, [gem1]);scene.remove(gemD1);//宝物削除
        World.remove(engine.world, [gem2]);scene.remove(gemD2);
        World.remove(engine.world, [gem3]);scene.remove(gemD3);
        World.remove(engine.world, [gem4]);scene.remove(gemD4);
        rand1 = Math.floor(Math.random() * 48) + 8;//数えると空きマスが199なので8~55で1つ置く
        rand2 = Math.floor(Math.random() * 48) + 56;//56~103で1つ置く
        rand3 = Math.floor(Math.random() * 48) + 104;//104~151で1つ置く
        rand4 = Math.floor(Math.random() * 48) + 152;//152~199で1つ置く
        b = 0;
        for (i = 0; i < mapSize; i += 1) {
            for (j = 0; j < mapSize; j += 1) {
                if (MAP[i][j] == 0) {
                    b = b + 1;
                    if (rand1 == b) {
                        Matter.Body.setPosition(gem1, { x: i * 20 + 10, y: j * 20 + 10 });
                        World.add(engine.world, [gem1]);
                        //3D
                        gemD1.position.set(i * 20 + 10, 2.5, j * 20 + 10);
                        scene.add(gemD1);
                    }
                    if (rand2 == b) {
                        Matter.Body.setPosition(gem2, { x: i * 20 + 10, y: j * 20 + 10 });
                        World.add(engine.world, [gem2]);
                        //3D
                        gemD2.position.set(i * 20 + 10, 2.5, j * 20 + 10);
                        scene.add(gemD2);
                    }
                    if (rand3 == b) {
                        Matter.Body.setPosition(gem3, { x: i * 20 + 10, y: j * 20 + 10 });
                        World.add(engine.world, [gem3]);
                        //3D
                        gemD3.position.set(i * 20 + 10, 2.5, j * 20 + 10);
                        scene.add(gemD3);
                    }
                    if (rand4 == b) {
                        Matter.Body.setPosition(gem4, { x: i * 20 + 10, y: j * 20 + 10 });
                        World.add(engine.world, [gem4]);
                        //3D
                        gemD4.position.set(i * 20 + 10, 2.5, j * 20 + 10);
                        scene.add(gemD4);
                    }
                }
            }
        }
    }

    //run the engine
    Engine.run(engine);

    //キー入力
    window.addEventListener('keydown', (e) => {
        e.preventDefault();
        if (e.key == 'ArrowLeft') { left = true }
        if (e.key == 'ArrowRight') { right = true }
        if (e.key == 'ArrowUp') { speed = 0.00006 }
        if (e.key == 'ArrowDown') { speed = -0.00006 }
        if (e.key == ' ') { if (fifrag) {fire = true;fifrag = false} }
    });
    window.addEventListener('keyup', (e) => {
        e.preventDefault();
        if (e.key == 'ArrowLeft') { left = false }
        if (e.key == 'ArrowRight') { right = false }
        if (e.key == 'ArrowUp' || e.key == 'ArrowDown') { speed = 0 }
        if (e.key == ' ') { fifrag = true }
        if (!game) { if (gameok) {game = true} }
    });
    //スマホ入力
    window.addEventListener('touchstart', function (e) {
        e.preventDefault();
        x = e.changedTouches[0].pageX - imageX - imagesize / 2;
        y = e.changedTouches[0].pageY - imageY - imagesize / 2;
        if (x * x + y * y <= imagesize * 120) {
            if (x < 0 && y < x * x * 0.01 && y > x * x * -0.01) { left = true }
            if (x > 0 && y < x * x * 0.01 && y > x * x * -0.01) { right = true }
            if (y < 0 && x < y * y * 0.01 && x > y * y * -0.01) { speed = 0.00006 }
            if (y > 0 && x < y * y * 0.01 && x > y * y * -0.01) { speed = -0.00006 }
        }
        if (e.changedTouches[0].pageX < image2size && e.changedTouches[0].pageY > image2Y) { if (fifrag) {fire = true;fifrag = false} }
    }, { passive: false });
    window.addEventListener('touchend', function (e) {
        e.preventDefault();
        x = e.changedTouches[0].pageX - imagesize / 2 - imageX;
        y = e.changedTouches[0].pageY - imageY - imagesize / 2;
        if (x * x + y * y <= imagesize * 120) { left = false; right = false; speed = 0}
        fifrag = true;
        if (!game) { if (gameok) {game = true} }
    }, { passive: false });

    const c1 = document.getElementById('js-engine');//matter.jsのMAPを表示
    window.addEventListener('load', function (e) {
        if (window.innerHeight < window.innerWidth) {
            h = window.innerHeight * 0.4;
            w = h;
        } else {
            w = window.innerWidth * 0.4;
            h = w;
        }
        c1.style.height = h + 'px';
        c1.style.width = w + 'px';
    });

    const c2 = document.getElementById('js-guideimg');//pad.png表示
    if (window.innerWidth < window.innerHeight) { imagesize = 490 } else { imagesize = 240 }
    imageX = window.innerWidth - imagesize;
    imageY = window.innerHeight - imagesize;
    c2.style.right = 0 + 'px'; c2.style.top = imageY + 'px';
    c2.style.width = imagesize + 'px'; c2.style.height = imagesize + 'px';

    const c3 = document.getElementById('js-guideimg2');//pad2.png表示
    if (window.innerWidth < window.innerHeight) { image2size = 245 } else { image2size = 120 }
    image2Y = window.innerHeight - image2size * 1.5;
    c3.style.left = 0 + 'px'; c3.style.top = image2Y + 'px';
    c3.style.width = image2size + 'px'; c3.style.height = image2size + 'px';

    //タイトル
    container = document.createElement('div');
    document.body.appendChild(container);
    var info = document.createElement('div');
    info.style.position = 'absolute';
    info.style.left = '10%';
    info.style.top = '20%';
    info.style.width = '80%';
    info.style.color = "white";
    info.style.fontWeight = "bold";
    info.style.fontSize = '220%';
    info.innerHTML = 'PC:[←]左回転[→]右回転[↑]前移動[↓]下移動[Space]撃つ';
    container.appendChild(info);
    window.setTimeout(function() {info.innerHTML = ' '}, 3000);//時間で消す
})();