<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>3D Червяк</title>
    <style>
        body { margin: 0; overflow: hidden; }
        #menu {
            position: absolute; top: 0; left: 0;
            width: 100%; height: 100%;
            background: rgba(255, 255, 255, 0.8);
            display: flex; flex-direction: column;
            align-items: center; justify-content: center;
            z-index: 10;
        }
        #menu h1 { margin-bottom: 20px; }
        #menu label { margin-bottom: 10px; }
        #menu button { padding: 10px 20px; font-size: 16px; }
        #score {
            position: absolute; top: 10px; left: 10px;
            color: black; font-size: 24px; z-index: 5;
            display: none;
        }
    </style>
</head>
<body>
    <div id="menu">
        <h1>Выберите настройки червяка</h1>
        <label>Выберите тип червяка:
            <select id="snakeType">
                <option value="default">Обычный червяк</option>
                <option value="textured">Червяк с текстурами</option>
            </select>
        </label>
        <div id="colorPicker">
            <label>Выберите цвет червяка:
                <input type="color" id="snakeColor" value="#FFFF00">
            </label>
        </div>
        <div id="textureUploader" style="display: none;">
            <label>Загрузите изображение для текстуры:
                <input type="file" id="textureFile" accept="image/png, image/jpeg">
            </label>
        </div>
        <button id="startButton">Начать игру</button>
    </div>
    <div id="score">Счет: 0</div>

    <script src="https://unpkg.com/three@0.152.0/build/three.min.js"></script>
    <script>
        let scene, camera, renderer;
        let wormSegments = [], positions = [];
        let direction = new THREE.Vector3(0, 0, -1), speed = 0.1;
        let food, keyStates = {};
        let numSegments = 2, segmentSpacing = 5, score = 0;
        let snake, textureGlobal, snakeColorGlobal = "#FFFF00", snakeTypeGlobal = "default";
        let segmentGeometry, segmentMaterial;

        document.getElementById('snakeType').addEventListener('change', function() {
            snakeTypeGlobal = this.value;
            document.getElementById('textureUploader').style.display = snakeTypeGlobal === 'textured' ? 'block' : 'none';
            document.getElementById('colorPicker').style.display = snakeTypeGlobal === 'default' ? 'block' : 'none';
        });

        document.getElementById('startButton').addEventListener('click', function() {
            snakeColorGlobal = document.getElementById('snakeColor').value;
            const textureFileInput = document.getElementById('textureFile');
            const textureFile = textureFileInput.files.length > 0 ? textureFileInput.files[0] : null;
            document.getElementById('menu').style.display = 'none';
            document.getElementById('score').style.display = 'block'; // Показываем счет только после начала игры
            init(snakeTypeGlobal, snakeColorGlobal, textureFile);
        });

        function init(snakeType, snakeColor, textureFile) {
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x87CEEB);

            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            camera.position.set(0, 5, 20);

            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
            scene.add(ambientLight);

            const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
            directionalLight.position.set(0, 10, 0);
            scene.add(directionalLight);

            const groundGeometry = new THREE.PlaneGeometry(100, 100);
            const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x008000 });
            const ground = new THREE.Mesh(groundGeometry, groundMaterial);
            ground.rotation.x = -Math.PI / 2;
            scene.add(ground);

            if (snakeType === 'textured' && textureFile) {
                const reader = new FileReader();
                reader.onload = function(event) {
                    const textureLoader = new THREE.TextureLoader();
                    textureLoader.load(event.target.result, function(texture) {
                        textureGlobal = texture;
                        createSnake();
                        createFood();
                        animate();
                    });
                };
                reader.readAsDataURL(textureFile);
            } else {
                createSnake();
                createFood();
                animate();
            }

            document.addEventListener('keydown', onKeyDown);
            document.addEventListener('keyup', onKeyUp);
            window.addEventListener('resize', onWindowResize);
        }

        function createSnake() {
            wormSegments = [];
            positions = [];

            segmentGeometry = new THREE.SphereGeometry(0.5, 16, 16);

            segmentMaterial = (snakeTypeGlobal === 'textured' && textureGlobal)
                ? new THREE.MeshBasicMaterial({ map: textureGlobal })
                : new THREE.MeshBasicMaterial({ color: new THREE.Color(snakeColorGlobal) });

            snake = { position: new THREE.Vector3(0, 0.5, 0) };
            positions.push(snake.position.clone());

            for (let i = 0; i < numSegments; i++) {
                const segment = new THREE.Mesh(segmentGeometry, segmentMaterial);
                segment.position.copy(snake.position);
                wormSegments.push(segment);
                scene.add(segment);
            }
        }

        function createFood() {
            const geometry = new THREE.SphereGeometry(0.5, 16, 16);
            const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
            food = new THREE.Mesh(geometry, material);
            food.position.set(
                Math.floor(Math.random() * 20 - 10),
                0.5,
                Math.floor(Math.random() * 20 - 10)
            );
            scene.add(food);
        }

        function onKeyDown(event) { keyStates[event.code] = true; }
        function onKeyUp(event) { keyStates[event.code] = false; }

        function updateDirection() {
            const turnSpeed = 0.05;
            if (keyStates['KeyA']) direction.applyAxisAngle(new THREE.Vector3(0, 1, 0), turnSpeed);
            if (keyStates['KeyD']) direction.applyAxisAngle(new THREE.Vector3(0, 1, 0), -turnSpeed);
            direction.normalize();
        }

        function animate() {
            requestAnimationFrame(animate);
            updateDirection();

            const newPosition = snake.position.clone().add(direction.clone().multiplyScalar(speed));
            newPosition.y = 0.5;
            snake.position.copy(newPosition);

            positions.unshift(snake.position.clone());
            if (positions.length > (numSegments + 1) * segmentSpacing) {
                positions.pop();
            }

            for (let i = 0; i < wormSegments.length; i++) {
                const index = (i + 1) * segmentSpacing;
                if (positions[index]) {
                    wormSegments[i].position.copy(positions[index]);
                }
            }

            if (snake.position.distanceTo(food.position) < 1) {
                scene.remove(food);
                createFood();
                const newSegment = new THREE.Mesh(segmentGeometry, segmentMaterial);
                newSegment.position.copy(wormSegments[wormSegments.length - 1].position);
                wormSegments.push(newSegment);
                scene.add(newSegment);

                numSegments += 1;
                score += 10;
                document.getElementById('score').textContent = 'Счет: ' + score;
            }

            const cameraDistance = 10;
            const cameraHeight = 5;
            const behindDirection = direction.clone().negate().normalize();
            const cameraOffset = behindDirection.clone().multiplyScalar(cameraDistance);
            cameraOffset.y += cameraHeight;
            camera.position.copy(snake.position.clone().add(cameraOffset));
            camera.lookAt(snake.position);

            renderer.render(scene, camera);
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
    </script>
</body>
</html>
добавь в меню на выбор управление пк или выбор телефона если выбирается телефон то появляются снизу две кнопки для управления червя влево и вправо