2
3

1, 2, 3 発射。ロケット打ち上げゲーム。

Last updated at Posted at 2024-08-12

スクリーンショット 2024-08-13 003853.png

スクリーンショット 2024-08-13 003918.png

スペースキーを押すと発射。ロケット打ち上げゲーム。

import http.server
import socketserver
import tempfile
import webbrowser

html_content = """
<!DOCTYPE html>
<html>
<head>
    <title>ロケット打ち上げシミュレーション</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            color: white;
            font-size: 24px;
            text-align: center;
            background-color: black;
        }
        #altitude {
            position: absolute;
            top: 10px;
            left: 10px;
            z-index: 1;
        }
        #startMessage {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 2;
            color: yellow;
            font-size: 36px;
        }
    </style>
</head>
<body>
    <div id="altitude">Altitude: 0 m</div>
    <div id="startMessage">Press SPACE to Start</div>
    <script src="https://cdn.jsdelivr.net/npm/three@0.139.2/build/three.min.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);

        // 地面を作成
        var groundGeometry = new THREE.PlaneGeometry(1000, 1000);
        var groundMaterial = new THREE.MeshBasicMaterial({ color: 0x228B22 });
        var ground = new THREE.Mesh(groundGeometry, groundMaterial);
        ground.rotation.x = -Math.PI / 2;
        ground.position.y = -0.5;
        scene.add(ground);

        // 発射台を作成
        var platformGeometry = new THREE.BoxGeometry(2, 0.5, 2);
        var platformMaterial = new THREE.MeshBasicMaterial({ color: 0x808080 });
        var platform = new THREE.Mesh(platformGeometry, platformMaterial);
        platform.position.y = 0;
        scene.add(platform);

        // ロケットを作成
        var rocketGeometry = new THREE.CylinderGeometry(0.2, 0.2, 2, 32);
        var rocketMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
        var rocket = new THREE.Mesh(rocketGeometry, rocketMaterial);
        rocket.position.y = 1.25;
        scene.add(rocket);

        // ロケットの炎を作成
        var flameGeometry = new THREE.ConeGeometry(0.3, 0.5, 32);
        var flameMaterial = new THREE.MeshBasicMaterial({ color: 0xffa500 });
        var flame = new THREE.Mesh(flameGeometry, flameMaterial);
        flame.position.y = -1.25;
        flame.rotation.x = Math.PI;
        rocket.add(flame);

        // 変数の初期化
        var rocketVelocity = 0.1;  // ロケットの初速度
        var gravity = -0.01;  // 重力加速度
        var altitude = 0;  // 高度
        var engineStartTime;  // エンジンが開始された時間
        var engineRunning = false;  // エンジンが動いているかどうか
        var landing = false;  // 着陸中かどうか

        camera.position.z = 5;

        // 四角い箱をランダムに10個配置
        for (var i = 0; i < 10; i++) {
            var boxGeometry = new THREE.BoxGeometry(1, 1, 1);
            var boxMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
            var box = new THREE.Mesh(boxGeometry, boxMaterial);
            box.position.set(Math.random() * 20 - 10, 0.5, Math.random() * 20 - 10);  // ランダムに配置
            scene.add(box);
        }

        // アニメーションループ
        function animate() {
            requestAnimationFrame(animate);

            // スペースキーが押されるまでエンジンを動かさない
            if (!engineRunning) {
                return;
            }

            var elapsedTime = (Date.now() - engineStartTime) / 1000;  // エンジン開始からの経過時間

            // 打ち上げフェーズ (10秒間)
            if (elapsedTime <= 10) {
                altitude += rocketVelocity;
                rocket.position.y += rocketVelocity;
            } 
            // 着陸フェーズ
            else if (altitude > 0) {
                flame.visible = false;  // 炎を消す
                rocketVelocity += gravity;  // 重力を適用
                altitude += rocketVelocity;
                rocket.position.y += rocketVelocity;

                // ロケットが地面に到達したら停止
                if (rocket.position.y <= 1.25) {
                    rocketVelocity = 0;
                    rocket.position.y = 1.25;
                    landing = true;
                }
            }

            // 高度を表示
            document.getElementById("altitude").textContent = "Altitude: " + Math.max(0, Math.round(altitude * 10)) + " m";
            camera.position.y = rocket.position.y;  // カメラをロケットに追従させる
            camera.lookAt(rocket.position);

            renderer.render(scene, camera);  // シーンをレンダリング
        }

        // スペースキーが押されたときにエンジンをスタートさせる
        document.addEventListener('keydown', function(event) {
            if (event.code === 'Space' && !engineRunning) {
                engineRunning = true;
                engineStartTime = Date.now();  // エンジン開始時間を記録
                document.getElementById("startMessage").style.display = 'none';  // スタートメッセージを隠す
            }
        });

        animate();  // アニメーションを開始
    </script>
</body>
</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}")

PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler

# ローカルサーバーを起動してHTMLを提供
with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print(f"Serving at port {PORT}")
    httpd.serve_forever()


2
3
1

Register as a new user and use Qiita more conveniently

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