Загрузка данных


<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GTA Browser Pro - Living City</title>
    <style>
        body { margin: 0; overflow: hidden; font-family: 'Arial Black', sans-serif; background: #87CEEB; }
        #hud {
            position: absolute; top: 20px; right: 20px; text-align: right;
            color: #2ecc71; font-size: 32px; font-weight: 900; text-shadow: 3px 3px #000;
        }
        #wanted { color: #f1c40f; font-size: 45px; letter-spacing: 2px; }
        #speed-ui { color: white; font-size: 22px; background: rgba(0,0,0,0.5); padding: 8px 15px; border-radius: 10px; margin-top: 10px; }
        .controls {
            position: absolute; bottom: 20px; left: 20px; color: #fff; font-size: 13px;
            background: rgba(0,0,0,0.7); padding: 15px; border-radius: 10px; pointer-events: none; border: 2px solid #3498db;
        }
        #crosshair {
            position: absolute; top: 50%; left: 50%; width: 8px; height: 8px;
            background: rgba(255, 255, 255, 0.8); border: 2px solid #ff0000; border-radius: 50%; transform: translate(-50%, -50%);
        }
    </style>
</head>
<body>

    <div id="crosshair"></div>
    <div id="hud">
        <div id="money">$00000000</div>
        <div id="wanted"></div>
        <div id="speed-ui">0 KM/H</div>
    </div>

    <div class="controls">
        <b style="color: #3498db; font-size: 16px;">ГТА ОНЛАЙН (BROWSER)</b><br><br>
        <b>WASD</b> - Движение | <b>SPACE</b> - РУЧНИК/ДРИФТ<br>
        <b>F</b> - ВХОД/ВЫХОД | <b>ЛКМ</b> - ОГОНЬ<br>
        <b>МЫШКА</b> - ОБЗОР 360° | <b>R</b> - РЕСТАРТ
    </div>

    <script type="importmap">
        { "imports": { "three": "https://unpkg.com/three@0.160.0/build/three.module.js" } }
    </script>

    <script type="module">
        import * as THREE from 'three';

        let scene, camera, renderer, clock;
        let player, car, npcs = [], police = [];
        let isInsideCar = false;
        let keys = {};
        let stats = { money: 0, wanted: 0 };
        const buildings = [];
        const bullets = [];
        
        let cameraAngleX = 0;
        let cameraAngleY = 0.3;

        init();
        animate();

        function init() {
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x87CEEB); 
            scene.fog = new THREE.Fog(0x87CEEB, 50, 400);
            
            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000);
            clock = new THREE.Clock();

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

            // МАКСИМАЛЬНЫЙ СВЕТ
            const ambient = new THREE.AmbientLight(0xffffff, 1.2);
            scene.add(ambient);
            const sun = new THREE.DirectionalLight(0xffffff, 1.8);
            sun.position.set(150, 300, 100);
            sun.castShadow = true;
            scene.add(sun);

            createCity();

            // СОЗДАНИЕ ИГРОКА (УЛУЧШЕННЫЙ)
            player = createHuman(0x3498db);
            scene.add(player);

            // МАШИНА
            car = createCar();
            car.position.set(10, 0, 15);
            scene.add(car);
            car.userData = { speed: 0, maxSpeed: 2.2, accel: 0.05, angle: 0 };

            // СПАВН ПЕШЕХОДОВ
            for(let i = 0; i < 50; i++) {
                spawnNPC();
            }

            document.addEventListener('mousemove', (e) => {
                if (document.pointerLockElement === document.body) {
                    cameraAngleX -= e.movementX * 0.005;
                    cameraAngleY = Math.max(0.1, Math.min(1.2, cameraAngleY + e.movementY * 0.005));
                }
            });

            document.addEventListener('mousedown', () => {
                document.body.requestPointerLock();
                shoot();
            });

            window.addEventListener('keydown', e => { 
                keys[e.code] = true; 
                if(e.code === 'KeyF') toggleCar();
                if(e.code === 'KeyR') location.reload();
            });
            window.addEventListener('keyup', e => keys[e.code] = false);
        }

        function createHuman(shirtColor) {
            const group = new THREE.Group();
            // Тело
            const torso = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.8, 0.3), new THREE.MeshStandardMaterial({color: shirtColor}));
            torso.position.y = 1.0;
            // Голова
            const head = new THREE.Mesh(new THREE.BoxGeometry(0.35, 0.35, 0.35), new THREE.MeshStandardMaterial({color: 0xffdbac}));
            head.position.y = 1.6;
            // Ноги
            const legGeo = new THREE.BoxGeometry(0.25, 0.6, 0.25);
            const legMat = new THREE.MeshStandardMaterial({color: 0x111111});
            const legL = new THREE.Mesh(legGeo, legMat);
            legL.position.set(-0.15, 0.3, 0);
            const legR = new THREE.Mesh(legGeo, legMat);
            legR.position.set(0.15, 0.3, 0);
            // Руки
            const armGeo = new THREE.BoxGeometry(0.2, 0.7, 0.2);
            const armL = new THREE.Mesh(armGeo, new THREE.MeshStandardMaterial({color: 0xffdbac}));
            armL.position.set(-0.45, 1.0, 0);
            const armR = new THREE.Mesh(armGeo, new THREE.MeshStandardMaterial({color: 0xffdbac}));
            armR.position.set(0.45, 1.0, 0);

            group.add(torso, head, legL, legR, armL, armR);
            return group;
        }

        function createCar() {
            const g = new THREE.Group();
            const body = new THREE.Mesh(new THREE.BoxGeometry(2.2, 0.7, 4.5), new THREE.MeshStandardMaterial({color: 0xc0392b}));
            body.position.y = 0.6;
            const roof = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.6, 2.2), new THREE.MeshStandardMaterial({color: 0x222222}));
            roof.position.set(0, 1.2, -0.2);
            // Колеса
            const wGeo = new THREE.CylinderGeometry(0.45, 0.45, 0.4, 16);
            const wMat = new THREE.MeshStandardMaterial({color: 0x111111});
            [[-1.1, 0.4, 1.5], [1.1, 0.4, 1.5], [-1.1, 0.4, -1.5], [1.1, 0.4, -1.5]].forEach(p => {
                const w = new THREE.Mesh(wGeo, wMat);
                w.rotation.z = Math.PI/2;
                w.position.set(...p);
                g.add(w);
            });
            g.add(body, roof);
            return g;
        }

        function createCity() {
            const ground = new THREE.Mesh(new THREE.PlaneGeometry(3000, 3000), new THREE.MeshStandardMaterial({color: 0x444444}));
            ground.rotation.x = -Math.PI/2;
            scene.add(ground);

            for(let i = -12; i < 12; i++) {
                for(let j = -12; j < 12; j++) {
                    if(Math.abs(i) < 2 && Math.abs(j) < 2) continue;
                    const h = 10 + Math.random() * 80;
                    const b = new THREE.Mesh(
                        new THREE.BoxGeometry(20, h, 20), 
                        new THREE.MeshStandardMaterial({color: new THREE.Color().setHSL(Math.random(), 0.2, 0.5)})
                    );
                    b.position.set(i * 55, h/2, j * 55);
                    scene.add(b);
                    buildings.push(b);
                }
            }
        }

        function spawnNPC() {
            const npc = createHuman(Math.random() * 0xffffff);
            npc.position.set((Math.random()-0.5)*400, 0, (Math.random()-0.5)*400);
            npc.userData = { 
                targetAngle: Math.random() * Math.PI * 2,
                timer: Math.random() * 100
            };
            scene.add(npc);
            npcs.push(npc);
        }

        function toggleCar() {
            const d = player.position.distanceTo(car.position);
            if(!isInsideCar && d < 6) {
                isInsideCar = true;
                player.visible = false;
            } else if(isInsideCar) {
                isInsideCar = false;
                player.visible = true;
                player.position.copy(car.position).add(new THREE.Vector3(3, 0, 0));
            }
        }

        function shoot() {
            const b = new THREE.Mesh(new THREE.SphereGeometry(0.2), new THREE.MeshBasicMaterial({color: 0xffff00}));
            const dir = new THREE.Vector3();
            camera.getWorldDirection(dir);
            b.position.copy(isInsideCar ? car.position : player.position).add(new THREE.Vector3(0, 1.5, 0));
            bullets.push({ mesh: b, dir: dir, life: 100 });
            scene.add(b);
            
            // Проверка попадания в NPC
            npcs.forEach((npc, idx) => {
                if(b.position.distanceTo(npc.position) < 3) {
                    stats.money += 100;
                    stats.wanted = Math.min(stats.wanted + 1, 5);
                }
            });
        }

        function checkWall(pos, radius) {
            const pBox = new THREE.Box3().setFromCenterAndSize(pos, new THREE.Vector3(radius, 2, radius));
            for(let b of buildings) {
                if(pos.distanceTo(b.position) < 25) {
                    const bBox = new THREE.Box3().setFromObject(b);
                    if(bBox.intersectsBox(pBox)) return true;
                }
            }
            return false;
        }

        function handlePhysics() {
            if(isInsideCar) {
                const isDrifting = keys['Space'];
                const turnSpeed = isDrifting ? 0.09 : 0.05;
                const friction = isDrifting ? 0.95 : 0.985;

                if(keys['KeyW']) car.userData.speed = Math.min(car.userData.speed + car.userData.accel, car.userData.maxSpeed);
                if(keys['KeyS']) car.userData.speed = Math.max(car.userData.speed - car.userData.accel, -0.7);
                car.userData.speed *= friction;

                if(Math.abs(car.userData.speed) > 0.1) {
                    if(keys['KeyA']) car.rotation.y += turnSpeed;
                    if(keys['KeyD']) car.rotation.y -= turnSpeed;
                }

                const nextPos = car.position.clone();
                nextPos.x += Math.sin(car.rotation.y) * car.userData.speed;
                nextPos.z += Math.cos(car.rotation.y) * car.userData.speed;

                if(!checkWall(nextPos, 3.5)) {
                    car.position.copy(nextPos);
                } else {
                    car.userData.speed *= -0.4;
                }
                player.position.copy(car.position);

                // Давим пешеходов
                npcs.forEach(npc => {
                    if(npc.position.distanceTo(car.position) < 3) {
                        npc.position.y = -5; // "Убираем"
                        stats.money += 50;
                        stats.wanted = Math.min(stats.wanted + 1, 5);
                    }
                });
            } else {
                const nextPos = player.position.clone();
                player.rotation.y = cameraAngleX;
                const moveSpeed = 0.35;
                if(keys['KeyW']) {
                    nextPos.x += Math.sin(player.rotation.y) * moveSpeed;
                    nextPos.z += Math.cos(player.rotation.y) * moveSpeed;
                }
                if(keys['KeyS']) {
                    nextPos.x -= Math.sin(player.rotation.y) * moveSpeed;
                    nextPos.z -= Math.cos(player.rotation.y) * moveSpeed;
                }
                if(!checkWall(nextPos, 1.2)) player.position.copy(nextPos);
            }

            // Логика NPC
            npcs.forEach(npc => {
                npc.userData.timer--;
                if(npc.userData.timer <= 0) {
                    npc.userData.targetAngle = Math.random() * Math.PI * 2;
                    npc.userData.timer = 100 + Math.random() * 200;
                }
                npc.rotation.y = THREE.MathUtils.lerp(npc.rotation.y, npc.userData.targetAngle, 0.05);
                const nextNpcPos = npc.position.clone();
                nextNpcPos.x += Math.sin(npc.rotation.y) * 0.05;
                nextNpcPos.z += Math.cos(npc.rotation.y) * 0.05;
                if(!checkWall(nextNpcPos, 1)) npc.position.copy(nextNpcPos);
            });
        }

        function animate() {
            requestAnimationFrame(animate);
            handlePhysics();

            bullets.forEach((b, i) => {
                b.mesh.position.addScaledVector(b.dir, 2.5);
                b.life--;
                if(b.life <= 0) {
                    scene.remove(b.mesh);
                    bullets.splice(i, 1);
                }
            });

            const target = isInsideCar ? car : player;
            const dist = isInsideCar ? 18 : 10;
            camera.position.x = target.position.x - Math.sin(cameraAngleX) * dist;
            camera.position.z = target.position.z - Math.cos(cameraAngleX) * dist;
            camera.position.y = target.position.y + cameraAngleY * dist;
            camera.lookAt(target.position.clone().add(new THREE.Vector3(0, 1.5, 0)));

            document.getElementById('money').innerText = "$" + stats.money.toString().padStart(8, '0');
            document.getElementById('wanted').innerText = "★".repeat(stats.wanted);
            document.getElementById('speed-ui').innerText = isInsideCar ? Math.round(Math.abs(car.userData.speed) * 160) + " KM/H" : "ON FOOT";

            renderer.render(scene, camera);
        }
    </script>
</body>
</html>