Newer
Older
2024-c1230660 / map / Kimatu-App / shooter.js
export function startShootingGame(backgroundImage) {
    return new Promise((resolve) => {
        const gameContainer = document.createElement('div');
        gameContainer.style.position = 'fixed';
        gameContainer.style.top = 0;
        gameContainer.style.left = 0;
        gameContainer.style.width = '100vw';
        gameContainer.style.height = '100vh';
        gameContainer.style.zIndex = 9999;
        document.body.appendChild(gameContainer);

        const scene = new THREE.Scene();
        const camera = new THREE.OrthographicCamera(
            window.innerWidth / -2, window.innerWidth / 2,
            window.innerHeight / 2, window.innerHeight / -2,
            1, 1000
        );
        camera.position.z = 10;

        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        gameContainer.appendChild(renderer.domElement);

        const loader = new THREE.TextureLoader();
        loader.load(backgroundImage, (texture) => {
            scene.background = texture;
        });

        const playerGeometry = new THREE.BoxGeometry(30, 30, 1);
        const playerMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
        const player = new THREE.Mesh(playerGeometry, playerMaterial);
        player.position.x = -200;
        scene.add(player);

        const bullets = [];
        const enemies = [];
        let score = 0;
        let gameActive = true;

        const keys = { up: false, down: false, left: false, right: false, space: false };

        // キーボード入力イベント
        document.addEventListener('keydown', (event) => {
            if (event.key) {
                switch (event.key.toLowerCase()) {
                    case 'w': keys.up = true; break;
                    case 's': keys.down = true; break;
                    case 'a': keys.left = true; break;
                    case 'd': keys.right = true; break;
                    case ' ': keys.space = true; break;
                }
            }
        });

        document.addEventListener('keyup', (event) => {
            if (event.key) {
                switch (event.key.toLowerCase()) {
                    case 'w': keys.up = false; break;
                    case 's': keys.down = false; break;
                    case 'a': keys.left = false; break;
                    case 'd': keys.right = false; break;
                    case ' ': keys.space = false; break;
                }
            }
        });

        let count = 20;
        const infoBox = document.createElement('div');
        infoBox.style.position = 'absolute';
        infoBox.style.top = '10px';
        infoBox.style.left = '10px';
        infoBox.style.color = 'blue';
        infoBox.style.fontSize = '20px';
        infoBox.textContent = `残り時間: ${count}秒`;
        gameContainer.appendChild(infoBox);

        const countDown = setInterval(() => {
            if (!gameActive) return;
            count--;
            infoBox.textContent = `残り時間: ${count}秒`;
            if (count === 0) gameStop();
        }, 1000);

        function gameStop() {
            clearInterval(countDown);
            gameActive = false;
            cancelAnimationFrame(animationId);
            document.body.removeChild(gameContainer);
            resolve(score);
        }

        let lastShot = 0;
        let animationId;

        // タッチ操作用のボタンを作成
        const touchControls = document.createElement('div');
        touchControls.style.position = 'absolute';
        touchControls.style.bottom = '20px';
        touchControls.style.left = '20px';
        touchControls.style.width = '150px';
        touchControls.style.height = '150px';
        touchControls.style.zIndex = 10000;
        touchControls.style.display = 'grid';
        touchControls.style.gridTemplateColumns = 'repeat(3, 50px)';
        touchControls.style.gridGap = '5px';
        gameContainer.appendChild(touchControls);

        const fireButton = document.createElement('button');
        fireButton.textContent = 'FIRE';
        fireButton.style.position = 'absolute';
        fireButton.style.bottom = '20px';
        fireButton.style.right = '20px';
        fireButton.style.width = '80px';
        fireButton.style.height = '80px';
        fireButton.style.fontSize = '16px';
        fireButton.style.zIndex = 10000;
        gameContainer.appendChild(fireButton);

        const directions = ['↑', '←', '↓', '→'];
        const directionKeys = ['up', 'left', 'down', 'right'];

        directions.forEach((label, index) => {
            const button = document.createElement('button');
            button.textContent = label;
            button.style.fontSize = '20px';
            button.style.width = '50px';
            button.style.height = '50px';
            touchControls.appendChild(button);

            button.addEventListener('touchstart', () => {
                keys[directionKeys[index]] = true;
            });

            button.addEventListener('touchend', () => {
                keys[directionKeys[index]] = false;
            });
        });

        fireButton.addEventListener('touchstart', () => {
            keys.space = true;
        });

        fireButton.addEventListener('touchend', () => {
            keys.space = false;
        });

        function animate() {
            if (!gameActive) return;
            animationId = requestAnimationFrame(animate);

            const time = performance.now();

            if (keys.up) player.position.y += 6;
            if (keys.down) player.position.y -= 6;
            if (keys.left) player.position.x -= 6;
            if (keys.right) player.position.x += 6;

            if (keys.space && time - lastShot > 250) {
                const bullet = new THREE.Mesh(
                    new THREE.BoxGeometry(20, 10, 1),
                    new THREE.MeshBasicMaterial({ color: 0x00ff00 })
                );
                bullet.position.set(player.position.x + 20, player.position.y, 0);
                bullets.push(bullet);
                scene.add(bullet);
                lastShot = time;
            }

            bullets.forEach((bullet, index) => {
                bullet.position.x += 15;
                if (bullet.position.x > window.innerWidth / 2) {
                    scene.remove(bullet);
                    bullets.splice(index, 1);
                }
            });

            if (Math.random() < 0.02) {
                const enemy = new THREE.Mesh(
                    new THREE.BoxGeometry(30, 30, 1),
                    new THREE.MeshBasicMaterial({ color: 0xff0000 })
                );
                enemy.position.set(window.innerWidth / 2, (Math.random() - 0.5) * window.innerHeight, 0);
                enemies.push(enemy);
                scene.add(enemy);
            }

            enemies.forEach((enemy, eIndex) => {
                enemy.position.x -= 3;
                bullets.forEach((bullet, bIndex) => {
                    if (bullet.position.distanceTo(enemy.position) < 20) {
                        scene.remove(enemy);
                        enemies.splice(eIndex, 1);
                        scene.remove(bullet);
                        bullets.splice(bIndex, 1);
                        score++;
                    }
                });
            });

            renderer.render(scene, camera);
        }

        animate();
    });
}