<html>
<head>
<meta charset="UTF-8">
<title>Кибершамыга</title>
<style>
body { margin: 0; overflow: hidden; font-family: Arial, sans-serif; }
canvas { display: block; }
#menu {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
}
#menu h1 {
font-size: 4em;
margin-bottom: 30px;
}
#playButton {
font-size: 1.5em;
padding: 10px 20px;
cursor: pointer;
}
#hud, #health-bar, #crosshair {
display: none;
}
#hud {
position: absolute;
top: 10px;
left: 10px;
color: white;
font-size: 18px;
}
#health-bar {
position: absolute;
bottom: 10px;
left: 10px;
width: 200px;
height: 20px;
background-color: red;
}
#health {
height: 100%;
background-color: green;
width: 100%;
text-align: center;
color: white;
font-weight: bold;
line-height: 20px;
}
#crosshair {
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
background-color: transparent;
border: 2px solid red;
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
#death-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
display: none;
justify-content: center;
align-items: center;
}

#death-modal-content {
background-color: #333;
padding: 40px;
border-radius: 10px;
text-align: center;
color: white;
}

#death-modal-content h2 {
margin-bottom: 30px;
}

#death-modal-content button {
font-size: 1.2em;
padding: 10px 30px;
margin: 10px;
cursor: pointer;
}
  #skins-modal {
       position: fixed;
       top: 0;
       left: 0;
       width: 100%;
       height: 100%;
       background-color: rgba(0, 0, 0, 0.8);
       display: none;
       justify-content: center;
       align-items: center;
   }
   #skins-modal-content {
       background-color: #333;
       padding: 40px;
       border-radius: 10px;
       text-align: center;
       color: white;
   }
   .skin-item {
    margin-bottom: 10px;
}
.skin-item span {
    margin-right: 10px;
}
#loading-modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.8);
    display: none; /* Скрыто по умолчанию */
    justify-content: center;
    align-items: center;
}

#loading-modal-content {
    background-color: #333;
    padding: 40px;
    border-radius: 10px;
    text-align: center;
    color: white;
}

#loading-progress {
    margin-top: 20px;
    font-size: 1.5em;
}
#version {
position: fixed;
bottom: 10px;
right: 10px;
color: white;
font-size: 14px;
}
</style>
</head>
<body>
<!-- Меню -->
<div id="menu">
<h1>Кибершамыга</h1>
<button id="playButton">Играть</button>
<span id="previous-kills"> Рекорд киллов: <span id="kills-display">0</span></span>
<button id="skinsButton">Скины</button>
</div>
<div id="skins-modal">
    <div id="skins-modal-content">
        <h2>Выбор скинов</h2>
        <div id="skins-list">
            <!-- Здесь будут отображаться скины -->
        </div>
        <button id="closeSkinsButton">Закрыть</button>
    </div>
</div>
<!-- Экран загрузки -->
<div id="loading-modal">
    <div id="loading-modal-content">
        <h2>Загрузка...</h2>
        <div id="loading-progress">0%</div>
    </div>
</div>
<div id="death-modal">
<div id="death-modal-content">
<h2>Вы погибли!</h2>
<button id="restartButton">Начать заново</button>
<button id="returnToMenuButton">Вернуться в меню</button>
</div>
</div>

<!-- HUD (Heads-Up Display) -->
<div id="hud">
    <div>Время: <span id="time">00:00</span></div>
    <div>Киллы: <span id="kills">0</span></div>
    <div>Патроны: <span id="ammo">10/∞</span></div>
</div>

<!-- Полоса здоровья -->
<div id="health-bar">
<div id="health">100%</div>
</div>

<!-- Прицел -->
<div id="crosshair"></div>

<!-- Подключаем библиотеку Three.js с CDN -->
<script src="https://cdn.jsdelivr.net/npm/three@0.148/build/three.min.js"></script>
<script>
let scene, camera, renderer, player;
let health = 100;
let bulletSpeed = 50.0;
let gameStartTime;
let kills = 0;
let killsRecord = 0;
let muzzleFlash;
let muzzleFlashDuration = 0;
let muzzleFlashEndTime = 0;
let magazineSize = 10;
let currentAmmo = magazineSize;
let isReloading = false;
let isGameActive = false;
let isMouseDown = false;
let lastShotTime = 0;
const shotInterval = 0.2; // Интервал между выстрелами в секундах (например, 0.2 секунды)
const enemyUpdateDistance = 1000; // Дистанция, внутри которой враги активно обновляются
const maxEnemyDistance = 2000;   // Дистанция, за пределами которой враги удаляются



let skins = {
    default: {
        name: "Стандартный",
        unlocked: true,
        model: null
    },
    golden: {
        name: "Золотой",
        unlocked: false,
        model: null
    }
};

