簡単な3Dオープンワールドのフライトシュミレータゲームです。カーソルキーで移動です。上で機首上げ、下で機首下げ、左右で旋回です。(操作に慣れてくると面白いです。)
実行結果。
ジュピター ノートブックにコードを貼り付けて実行すると、サーバーが起動してブラウザ上でゲームが始まります。
フライトシュミレータ ゲームです。
import http.server
import socketserver
import tempfile
import webbrowser
import random
# HTMLとJavaScriptのコード
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>フライトシミュレーター</title>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/three@0.139.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.139.2/examples/js/controls/PointerLockControls.js"></script>
<script>
// シーン、カメラ、レンダラーの作成
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 背景色を空の青色に設定
scene.background = new THREE.Color(0x87CEEB);
// 飛行機(3つのボックスで構成)
var fuselageGeometry = new THREE.BoxGeometry(1, 0.2, 2);
var wingGeometry = new THREE.BoxGeometry(3, 0.1, 0.5);
var tailGeometry = new THREE.BoxGeometry(0.5, 0.1, 0.5);
var planeMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var fuselage = new THREE.Mesh(fuselageGeometry, planeMaterial);
var wing = new THREE.Mesh(wingGeometry, planeMaterial);
var tail = new THREE.Mesh(tailGeometry, planeMaterial);
wing.position.set(0, 0.15, 0);
tail.position.set(0, 0.2, -0.75);
var plane = new THREE.Group();
plane.add(fuselage);
plane.add(wing);
plane.add(tail);
plane.position.y = 2; // 飛行機を初期位置で空中に設定
scene.add(plane);
// 茶色の地面を作成
var groundGeometry = new THREE.PlaneGeometry(1000, 1000);
var groundMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513, side: THREE.DoubleSide });
var ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = Math.PI / 2;
scene.add(ground);
// カラフルなボックスをランダムに地面と空中に配置
var blockCount = 500;
for (var i = 0; i < blockCount; i++) {
var blockGeometry = new THREE.BoxGeometry(
Math.random() * 2 + 0.5,
Math.random() * 2 + 0.5,
Math.random() * 2 + 0.5
);
var blockMaterial = new THREE.MeshBasicMaterial({
color: Math.random() * 0xffffff
});
var block = new THREE.Mesh(blockGeometry, blockMaterial);
block.position.set(
(Math.random() - 0.5) * 1000,
Math.random() * 10 + 0.5,
(Math.random() - 0.5) * 1000
);
scene.add(block);
}
// カメラコントロールの設定
var controls = new THREE.PointerLockControls(camera, document.body);
camera.position.set(0, 2.5, 5);
document.body.addEventListener('click', function() {
controls.lock();
});
// 操作フラグ
var yawLeft = false;
var yawRight = false;
var pitchUp = false;
var pitchDown = false;
var planeSpeed = 0.5;
// キーが押された時の処理
function onKeyDown(event) {
switch(event.code) {
case 'ArrowLeft':
yawLeft = true;
break;
case 'ArrowRight':
yawRight = true;
break;
case 'ArrowUp':
pitchUp = true;
break;
case 'ArrowDown':
pitchDown = true;
break;
}
}
// キーが離された時の処理
function onKeyUp(event) {
switch(event.code) {
case 'ArrowLeft':
yawLeft = false;
break;
case 'ArrowRight':
yawRight = false;
break;
case 'ArrowUp':
pitchUp = false;
break;
case 'ArrowDown':
pitchDown = false;
break;
}
}
// キーボードイベントリスナー
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
// アニメーションループ
function animate() {
requestAnimationFrame(animate);
// 機体の旋回操作(ヨー)
if (yawLeft) plane.rotation.y += 0.05; // 左旋回
if (yawRight) plane.rotation.y -= 0.05; // 右旋回
// 機首の上下操作(ピッチ)
if (pitchUp) plane.rotation.x -= 0.05; // 機首上げ
if (pitchDown) plane.rotation.x += 0.05; // 機首下げ
// 機体の進行方向を計算
var forwardDirection = new THREE.Vector3(0, 0, -1);
forwardDirection.applyQuaternion(plane.quaternion);
plane.position.addScaledVector(forwardDirection, planeSpeed);
// カメラの追従
camera.position.set(
plane.position.x - 3 * Math.sin(plane.rotation.y),
plane.position.y + 2,
plane.position.z - 3 * Math.cos(plane.rotation.y)
);
camera.lookAt(plane.position);
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
"""
# 一時的なファイルにHTMLコンテンツを書き込む
with tempfile.NamedTemporaryFile(delete=False, suffix=".html") as temp_html:
temp_html.write(html_content.encode("utf-8"))
temp_html.flush()
webbrowser.open(f"file://{temp_html.name}")
# サーバーを作成してHTMLを提供する
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print(f"Serving at port {PORT}")
httpd.serve_forever()