<!DOCTYPE html>

<html lang="ru">

<head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Шутер (а-ля Standoff 2)</title>

    <style>

        body { margin: 0; overflow: hidden; background: #000; }

        #info {

            position: absolute;

            top: 20px;

            left: 20px;

            color: white;

            font-family: Arial, sans-serif;

            font-size: 18px;

            background: rgba(0,0,0,0.6);

            padding: 10px 20px;

            border-radius: 8px;

            pointer-events: none;

            user-select: none;

        }

        #reticle {

            position: absolute;

            top: 50%;

            left: 50%;

            width: 4px;

            height: 4px;

            background: red;

            border-radius: 50%;

            transform: translate(-50%, -50%);

            pointer-events: none;

        }

        #hint {

            position: absolute;

            bottom: 30px;

            left: 0;

            width: 100%;

            text-align: center;

            color: #aaa;

            font-family: Arial, sans-serif;

            font-size: 16px;

            pointer-events: none;

            background: rgba(0,0,0,0.5);

            padding: 8px;

        }

    </style>

</head>

<body>

    <div id="info">🎯 Счёт: <span id="score">0</span>  |  Врагов: <span id="enemies">0</span></div>

    <div id="reticle"></div>

    <div id="hint">Кликните по экрану → управление WASD + мышь (прицел) / ЛКМ — огонь</div>

    <!-- Подключаем Three.js и вспомогательные библиотеки -->

    <script type="importmap">

        {

            "imports": {

                "three": "https://unpkg.com/three@0.128.0/build/three.module.js",

                "three/addons/": "https://unpkg.com/three@0.128.0/examples/jsm/"

            }

        }

    </script>

    <script type="module">

        import * as THREE from 'three';

        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

        import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';

        // --- Сцена, камера, рендер ---

        const scene = new THREE.Scene();

        scene.background = new THREE.Color(0x87CEEB); // небо

        scene.fog = new THREE.Fog(0x87CEEB, 30, 80);

        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);

        camera.position.set(0, 1.6, 0);

        const renderer = new THREE.WebGLRenderer({ antialias: true });

        renderer.setSize(window.innerWidth, window.innerHeight);

        renderer.shadowMap.enabled = true;

        document.body.appendChild(renderer.domElement);

        // --- Управление (захват мыши) ---

        const controls = new PointerLockControls(camera, document.body);

        // --- Освещение ---

        const ambientLight = new THREE.AmbientLight(0x404060);

        scene.add(ambientLight);

        const dirLight = new THREE.DirectionalLight(0xffffff, 1);

        dirLight.position.set(20, 30, 10);

        dirLight.castShadow = true;

        scene.add(dirLight);

        const backLight = new THREE.DirectionalLight(0xccddff, 0.5);

        backLight.position.set(-20, 10, -20);

        scene.add(backLight);

        // --- Пол ---

        const groundGeometry = new THREE.PlaneGeometry(100, 100);

        const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x2c3e50, roughness: 0.8 });

        const ground = new THREE.Mesh(groundGeometry, groundMaterial);

        ground.rotation.x = -Math.PI / 2;

        ground.position.y = -0.01;

        ground.receiveShadow = true;

        scene.add(ground);

        // Сетка для ориентира

        const grid = new THREE.GridHelper(100, 20, 0xaaaaaa, 0x444444);

        grid.position.y = 0;

        scene.add(grid);

        // --- Стены по краям (для ощущения пространства) ---

        const wallMat = new THREE.MeshStandardMaterial({ color: 0x7f8c8d, roughness: 0.7 });

        const createWall = (x, z, w, h, d) => {

            const wall = new THREE.Mesh(new THREE.BoxGeometry(w, h, d), wallMat);

            wall.position.set(x, h/2, z);

            wall.castShadow = true;

            wall.receiveShadow = true;

            scene.add(wall);

            return wall;

        };

        createWall(0, -48, 100, 4, 2); // задняя

        createWall(0, 48, 100, 4, 2);  // передняя

        createWall(-48, 0, 2, 4, 100); // левая

        createWall(48, 0, 2, 4, 100);  // правая

        // --- Создание врагов (красные кубы) ---

        const enemies = [];

        const enemyMaterial = new THREE.MeshStandardMaterial({ color: 0xe74c3c, emissive: 0x330000 });

        const enemyGeometry = new THREE.BoxGeometry(0.8, 1.8, 0.8);

        function spawnEnemy() {

            let x, z, valid;

            let attempts = 0;

            do {

                x = (Math.random() - 0.5) * 70;

                z = (Math.random() - 0.5) * 70;

                valid = true;

                // Не спавнить слишком близко к игроку (0,0)

                if (Math.sqrt(x*x + z*z) < 5) valid = false;

                // Не спавнить внутри других врагов

                for (let e of enemies) {

                    if (e.position.distanceTo(new THREE.Vector3(x, 0, z)) < 1.5) {

                        valid = false;

                        break;

                    }

                }

                attempts++;

                if (attempts > 100) break;

            } while (!valid);

           

            const enemy = new THREE.Mesh(enemyGeometry, enemyMaterial);

            enemy.position.set(x, 1.0, z);

            enemy.castShadow = true;

            enemy.receiveShadow = true;

            scene.add(enemy);

            enemies.push(enemy);

            updateUI();

        }

        // Изначально 10 врагов

        for (let i = 0; i < 10; i++) spawnEnemy();

        // --- Счёт и UI ---

        let score = 0;

        const scoreSpan = document.getElementById('score');

        const enemiesSpan = document.getElementById('enemies');

        function updateUI() {

            scoreSpan.textContent = score;

            enemiesSpan.textContent = enemies.length;

        }

        updateUI();

        // --- Выстрел (Raycaster) ---

        const raycaster = new THREE.Raycaster();

        function shoot() {

            if (!controls.isLocked) return; // стрельба только когда захвачена мышь

            raycaster.setFromCamera({ x: 0, y: 0 }, camera); // центр экрана

            const intersects = raycaster.intersectObjects(enemies);

            if (intersects.length > 0) {

                const hit = intersects[0].object;

                // Удаляем врага

                scene.remove(hit);

                const idx = enemies.indexOf(hit);

                if (idx !== -1) enemies.splice(idx, 1);

                score++;

                updateUI();

                // Через 2 секунды появится новый враг (чтобы не было пусто)

                setTimeout(() => {

                    if (enemies.length < 20) spawnEnemy();

                }, 1000);

            }

        }

        // --- Обработка событий ---

        // Клик по экрану для захвата мыши

        document.addEventListener('click', () => {

            if (!controls.isLocked) {

                controls.lock();

            } else {

                shoot(); // если уже захвачено, стреляем

            }

        });

        // Клавиша Escape разблокирует мышь

        document.addEventListener('keydown', (e) => {

            if (e.key === 'Escape' && controls.isLocked) {

                controls.unlock();

            }

        });

        // Событие выстрела также по пробелу (для удобства)

        document.addEventListener('keydown', (e) => {

            if (e.key === ' ' && controls.isLocked) {

                e.preventDefault();

                shoot();

            }

        });

        // --- Перемещение (клавиши WASD) ---

        const keys = { w: false, a: false, s: false, d: false };

        document.addEventListener('keydown', (e) => {

            switch(e.key.toLowerCase()) {

                case 'w': keys.w = true; e.preventDefault(); break;

                case 'a': keys.a = true; e.preventDefault(); break;

                case 's': keys.s = true; e.preventDefault(); break;

                case 'd': keys.d = true; e.preventDefault(); break;

            }

        });

        document.addEventListener('keyup', (e) => {

            switch(e.key.toLowerCase()) {

                case 'w': keys.w = false; e.preventDefault(); break;

                case 'a': keys.a = false; e.preventDefault(); break;

                case 's': keys.s = false; e.preventDefault(); break;

                case 'd': keys.d = false; e.preventDefault(); break;

            }

        });

        // --- Адаптация размера окна ---

        window.addEventListener('resize', () => {

            camera.aspect = window.innerWidth / window.innerHeight;

            camera.updateProjectionMatrix();

            renderer.setSize(window.innerWidth, window.innerHeight);

        });

        // --- Анимация цикла ---

        function animate() {

            requestAnimationFrame(animate);

            // Перемещение (только если мышь захвачена)

            if (controls.isLocked) {

                const speed = 0.12;

                const forward = new THREE.Vector3(0, 0, -1);

                forward.applyQuaternion(camera.quaternion);

                forward.y = 0;

                forward.normalize();

                const right = new THREE.Vector3(1, 0, 0);

                right.applyQuaternion(camera.quaternion);

                right.y = 0;

                right.normalize();

                const moveVec = new THREE.Vector3(0, 0, 0);

                if (keys.w) moveVec.add(forward);

                if (keys.s) moveVec.sub(forward);

                if (keys.d) moveVec.add(right);

                if (keys.a) moveVec.sub(right);

               

                if (moveVec.length() > 0) {

                    moveVec.normalize().multiplyScalar(speed);

                    camera.position.add(moveVec);

                    // Простая коллизия со стенами (приблизительная)

                    if (Math.abs(camera.position.x) > 46) camera.position.x = Math.sign(camera.position.x) * 46;

                    if (Math.abs(camera.position.z) > 46) camera.position.z = Math.sign(camera.position.z) * 46;

                }

            }

            renderer.render(scene, camera);

        }

        animate();

        // Периодическое появление новых врагов, если их мало

        setInterval(() => {

            if (enemies.length < 8) {

                spawnEnemy();

            }

        }, 5000);

        console.log('Игра запущена! Кликните, чтобы захватить мышь, WASD — ходьба, клик/пробел — стрельба.');

    </script>

</body>

</html>