let selectedSkin = 'default';

let reloadAnimationProgress = 0;
let isAnimatingReload = false;
const reloadAnimationDuration = 1.5;

const enemies = [];
let enemySpeed = 5.0;
let maxEnemies = 40;
let lastDifficultyIncreaseTime;
const bullets = [];

let tileSize = 150;
let tiles = {};
let tileMeshes = {};
const trees = [];
let treeMeshes = {};
let treeInstances = {};

const skinsButton = document.getElementById('skinsButton');
const skinsModal = document.getElementById('skins-modal');
const closeSkinsButton = document.getElementById('closeSkinsButton');

skinsButton.addEventListener('click', function(event) {
    event.stopPropagation();
    skinsModal.style.display = 'flex';
});

closeSkinsButton.addEventListener('click', function(event) {
    event.stopPropagation();
    skinsModal.style.display = 'none';
});

let gunGroup, gunBody, magazine;

function updateGunSkin() {
    if (selectedSkin === 'golden') {
        gunBody.material.color.set(0xFFD700);
    } else {
        gunBody.material.color.set(0x333333);
    }
}

function updateSkinsMenu() {
    const skinsList = document.getElementById('skins-list');
    skinsList.innerHTML = '';

    for (let key in skins) {
        let skin = skins[key];

        let skinDiv = document.createElement('div');
        skinDiv.className = 'skin-item';

        let skinName = document.createElement('span');
        skinName.textContent = skin.name;

        let selectButton = document.createElement('button');
        selectButton.textContent = 'Выбрать';
        selectButton.disabled = !skin.unlocked;
        selectButton.addEventListener('click', function () {
            selectedSkin = key;
            skinsModal.style.display = 'none';
            updateGunSkin();
        });

        if (!skin.unlocked) {
            let lockSpan = document.createElement('span');
            lockSpan.textContent = '🔒 Требуется 1000 киллов';
            skinDiv.appendChild(lockSpan);
        }

        skinDiv.appendChild(skinName);
        skinDiv.appendChild(selectButton);
        skinsList.appendChild(skinDiv);
    }
}

function saveSkins() {
    localStorage.setItem('skins', JSON.stringify({
        goldenUnlocked: skins.golden.unlocked
    }));
}

function loadSkins() {
    let storedSkins = localStorage.getItem('skins');
    if (storedSkins) {
        let data = JSON.parse(storedSkins);
        skins.golden.unlocked = data.goldenUnlocked || false;
    }
}

loadSkins();

function getRandomSpawnPosition() {
    let position;
    let isPositionValid = false;
    const preloadRadius = window.preloadRadius || 10000; // Убедитесь, что preloadRadius доступен

    while (!isPositionValid) {
        position = new THREE.Vector3(
            (Math.random() * 2 - 1) * preloadRadius,
            1.6,
            (Math.random() * 2 - 1) * preloadRadius
        );

        isPositionValid = true;

        // Проверяем, что позиция не слишком близка к деревьям
        for (let i = 0; i < trees.length; i++) {
            const tree = trees[i];
            const distance = position.distanceTo(tree);
            if (distance < 5) {
                isPositionValid = false;
                break;
            }
        }
    }
    return position;
}

function reload() {
    if (isReloading || currentAmmo === magazineSize) {
        return;
    }

    isReloading = true;
    isAnimatingReload = true;
    reloadAnimationProgress = 0;
    updateHUD();
}

function showDeathModal() {
    const deathModal = document.getElementById('death-modal');
    deathModal.style.display = 'flex';

    document.getElementById('crosshair').style.display = 'none'; // Скрываем прицел
}

function saveProgress() {
    localStorage.setItem('killsRecord', killsRecord);
}

function loadProgress() {
    const storedKillsRecord = localStorage.getItem('killsRecord');
    if (storedKillsRecord) {
        killsRecord = parseInt(storedKillsRecord, 10);
    }
}

function updateMenu() {
    const killsDisplay = document.getElementById('kills-display');
    killsDisplay.textContent = killsRecord;

    // Обновляем список скинов
    updateSkinsMenu();
}

loadProgress();
updateMenu();

function updateHUD() {
    const timeElement = document.getElementById('time');
    const killsElement = document.getElementById('kills');
    const ammoElement = document.getElementById('ammo');

    const currentTime = new Date().getTime();
    const elapsedTime = Math.floor((currentTime - gameStartTime) / 1000);
    const minutes = Math.floor(elapsedTime / 60);
    const seconds = elapsedTime % 60;

    // Исправляем шаблонные строки
    timeElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    killsElement.textContent = kills;

    ammoElement.textContent = isReloading ? 'Перезарядка...' : `${currentAmmo}/${String.fromCharCode(8734)}`;
}


