/* ===== АВТО-РЕЖИМ: выбор транспорта + езда на ported reVC-физике (client) ===== */ var carMode = false, carObj = null, carMesh = null, carGround = null, carAcc = 0, carPreset = 'brovenosec'; var carMesh_wheels = []; var carHeadlights = []; var CAR_SPAWN = { x: 70, z: -40 }; function buildCarMesh() { var h = carObj.h; var g = new THREE.Group(); var L = h.Dimension.y, Wd = h.Dimension.x, Ht = h.Dimension.z; var body = new THREE.Mesh(new THREE.BoxGeometry(Wd, Ht * 0.6, L), new THREE.MeshStandardMaterial({ color: 0xc81e3a, roughness: 0.45, metalness: 0.3 })); body.position.y = Ht * 0.15; g.add(body); var cab = new THREE.Mesh(new THREE.BoxGeometry(Wd * 0.86, Ht * 0.5, L * 0.5), new THREE.MeshStandardMaterial({ color: 0x20242c, roughness: 0.3, metalness: 0.4 })); cab.position.set(0, Ht * 0.55, -L * 0.05); g.add(cab); var nose = new THREE.Mesh(new THREE.BoxGeometry(Wd * 0.5, Ht * 0.2, 0.3), new THREE.MeshStandardMaterial({ color: 0xffd23a, emissive: 0x442200 })); nose.position.set(0, Ht * 0.1, L * 0.5); g.add(nose); // жёлтый нос = вперёд (+Z) // фары — area lights (LTC, как у дрона): светят вперёд (+Z) и чуть вниз на дорогу var hlX = Wd * 0.34, hlY = Ht * 0.16, hlZ = L * 0.5 + 0.04; var lensMat = new THREE.MeshStandardMaterial({ color: 0xfff6d8, emissive: 0xfff0b0, emissiveIntensity: 2.6, roughness: 0.25, metalness: 0.0 }); carHeadlights = []; for (var hi = 0; hi < 2; hi++) { var sx = hi === 0 ? -1 : 1; var lens = new THREE.Mesh(new THREE.BoxGeometry(Wd * 0.26, Ht * 0.18, 0.10), lensMat); lens.position.set(sx * hlX, hlY, hlZ); g.add(lens); var hl = new THREE.RectAreaLight(0xfff2cc, 11.0, Wd * 0.55, Ht * 0.42); hl.position.set(sx * hlX, hlY, hlZ + 0.06); hl.rotation.set(Math.PI + 0.16, 0, 0); // локальный -Z -> +Z (вперёд), лёгкий наклон вниз g.add(hl); carHeadlights.push(hl); } var wr = carObj.wheelRadius; var wheelGeo = new THREE.CylinderGeometry(wr, wr, 0.3, 16); var wheelMat = new THREE.MeshStandardMaterial({ color: 0x111214, roughness: 0.85 }); carMesh_wheels = []; for (var i = 0; i < 4; i++) { var w = new THREE.Mesh(wheelGeo, wheelMat); var pb = carObj.m_wheelPosBody[i]; w.position.set(pb.x, pb.y, pb.z); w.rotation.set(0, 0, Math.PI / 2); // ось колеса вдоль X g.add(w); carMesh_wheels.push(w); } return g; } function spawnCar() { var CP = window.PZCarPhys; var hd = CP.makeHandling(CP.PRESETS[carPreset]); carGround = CP.makeGround(groundH, WATER_Y, { patch: 1.5 }); var gy = groundH(CAR_SPAWN.x, CAR_SPAWN.z); carObj = new CP.Car(hd, { x: CAR_SPAWN.x, y: gy + 2.0, z: CAR_SPAWN.z, heading: 0 }); carMesh = buildCarMesh(); scene.add(carMesh); try { window.PZCAR = carObj; } catch(e){} } function readCarInput() { var th = 0, st = 0; if (keys['KeyW'] || keys['ArrowUp']) th += 1; if (keys['KeyS'] || keys['ArrowDown']) th -= 1; if (keys['KeyA'] || keys['ArrowLeft']) st += 1; // руль влево (исправлено: влево/вправо было перепутано) if (keys['KeyD'] || keys['ArrowRight']) st -= 1; // руль вправо return { throttle: th, steer: st, handbrake: !!keys['Space'], brakeHeld: (th < 0) }; } var _cbR = new THREE.Vector3(), _cbU = new THREE.Vector3(), _cbF = new THREE.Vector3(), _cbM = new THREE.Matrix4(); function carRespawn() { var CP = window.PZCarPhys, gy = groundH(CAR_SPAWN.x, CAR_SPAWN.z); carObj.pos = CP._v(CAR_SPAWN.x, gy + 2.0, CAR_SPAWN.z); carObj.moveSpeed = CP._v(0, 0, 0); carObj.turnSpeed = CP._v(0, 0, 0); carObj.setHeading(0); } function carStep(dt) { if (!carObj) return; if (keys['KeyR']) carRespawn(); var inp = readCarInput(); carAcc += dt; var n = 0; while (carAcc >= 0.02 && n < 6) { carObj.step(inp, carGround); carAcc -= 0.02; n++; } // фиксированные 50 Гц carMesh.position.set(carObj.pos.x, carObj.pos.y, carObj.pos.z); _cbR.set(carObj.right.x, carObj.right.y, carObj.right.z); _cbU.set(carObj.up.x, carObj.up.y, carObj.up.z); _cbF.set(carObj.fwd.x, carObj.fwd.y, carObj.fwd.z); _cbM.makeBasis(_cbR, _cbU, _cbF); carMesh.quaternion.setFromRotationMatrix(_cbM); for (var i = 0; i < 4; i++) { var w = carMesh_wheels[i]; if (!w) continue; var pb = carObj.m_wheelPosBody[i]; w.position.set(pb.x, pb.y, pb.z); var steer = (i < 2) ? carObj.m_fSteerAngle : 0; // FL,FR поворачиваются w.rotation.set(0, -steer, Math.PI / 2); } } var _carGoal = new THREE.Vector3(), _carLook = new THREE.Vector3(); function carCamera() { controls.enabled = false; _cbF.set(carObj.fwd.x, 0, carObj.fwd.z); if (_cbF.lengthSq() < 1e-4) _cbF.set(0, 0, 1); _cbF.normalize(); _carGoal.set(carObj.pos.x, carObj.pos.y, carObj.pos.z).addScaledVector(_cbF, -12).addScaledVector(WUP, 5.5); camera.position.lerp(_carGoal, 0.12); _carLook.set(carObj.pos.x, carObj.pos.y + 1.3, carObj.pos.z); _camLook.lerp(_carLook, 0.3); camera.lookAt(_camLook); } /* --- стартовый выбор транспорта --- */ (function vehicleSelect() { var ov = document.createElement('div'); ov.id = 'vsOverlay'; ov.style.cssText = 'position:fixed;inset:0;z-index:10050;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(4,6,12,.88);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);font-family:system-ui,Segoe UI,Roboto,sans-serif;color:#eef3ff'; ov.innerHTML = '
ПЛАНЕТА ЖОПА
' + '
На чём поедешь?
' + '
' + '' + '' + '
' + '
сменить транспорт — перезагрузка страницы
'; document.body.appendChild(ov); ['pointerdown', 'touchstart', 'mousedown', 'keydown'].forEach(function (ev) { ov.addEventListener(ev, function (e) { e.stopPropagation(); }); }); document.getElementById('vsDrone').onclick = function () { carMode = false; ov.remove(); }; document.getElementById('vsCar').onclick = function () { carMode = true; try { spawnCar(); } catch (e) { console.error('spawnCar', e); } try { if (typeof drone !== 'undefined' && drone) drone.visible = false; } catch (e) {} try { sd.style.display = 'none'; } catch (e) {} try { dp.style.display = 'none'; } catch (e) {} var hp = document.getElementById('help'); if (hp) hp.innerHTML = '🚗 МАШИНА (физика reVC): W газ · S тормоз/задний · A/D руль · Space ручник · R сброс'; ov.remove(); }; })();