スマホのプラウザ上で遊べる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.js、three.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.js、three.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);//時間で消す
})();