function updateHealthBar() {
    const healthBar = document.getElementById('health');
    healthBar.style.width = health + '%';
    healthBar.textContent = health + '%';
}

function takeDamage(amount) {
    health -= amount;
    if (health <= 0) {
        health = 0;
        updateHealthBar();
        endGame();
        showDeathModal();
    } else {
        updateHealthBar();
    }
}

function createTreeInstance(positions) {
    const trunkGeometry = new THREE.CylinderGeometry(0.2, 0.2, 2, 8);
    const trunkMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
    const trunkMesh = new THREE.InstancedMesh(trunkGeometry, trunkMaterial, positions.length);

    const leavesGeometry = new THREE.ConeGeometry(1, 2, 8);
    const leavesMaterial = new THREE.MeshBasicMaterial({ color: 0x228B22 });
    const leavesMesh = new THREE.InstancedMesh(leavesGeometry, leavesMaterial, positions.length);

    const dummy = new THREE.Object3D();

    positions.forEach((pos, i) => {
        dummy.position.set(pos.x, pos.y, pos.z);
        dummy.updateMatrix();
        trunkMesh.setMatrixAt(i, dummy.matrix);

        dummy.position.set(pos.x, pos.y + 2, pos.z);
        dummy.updateMatrix();
        leavesMesh.setMatrixAt(i, dummy.matrix);
    });

    return { trunkMesh, leavesMesh };
}


function createEnemy() {
    if (!isGameActive) return;

    const enemy = new THREE.Object3D();

    const enemyTexture = new THREE.TextureLoader().load('https://i.postimg.cc/QC6j7xGC/photo-2024-05-28-17-49-00.jpg');
    const enemyMaterial = new THREE.MeshBasicMaterial({
        map: enemyTexture,
        transparent: true,
        side: THREE.DoubleSide
    });
    const enemyGeometry = new THREE.PlaneGeometry(2, 2);
    const enemyMesh = new THREE.Mesh(enemyGeometry, enemyMaterial);
    enemyMesh.userData.isEnemyMesh = true;

    enemy.add(enemyMesh);

    const sword = createSword();
    sword.position.set(0.5, -0.5, 0);
    sword.userData.initialRotation = sword.rotation.clone();
    sword.userData.isSword = true;
    enemyMesh.add(sword);

    // Устанавливаем начальную позицию врага
    let enemyPosition;
    let attempts = 0;
    do {
        const currentTileX = Math.floor(player.position.x / tileSize);
        const currentTileZ = Math.floor(player.position.z / tileSize);

        const minX = currentTileX * tileSize - tileSize * 2;
        const maxX = (currentTileX + 1) * tileSize + tileSize * 2;
        const minZ = currentTileZ * tileSize - tileSize * 2;
        const maxZ = (currentTileZ + 1) * tileSize + tileSize * 2;

        enemyPosition = new THREE.Vector3(
            Math.random() * (maxX - minX) + minX,
            1,
            Math.random() * (maxZ - minZ) + minZ
        );
        attempts++;
        if (attempts > 10) break;
    } while (enemyPosition.distanceTo(player.position) < 20); // Увеличили дистанцию до 20

    enemy.position.copy(enemyPosition);

    scene.add(enemy);
    enemies.push(enemy);
}


function createSword() {
    const bladeGeometry = new THREE.BoxGeometry(0.05, 1, 0.2);
    const bladeMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
    const blade = new THREE.Mesh(bladeGeometry, bladeMaterial);
    blade.position.set(0, 0.5, 0);

    const hiltGeometry = new THREE.CylinderGeometry(0.05, 0.05, 0.3, 8);
    const hiltMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
    const hilt = new THREE.Mesh(hiltGeometry, hiltMaterial);
    hilt.position.set(0, -0.15, 0);

    const sword = new THREE.Group();
    sword.add(blade);
    sword.add(hilt);

    sword.rotation.order = 'YXZ';

    return sword;
}

function shoot() {
    if (isReloading) {
        return;
    }

    if (currentAmmo > 0) {
        currentAmmo--;
        updateHUD();

        const bulletGeometry = new THREE.SphereGeometry(0.1, 8, 8);
        const bulletMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
        const bullet = new THREE.Mesh(bulletGeometry, bulletMaterial);

        const cameraWorldPosition = new THREE.Vector3();
        camera.getWorldPosition(cameraWorldPosition);

        const cameraWorldDirection = new THREE.Vector3();
        camera.getWorldDirection(cameraWorldDirection);

        bullet.position.copy(cameraWorldPosition).add(cameraWorldDirection.multiplyScalar(1));

        bullet.userData.direction = cameraWorldDirection.clone();

        scene.add(bullet);
        bullets.push(bullet);

        // Показываем дульную вспышку
        muzzleFlash.visible = true;
        muzzleFlash.material.opacity = 1;
        const currentTimeSec = performance.now() / 1000;
        muzzleFlashEndTime = currentTimeSec + 0.05;
    } else {
        reload();
    }
}

function initScene() {
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0x87CEEB);
    scene.fog = new THREE.FogExp2(0x87CEEB, 0.002);

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

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

    // Создаем игрока
    player = new THREE.Object3D();
    player.position.set(0, 1.6, 0);
    scene.add(player);
    player.add(camera);

    // Инициализируем тайлы карты после создания игрока
    generateTilesAroundPlayer();

    // Создаем группу для пистолета
    gunGroup = new THREE.Group();

    const gunGeometry = new THREE.BoxGeometry(0.1, 0.1, 0.5);
    const gunMaterial = new THREE.MeshBasicMaterial({ color: 0x333333 });

    gunBody = new THREE.Mesh(gunGeometry, gunMaterial);
    gunBody.position.set(0, 0, 0);
    gunGroup.add(gunBody);

    const handleGeometry = new THREE.BoxGeometry(0.05, 0.2, 0.1);
    const handleMaterial = new THREE.MeshBasicMaterial({ color: 0x111111 });
    const handle = new THREE.Mesh(handleGeometry, handleMaterial);
    handle.position.set(0, -0.15, -0.2);
    gunGroup.add(handle);

    const magazineGeometry = new THREE.BoxGeometry(0.04, 0.1, 0.1);
    const magazineMaterial = new THREE.MeshBasicMaterial({ color: 0x555555 });
    magazine = new THREE.Mesh(magazineGeometry, magazineMaterial);
    magazine.position.set(0, -0.25, -0.2);
    gunGroup.add(magazine);

    const muzzleFlashGeometry = new THREE.ConeGeometry(0.1, 0.2, 4);
    const muzzleFlashMaterial = new THREE.MeshBasicMaterial({
        color: 0xffaa00,
        transparent: true,
    });
    muzzleFlash = new THREE.Mesh(muzzleFlashGeometry, muzzleFlashMaterial);
    muzzleFlash.position.set(0, 0, -0.25);
    muzzleFlash.rotation.x = Math.PI / 2;
    muzzleFlash.visible = false;
    gunBody.add(muzzleFlash);

    updateGunSkin();

    gunGroup.position.set(0.2, -0.2, -0.5);
    camera.add(gunGroup);
}

// Обработчики событий клавиатуры
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;

const velocity = new THREE.Vector3();
const direction = new THREE.Vector3();

document.addEventListener('keydown', function(event) {
    if (!isGameActive) return;

    // Remove or comment out the blocking code for F5 and F12
    // Now F5 and F12 will function normally

    // Prevent default actions for specific game control keys
    if (
        event.code === 'KeyW' ||
        event.code === 'KeyA' ||
        event.code === 'KeyS' ||
        event.code === 'KeyD' ||
        event.code === 'KeyR'
    ) {
        event.preventDefault();
    }

    // Handle game control keys
    switch (event.code) {
        case 'KeyW':
            moveForward = true;
            break;
        case 'KeyS':
            moveBackward = true;
            break;
        case 'KeyA':
            moveLeft = true;
            break;
        case 'KeyD':
            moveRight = true;
            break;
        case 'KeyR':
            reload();
            break;
        // Include other key cases if necessary
    }
});

document.addEventListener('keyup', function(event) {
    if (!isGameActive) return;

    // Prevent default actions for game control keys when released
    if (
        event.code === 'KeyW' ||
        event.code === 'KeyA' ||
        event.code === 'KeyS' ||
        event.code === 'KeyD'
    ) {
        event.preventDefault();
    }

    switch (event.code) {
        case 'KeyW':
            moveForward = false;
            break;
        case 'KeyS':
            moveBackward = false;
            break;
        case 'KeyA':
            moveLeft = false;
            break;
        case 'KeyD':
            moveRight = false;
            break;
        // Include other key cases if necessary
    }
});

document.addEventListener('mousedown', function(event) {
    if (isGameActive && isLocked && event.button === 0) {
        event.preventDefault();
        isMouseDown = true;
    }
});

document.addEventListener('mouseup', function(event) {
    if (event.button === 0) {
        isMouseDown = false;
    }
});


let isLocked = false;

const pointerLockChange = function () {
    isLocked = document.pointerLockElement === document.body;
};

document.addEventListener('pointerlockchange', pointerLockChange, false);

document.addEventListener('click', function () {
    if (isGameActive && !isLocked) {
        document.body.requestPointerLock();
    }
}, false);

document.addEventListener('mousemove', function (event) {
    if (isLocked && isGameActive) {
        const movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
        const movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;

        player.rotation.y -= movementX * 0.002;
        camera.rotation.x -= movementY * 0.002;
        camera.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, camera.rotation.x));
    }
}, false);
let prevTime = performance.now();
// Обновлённая функция animate
function animate() {
    requestAnimationFrame(animate);

    const time = performance.now();
    const delta = (time - prevTime) / 1000; // Переводим время в секунды
    prevTime = time;

    const prevPosition = player.position.clone();

    // Обновляем скорость движения игрока
    velocity.x -= velocity.x * 10.0 * delta;
    velocity.z -= velocity.z * 10.0 * delta;

    direction.z = Number(moveForward) - Number(moveBackward);
    direction.x = Number(moveLeft) - Number(moveRight);
    direction.normalize();

    const speed = 150.0;
    if (moveForward || moveBackward) velocity.z -= direction.z * speed * delta;
    if (moveLeft || moveRight) velocity.x -= direction.x * speed * delta;

    player.translateX(velocity.x * delta);
    player.translateZ(velocity.z * delta);

    // Если хотите ограничить позицию игрока границами предварительно загруженной карты:
    // const mapBoundary = window.preloadTileRange * tileSize;
    // player.position.x = Math.max(-mapBoundary, Math.min(mapBoundary, player.position.x));
    // player.position.z = Math.max(-mapBoundary, Math.min(mapBoundary, player.position.z));

    // Генерация тайлов вокруг игрока
    if (isGameActive) {
        generateTilesAroundPlayer();
    }

    // Обработка столкновений с деревьями
    let collisionDetected = false;

    const playerPositionXZ = new THREE.Vector2(player.position.x, player.position.z);

    for (let i = 0; i < trees.length; i++) {
        const tree = trees[i];
        const treePositionXZ = new THREE.Vector2(tree.x, tree.z);
        const distance = playerPositionXZ.distanceTo(treePositionXZ);
        if (distance < 1.5) {
            collisionDetected = true;
            break;
        }
    }

    if (collisionDetected) {
        player.position.copy(prevPosition);
    }

    // Механизм стрельбы
    if (isGameActive && isMouseDown) {
        const currentTimeSec = time / 1000;
        if (currentTimeSec - lastShotTime >= shotInterval) {
            shoot();
            lastShotTime = currentTimeSec;
        }
    }

    // Обновление положения пуль и проверка столкновений
    if (isGameActive) {
        for (let i = bullets.length - 1; i >= 0; i--) {
            const bullet = bullets[i];
            bullet.position.add(
                bullet.userData.direction.clone().multiplyScalar(bulletSpeed * delta)
            );

            // Проверяем столкновение пули с врагами поблизости
            let bulletHit = false;
            for (let j = enemies.length - 1; j >= 0; j--) {
                const enemy = enemies[j];
                const distanceToEnemy = bullet.position.distanceTo(enemy.position);
                if (distanceToEnemy < 1.5) {
                    scene.remove(enemy);
                    enemies.splice(j, 1);

                    scene.remove(bullet);
                    bullets.splice(i, 1);

                    kills++;
                    updateHUD();

                    bulletHit = true;
                    break;
                }
            }

            if (bulletHit) continue;

            // Удаляем пули, которые улетели слишком далеко
            if (bullet.position.length() > 5000) {
                scene.remove(bullet);
                bullets.splice(i, 1);
            }
        }
    }

    // Обновление положения врагов и их поведение
    if (isGameActive) {
        const enemyUpdateDistance = 500; // Дистанция, внутри которой враги активно обновляются
        const maxEnemyDistance = 1000;   // Дистанция, за пределами которой враги удаляются

        for (let i = enemies.length - 1; i >= 0; i--) {
            const enemy = enemies[i];
            const distanceToPlayer = enemy.position.distanceTo(player.position);

            if (distanceToPlayer < enemyUpdateDistance) {
                // Обновление поведения врага (движение, поворот, атака)
                let enemyDirection = new THREE.Vector3();
                enemyDirection.subVectors(
                    player.position.clone().setY(0),
                    enemy.position.clone().setY(0)
                );
                enemyDirection.normalize();

                let avoidDirection = new THREE.Vector3(0, 0, 0);
                let isObstacleDetected = false;

                // Обход препятствий (деревья)
                for (let j = 0; j < trees.length; j++) {
                    const tree = trees[j];
                    const distanceToTree = enemy.position.distanceTo(tree);
                    if (distanceToTree < 3) {
                        let f = new THREE.Vector3();
                        f.subVectors(enemy.position, tree);
                        f.y = 0;
                        f.normalize();
                        f.divideScalar(distanceToTree);
                        avoidDirection.add(f);
                        isObstacleDetected = true;
                    }
                }

                if (isObstacleDetected) {
                    avoidDirection.normalize();
                    enemyDirection.add(avoidDirection);
                    enemyDirection.normalize();
                }

                // Обновляем позицию врага
                enemy.position.addScaledVector(enemyDirection, enemySpeed * delta);
                enemy.position.y = 1; // Фиксируем высоту врага

                // Поворот врага в сторону игрока
                enemy.traverse(function(child) {
                    if (child.userData.isEnemyMesh) {
                        const enemyPositionWorld = new THREE.Vector3();
                        child.getWorldPosition(enemyPositionWorld);
                        const cameraPositionWorld = new THREE.Vector3();
                        camera.getWorldPosition(cameraPositionWorld);

                        const dx = cameraPositionWorld.x - enemyPositionWorld.x;
                        const dz = cameraPositionWorld.z - enemyPositionWorld.z;
                        const angle = Math.atan2(dx, dz);

                        child.rotation.set(0, angle, 0);
                    }

                    // Обновляем позицию и поворот меча
                    if (child.userData.isSword) {
                        child.rotation.copy(child.userData.initialRotation);
                    }
                });

                // Проверка на столкновение с игроком
                if (distanceToPlayer < 1.5) {
                    takeDamage(10);
                }
            }

            // Удаляем врагов, находящихся слишком далеко от игрока
            if (distanceToPlayer > maxEnemyDistance) {
                scene.remove(enemy);
                enemies.splice(i, 1);
            }
        }
    }

    updateHUD();

    // Обновление дульной вспышки
    const currentTimeSec = time / 1000;
    if (currentTimeSec >= muzzleFlashEndTime) {
        muzzleFlash.visible = false;
    } else {
        muzzleFlash.visible = true;
        const remainingTime = muzzleFlashEndTime - currentTimeSec;
        muzzleFlash.material.opacity = remainingTime / 0.05;
    }

    // Анимация перезарядки
    if (isAnimatingReload) {
        reloadAnimationProgress += delta;

        const halfDuration = reloadAnimationDuration / 2;

        if (reloadAnimationProgress <= halfDuration) {
            const t = reloadAnimationProgress / halfDuration;
            magazine.position.y = THREE.MathUtils.lerp(-0.25, -0.5, t);
        } else if (reloadAnimationProgress <= reloadAnimationDuration) {
            const t = (reloadAnimationProgress - halfDuration) / halfDuration;
            magazine.position.y = THREE.MathUtils.lerp(-0.5, -0.25, t);
        } else {
            magazine.position.y = -0.25;
            isAnimatingReload = false;
            currentAmmo = magazineSize;
            isReloading = false;
            updateHUD();
        }
    }

    renderer.render(scene, camera);
}


// Функция для генерации тайлов вокруг игрока
function generateTilesAroundPlayer() {
    const playerTileX = Math.floor(player.position.x / tileSize);
    const playerTileZ = Math.floor(player.position.z / tileSize);

    const range = 2; // Радиус генерации тайлов вокруг игрока

    const preloadTileRange = window.preloadTileRange; // Радиус предварительно загруженной области в тайлах

    for (let x = playerTileX - range; x <= playerTileX + range; x++) {
        for (let z = playerTileZ - range; z <= playerTileZ + range; z++) {
            const tileKey = `${x},${z}`;
            const distanceToCenter = Math.max(Math.abs(x), Math.abs(z));

            if (!tiles[tileKey] && distanceToCenter > preloadTileRange) {
                createTile(x, z);
            }
        }
    }

    // Удаляем тайлы, которые находятся слишком далеко
    for (let key in tiles) {
        const [tileX, tileZ] = key.split(',').map(Number);
        const distanceToPlayer = Math.max(Math.abs(tileX - playerTileX), Math.abs(tileZ - playerTileZ));
        const distanceToCenter = Math.max(Math.abs(tileX), Math.abs(tileZ));

        if (distanceToPlayer > range + 2 && distanceToCenter > preloadTileRange) {
            removeTile(tileX, tileZ);
        }
    }
}
function createEnemyInTile(tileX, tileZ) {
    if (!isGameActive) return;

    // Ограничиваем общее количество врагов, чтобы предотвратить перегрузку
    const maxTotalEnemies = 200; // Настройте по необходимости
    if (enemies.length >= maxTotalEnemies) return;

    const enemy = new THREE.Object3D();

    const enemyTexture = new THREE.TextureLoader().load(
        'https://i.postimg.cc/QC6j7xGC/photo-2024-05-28-17-49-00.jpg'
    );
    const enemyMaterial = new THREE.MeshBasicMaterial({
        map: enemyTexture,
        transparent: true,
        side: THREE.DoubleSide,
    });
    const enemyGeometry = new THREE.PlaneGeometry(2, 2);
    const enemyMesh = new THREE.Mesh(enemyGeometry, enemyMaterial);

    enemyMesh.userData.isEnemyMesh = true;

    enemy.add(enemyMesh);

    const sword = createSword();
    sword.position.set(0.5, -0.5, 0);
    sword.userData.initialRotation = sword.rotation.clone();
    sword.userData.isSword = true;
    enemyMesh.add(sword);

    // Устанавливаем случайную позицию внутри тайла
    const minX = tileX * tileSize;
    const maxX = minX + tileSize;
    const minZ = tileZ * tileSize;
    const maxZ = minZ + tileSize;

    enemy.position.x = Math.random() * (maxX - minX) + minX;
    enemy.position.z = Math.random() * (maxZ - minZ) + minZ;
    enemy.position.y = 1; // Устанавливаем корректную высоту

    scene.add(enemy);
    enemies.push(enemy);
}



// Функция для создания тайла
function createTile(x, z) {
    const tileGeometry = new THREE.PlaneGeometry(tileSize, tileSize);
    const tileMaterial = new THREE.MeshBasicMaterial({ color: 0x228B22 });
    const tile = new THREE.Mesh(tileGeometry, tileMaterial);
    tile.rotation.x = -Math.PI / 2;
    tile.position.set(
        x * tileSize + tileSize / 2,
        0,
        z * tileSize + tileSize / 2
    );
    scene.add(tile);

    tileMeshes[`${x},${z}`] = tile;
    tiles[`${x},${z}`] = true;

    // Генерация деревьев на тайле
    const numTrees = 9;
    const positions = [];
    for (let i = 0; i < numTrees; i++) {
        const treeX = x * tileSize + Math.random() * tileSize;
        const treeZ = z * tileSize + Math.random() * tileSize;
        positions.push(new THREE.Vector3(treeX, 0, treeZ));
    }

    const { trunkMesh, leavesMesh } = createTreeInstance(positions);
    scene.add(trunkMesh);
    scene.add(leavesMesh);
    trees.push(...positions);

    treeInstances[`${x},${z}`] = { trunkMesh, leavesMesh, positions };

    // Генерация врагов на тайле
    const enemiesPerTile = 4; // Настраивайте по необходимости
    for (let i = 0; i < enemiesPerTile; i++) {
        createEnemyInTile(x, z);
    }
}



// Функция для удаления тайла
function removeTile(x, z) {
    const tileKey = `${x},${z}`;
    const tile = tileMeshes[tileKey];
    if (tile) {
        scene.remove(tile);
        delete tileMeshes[tileKey];
    }

    const treeInstance = treeInstances[tileKey];
    if (treeInstance) {
        scene.remove(treeInstance.trunkMesh);
        scene.remove(treeInstance.leavesMesh);

        treeInstance.positions.forEach(pos => {
            const index = trees.findIndex(treePos => treePos.equals(pos));
            if (index > -1) {
                trees.splice(index, 1);
            }
        });

        delete treeInstances[tileKey];
    }

    // Удаляем врагов, находящихся на этом тайле
    for (let i = enemies.length - 1; i >= 0; i--) {
        const enemy = enemies[i];
        const enemyTileX = Math.floor(enemy.position.x / tileSize);
        const enemyTileZ = Math.floor(enemy.position.z / tileSize);
        if (enemyTileX === x && enemyTileZ === z) {
            scene.remove(enemy);
            enemies.splice(i, 1);
        }
    }

    delete tiles[tileKey];
}
function preloadMap(callback) {
    const loadingProgress = document.getElementById('loading-progress');

    const preloadRadius = window.preloadRadius; // Должен быть определен глобально в startGame()
    const tileRange = Math.ceil(preloadRadius / tileSize); // Количество тайлов от центра до края

    const totalTiles = (2 * tileRange + 1) * (2 * tileRange + 1);
    let tilesLoaded = 0;

    let x = -tileRange;
    let z = -tileRange;

    function generateNextTile() {
        if (x > tileRange) {
            // Загрузка завершена
            callback();
            return;
        }

        const tileKey = `${x},${z}`;
        if (!tiles[tileKey]) {
            createTile(x, z);
            tilesLoaded++;

            // Обновляем прогресс загрузки
            const progress = Math.floor((tilesLoaded / totalTiles) * 100);
            loadingProgress.textContent = `${progress}%`;
        }

        z++;
        if (z > tileRange) {
            z = -tileRange;
            x++;
        }

        // Планируем генерацию следующего тайла, чтобы избежать блокировки UI
        setTimeout(generateNextTile, 0);
    }

    generateNextTile();
}
function startGame() {
    const menu = document.getElementById('menu');
    menu.style.display = 'none';

    const deathModal = document.getElementById('death-modal');
    deathModal.style.display = 'none';

    // Показываем экран загрузки
    const loadingModal = document.getElementById('loading-modal');
    loadingModal.style.display = 'flex';
    document.getElementById('loading-progress').textContent = '0%';

    kills = 0;
    health = 100;
    updateHealthBar();
    updateHUD();

    currentAmmo = magazineSize;
    isReloading = false;
    isAnimatingReload = false;
    reloadAnimationProgress = 0;
    updateHUD();

    // Очищаем объекты игры
    clearGameObjects();

    // Сбрасываем позицию и поворот игрока и камеры
    player.position.copy(getRandomSpawnPosition());
    player.rotation.set(0, 0, 0);
    camera.rotation.set(0, 0, 0);

    velocity.x = 0;
    velocity.y = 0;
    velocity.z = 0;

    gameStartTime = new Date().getTime();

    isGameActive = true;

    enemySpeed = 5.0;

    enemies.length = 0; // Очищаем массив врагов

    // Устанавливаем радиус предварительной загрузки глобально, чтобы он был доступен в других местах
    window.preloadRadius = 10000; // Единицы измерения
    window.preloadTileRange = Math.ceil(preloadRadius / tileSize);

    // Начинаем предварительную загрузку карты
    preloadMap(() => {
        // Скрываем экран загрузки
        loadingModal.style.display = 'none';

        // Показываем HUD и прицел
        document.getElementById('hud').style.display = 'block';
        document.getElementById('health-bar').style.display = 'block';
        document.getElementById('crosshair').style.display = 'block';

        // Активируем управление мышью
        document.body.requestPointerLock();

        // Начинаем обновлять тайлы вокруг игрока
        if (isGameActive) {
            generateTilesAroundPlayer();
        }
    });
}

function endGame() {
    isGameActive = false;

    document.exitPointerLock();

    document.getElementById('crosshair').style.display = 'none'; // Скрываем прицел

    if (kills > killsRecord) {
        killsRecord = kills;
        saveProgress();
    }

    if (killsRecord >= 1000) {
        skins.golden.unlocked = true;
        saveSkins();
    }

    updateMenu();
}

function clearGameObjects() {
    // Удаляем врагов
    enemies.forEach(enemy => scene.remove(enemy));
    enemies.length = 0;

    // Удаляем пули
    bullets.forEach(bullet => scene.remove(bullet));
    bullets.length = 0;

    // Удаляем тайлы и деревья
    for (let key in tileMeshes) {
        scene.remove(tileMeshes[key]);
    }
    for (let key in treeInstances) {
        scene.remove(treeInstances[key].trunkMesh);
        scene.remove(treeInstances[key].leavesMesh);
    }
    tiles = {};
    tileMeshes = {};
    treeInstances = {};
    trees.length = 0;
}

const restartButton = document.getElementById('restartButton');
const returnToMenuButton = document.getElementById('returnToMenuButton');

restartButton.addEventListener('click', function(event) {
    event.stopPropagation();
    const deathModal = document.getElementById('death-modal');
    deathModal.style.display = 'none';

    startGame();
});

returnToMenuButton.addEventListener('click', function(event) {
    event.stopPropagation();
    const deathModal = document.getElementById('death-modal');
    deathModal.style.display = 'none';

    document.getElementById('crosshair').style.display = 'none'; // Скрываем прицел

    // Показываем главное меню
    const menu = document.getElementById('menu');
    menu.style.display = 'flex';

    // Скрываем HUD и полосу здоровья
    document.getElementById('hud').style.display = 'none';
    document.getElementById('health-bar').style.display = 'none';

    // Очищаем объекты игры
    clearGameObjects();

    isGameActive = false;
});

const playButton = document.getElementById('playButton');
playButton.addEventListener('click', function(event) {
    event.stopPropagation();
    startGame();
});

window.addEventListener('resize', function() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}, false);

// Инициализация игры
loadProgress();
loadSkins();
initScene();
updateGunSkin();
updateMenu();
updateHealthBar();
updateHUD();
animate();
</script>
<div id="version">Версия 0.0.0.6(bug-fix)</div>
</body>
</html>
загрузка долгая должна быть быстрая и чтоб поялялось было видно что загружается а также почему-то в меню пропала земля у игрока а также во время загрузки могу стрелять и ходить