Найден корректный robots.txt
Файл управления сканированием сайта роботами
?
Robots.txt указывает поисковым роботам, какие страницы сканировать, а какие — нет. Ошибки в файле могут случайно закрыть важные разделы от индексации.
Robots.txt настроен корректно. Размер файла: 38891 байт. Загружен за: 1сек.
Проверяемая страница не запрещена в robots.txt.
Показать содержимое robots.txt
यह रहा आपका पूरा **Updated 4K Real-World Dubai 3D Game** का कोड:
```html
<!DOCTYPE html>
<html lang="hi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Dubai E11 Sheikh Zayed Road 3D</title>
<!-- Three.js CDN with multiple Fallbacks -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
if (typeof THREE === 'undefined') {
document.write('<script src="https://unpkg.com/three@0.128.0/build/three.min.js"><\/script>');
}
</script>
<script>
if (typeof THREE === 'undefined') {
document.write('<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js"><\/script>');
}
</script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
user-select: none;
-webkit-user-select: none;
}
body {
background-color: #64b5f6;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
overflow: hidden;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
}
#game-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
#top-bar {
position: absolute;
top: 15px;
left: 0;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
z-index: 10;
pointer-events: none;
}
.location-badge {
pointer-events: auto;
background: rgba(15, 23, 42, 0.9);
border: 1.5px solid rgba(251, 191, 36, 0.6);
border-radius: 30px;
padding: 8px 18px;
display: flex;
align-items: center;
gap: 10px;
font-size: 13px;
font-weight: 800;
}
.location-badge .code {
background: #046a38;
color: #ffffff;
padding: 3px 8px;
border-radius: 6px;
font-weight: 900;
}
.controls-top {
pointer-events: auto;
display: flex;
gap: 10px;
}
.btn-pill {
background: rgba(15, 23, 42, 0.85);
border: 1.5px solid rgba(251, 191, 36, 0.5);
color: #fbbf24;
padding: 8px 16px;
border-radius: 20px;
font-size: 13px;
font-weight: 800;
cursor: pointer;
}
#hud-cluster {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 20px;
z-index: 10;
background: rgba(15, 23, 42, 0.95);
padding: 10px 30px;
border-radius: 25px;
border: 2px solid rgba(251, 191, 36, 0.5);
box-shadow: 0 10px 30px rgba(0,0,0,0.6);
}
.cluster-col {
display: flex;
flex-direction: column;
align-items: center;
}
.cluster-lbl {
font-size: 9px;
text-transform: uppercase;
color: #94a3b8;
font-weight: 900;
}
.cluster-val {
font-size: 24px;
font-weight: 900;
color: #ffffff;
font-family: monospace;
}
#speed-num {
font-size: 36px;
color: #38bdf8;
}
#near-miss-banner {
position: absolute;
top: 80px;
left: 50%;
transform: translateX(-50%) scale(0.6);
background: linear-gradient(90deg, #f59e0b, #ef4444);
color: white;
padding: 8px 24px;
border-radius: 30px;
font-weight: 900;
font-size: 15px;
text-transform: uppercase;
box-shadow: 0 0 25px rgba(239, 68, 68, 0.8);
opacity: 0;
pointer-events: none;
transition: all 0.25s ease;
z-index: 12;
}
#near-miss-banner.show {
opacity: 1;
transform: translateX(-50%) scale(1);
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 30;
background: rgba(10, 15, 26, 0.92);
backdrop-filter: blur(10px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
padding: 20px;
}
.overlay.hidden {
display: none !important;
}
.overlay h1 {
font-size: 42px;
font-weight: 900;
margin-bottom: 8px;
color: #fbbf24;
text-transform: uppercase;
letter-spacing: 2px;
}
.overlay p {
color: #cbd5e1;
font-size: 16px;
margin-bottom: 22px;
max-width: 450px;
line-height: 1.5;
}
.score-summary {
background: rgba(255, 255, 255, 0.08);
border: 1.5px solid rgba(251, 191, 36, 0.4);
border-radius: 18px;
padding: 16px 40px;
margin-bottom: 20px;
}
.score-summary .stat {
font-size: 15px;
color: #cbd5e1;
margin: 6px 0;
}
.score-summary .stat span {
font-size: 24px;
font-weight: 900;
color: #fbbf24;
margin-left: 10px;
}
.btn-glow {
padding: 16px 48px;
font-size: 20px;
font-weight: 900;
color: #0f172a;
background: linear-gradient(135deg, #fbbf24, #f59e0b);
border: none;
border-radius: 50px;
cursor: pointer;
box-shadow: 0 0 35px rgba(251, 191, 36, 0.8);
transition: all 0.2s ease;
text-transform: uppercase;
}
.btn-glow:hover {
transform: scale(1.05);
}
.keys-tip {
margin-top: 20px;
font-size: 13px;
color: #94a3b8;
}
.key-badge {
background: #1e293b;
padding: 4px 10px;
border-radius: 6px;
border: 1px solid #334155;
color: #fff;
font-weight: 800;
}
#mobile-controls {
position: absolute;
bottom: 25px;
left: 0;
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 25px;
z-index: 10;
pointer-events: none;
}
.touch-btn {
pointer-events: auto;
width: 75px;
height: 75px;
border-radius: 50%;
background: rgba(15, 23, 42, 0.85);
border: 2px solid rgba(251, 191, 36, 0.6);
color: #fbbf24;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
touch-action: manipulation;
}
@media (max-width: 768px) {
#hud-cluster { bottom: 110px; padding: 8px 18px; gap: 12px; }
#speed-num { font-size: 26px; }
.overlay h1 { font-size: 30px; }
}
</style>
</head>
<body>
<canvas id="game-canvas"></canvas>
<div id="top-bar">
<div class="location-badge">
<span class="code">E 11</span>
<span>SHEIKH ZAYED ROAD • DUBAI</span>
</div>
<div class="controls-top">
<button class="btn-pill" id="cam-btn">🎥 CAM: CHASE</button>
<button class="btn-pill" id="sound-btn">🔊 AUDIO: ON</button>
</div>
</div>
<div id="hud-cluster">
<div class="cluster-col">
<span class="cluster-lbl">Gear</span>
<span id="gear-num">6</span>
</div>
<div class="cluster-col">
<span class="cluster-lbl">Speed</span>
<div style="display: flex; align-items: baseline; gap: 3px;">
<span id="speed-num">140</span>
<span style="font-size: 11px; color: #38bdf8; font-weight: bold;">KM/H</span>
</div>
</div>
<div class="cluster-col">
<span class="cluster-lbl">Score</span>
<span id="score-num" class="cluster-val">0</span>
</div>
<div class="cluster-col">
<span class="cluster-lbl">Record</span>
<span id="best-num" class="cluster-val" style="color: #34d399;">0</span>
</div>
</div>
<div id="near-miss-banner">⚡ CLOSE PASS +50</div>
<div id="game-modal" class="overlay">
<h1 id="modal-title">DUBAI 3D CAR DODGER</h1>
<p id="modal-desc">शेख ज़ायद रोड पर दिन के उजाले में मैकलेरन सुपरकार चलाएं! ट्रैफिक से बचें और रिकॉर्ड बनाएं!</p>
<div id="modal-stats" class="score-summary" style="display: none;">
<div class="stat">Score: <span id="final-score">0</span></div>
<div class="stat">Best Score: <span id="final-best">0</span></div>
<div class="stat">Near Misses: <span id="final-misses">0</span></div>
</div>
<button id="modal-btn" class="btn-glow">START RACE</button>
<div class="keys-tip">
<span><span class="key-badge">←</span> <span class="key-badge">→</span> या <span class="key-badge">A</span> <span class="key-badge">D</span> स्टेयर करें | <span class="key-badge">Space</span> रीस्टार्ट</span>
</div>
</div>
<div id="mobile-controls">
<button class="touch-btn" id="btn-left">◀</button>
<button class="touch-btn" id="btn-right">▶</button>
</div>
<script>
if (typeof THREE === 'undefined') {
alert("Three.js 3D लाइब्रेरी लोड नहीं हो सकी। कृपया इंटरनेट कनेक्शन चेक करें!");
}
function createRealAsphaltTexture() {
const cvs = document.createElement('canvas');
cvs.width = 512; cvs.height = 512;
const ctx = cvs.getContext('2d');
ctx.fillStyle = '#22262c';
ctx.fillRect(0, 0, 512, 512);
ctx.fillStyle = '#ffffff';
for (let y = 50; y < 512; y += 120) {
ctx.beginPath();
ctx.moveTo(230, y); ctx.lineTo(256, y - 30); ctx.lineTo(282, y);
ctx.lineTo(270, y + 20); ctx.lineTo(256, y - 10); ctx.lineTo(242, y + 20);
ctx.fill();
}
const tex = new THREE.CanvasTexture(cvs);
tex.wrapS = THREE.RepeatWrapping; tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set(1, 8);
return tex;
}
function createDesertSandTexture() {
const cvs = document.createElement('canvas');
cvs.width = 256; cvs.height = 256;
const ctx = cvs.getContext('2d');
ctx.fillStyle = '#d4a85c';
ctx.fillRect(0, 0, 256, 256);
ctx.strokeStyle = 'rgba(255, 240, 195, 0.3)';
ctx.lineWidth = 14;
for (let y = 0; y < 256; y += 35) {
ctx.beginPath(); ctx.moveTo(0, y);
ctx.bezierCurveTo(80, y + 15, 170, y - 15, 256, y);
ctx.stroke();
}
const tex = new THREE.CanvasTexture(cvs);
tex.wrapS = THREE.RepeatWrapping; tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set(8, 12);
return tex;
}
let audioCtx = null;
let soundEnabled = true;
let engineOsc1 = null, engineOsc2 = null, engineGain = null;
function initAudio() {
if (!audioCtx) {
try {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
engineOsc1 = audioCtx.createOscillator();
engineOsc2 = audioCtx.createOscillator();
engineGain = audioCtx.createGain();
engineOsc1.type = 'sawtooth';
engineOsc2.type = 'triangle';
engineOsc1.frequency.setValueAtTime(55, audioCtx.currentTime);
engineOsc2.frequency.setValueAtTime(110, audioCtx.currentTime);
const filter = audioCtx.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.setValueAtTime(450, audioCtx.currentTime);
engineGain.gain.setValueAtTime(0.001, audioCtx.currentTime);
engineOsc1.connect(filter);
engineOsc2.connect(filter);
filter.connect(engineGain);
engineGain.connect(audioCtx.destination);
engineOsc1.start();
engineOsc2.start();
} catch(e) { console.log(e); }
}
if (audioCtx && audioCtx.state === 'suspended') {
audioCtx.resume();
}
}
function updateEngineAudio(spd) {
if (!soundEnabled || !engineGain || !audioCtx) return;
const freq = 45 + (spd * 2.2);
engineOsc1.frequency.setTargetAtTime(freq, audioCtx.currentTime, 0.04);
engineOsc2.frequency.setTargetAtTime(freq * 1.5, audioCtx.currentTime, 0.04);
engineGain.gain.setTargetAtTime(isPlaying ? 0.075 : 0.001, audioCtx.currentTime, 0.1);
}
function playSound(type) {
if (!soundEnabled || !audioCtx) return;
try {
const now = audioCtx.currentTime;
if (type === 'pass') {
const osc = audioCtx.createOscillator();
const g = audioCtx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(300, now);
osc.frequency.exponentialRampToValueAtTime(850, now + 0.14);
g.gain.setValueAtTime(0.18, now);
g.gain.linearRampToValueAtTime(0.001, now + 0.14);
osc.connect(g); g.connect(audioCtx.destination);
osc.start(now); osc.stop(now + 0.14);
} else if (type === 'nearmiss') {
const osc = audioCtx.createOscillator();
const g = audioCtx.createGain();
osc.type = 'triangle';
osc.frequency.setValueAtTime(750, now);
osc.frequency.exponentialRampToValueAtTime(1400, now + 0.18);
g.gain.setValueAtTime(0.25, now);
g.gain.linearRampToValueAtTime(0.001, now + 0.18);
osc.connect(g); g.connect(audioCtx.destination);
osc.start(now); osc.stop(now + 0.18);
} else if (type === 'crash') {
const bufferSize = audioCtx.sampleRate * 0.5;
const buffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate);
const output = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) output[i] = Math.random() * 2 - 1;
const noise = audioCtx.createBufferSource(); noise.buffer = buffer;
const filter = audioCtx.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.setValueAtTime(1000, now);
filter.frequency.linearRampToValueAtTime(50, now + 0.5);
const g = audioCtx.createGain();
g.gain.setValueAtTime(0.8, now);
g.gain.exponentialRampToValueAtTime(0.01, now + 0.5);
noise.connect(filter); filter.connect(g);
g.connect(audioCtx.destination);
noise.start(now);
}
} catch (e) {}
}
const canvas = document.getElementById('game-canvas');
const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x64b5f6);
scene.fog = new THREE.FogExp2(0xcce3f5, 0.005);
let cameraMode = 'chase';
const camera = new THREE.PerspectiveCamera(56, window.innerWidth / window.innerHeight, 0.1, 600);
function toggleCameraView() {
cameraMode = cameraMode === 'chase' ? 'hood' : 'chase';
document.getElementById('cam-btn').innerText = cameraMode === 'chase' ? '🎥 CAM: CHASE' : '🎥 CAM: HOOD';
}
const hemiLight = new THREE.HemisphereLight(0xffffff, 0xd4a85c, 0.9);
scene.add(hemiLight);
const sunLight = new THREE.DirectionalLight(0xfffbe6, 1.8);
sunLight.position.set(50, 90, 40);
sunLight.castShadow = true;
sunLight.shadow.mapSize.width = 1024;
sunLight.shadow.mapSize.height = 1024;
scene.add(sunLight);
const sunOrb = new THREE.Mesh(new THREE.SphereGeometry(16, 32, 32), new THREE.MeshBasicMaterial({ color: 0xfffae0, fog: false }));
sunOrb.position.set(150, 230, -340);
scene.add(sunOrb);
const ROAD_WIDTH = 15.5;
const ROAD_LENGTH = 300;
const ROAD_SEGMENTS = 2;
const roadGroup = new THREE.Group();
scene.add(roadGroup);
const asphaltMat = new THREE.MeshStandardMaterial({ map: createRealAsphaltTexture(), roughness: 0.7 });
const sandMat = new THREE.MeshStandardMaterial({ map: createDesertSandTexture(), roughness: 0.95 });
function createRealPalmTree() {
const tree = new THREE.Group();
const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.22, 0.42, 8.0, 8), new THREE.MeshStandardMaterial({ color: 0x5c3a1e, roughness: 0.9 }));
trunk.position.y = 4.0;
trunk.castShadow = true;
tree.add(trunk);
const leafMat = new THREE.MeshStandardMaterial({ color: 0x15803d, roughness: 0.5, side: THREE.DoubleSide });
for (let i = 0; i < 8; i++) {
const leaf = new THREE.Mesh(new THREE.ConeGeometry(0.85, 4.2, 4), leafMat);
leaf.position.set(0, 7.8, 0);
leaf.rotation.z = Math.PI / 2.5;
leaf.rotation.y = (i / 8) * Math.PI * 2;
leaf.castShadow = true;
tree.add(leaf);
}
return tree;
}
function createMuseumOfTheFutureExact() {
const motf = new THREE.Group();
const torusGeo = new THREE.TorusGeometry(18, 7, 16, 32);
const torus = new THREE.Mesh(torusGeo, new THREE.MeshStandardMaterial({ color: 0xcbd5e1, metalness: 0.9, roughness: 0.15 }));
torus.position.set(-ROAD_WIDTH / 2 - 12, 24, 0);
torus.rotation.y = Math.PI / 5;
torus.castShadow = true;
motf.add(torus);
const bridge = new THREE.Mesh(new THREE.BoxGeometry(10, 1.2, 120), new THREE.MeshStandardMaterial({ color: 0xd1d5db }));
bridge.position.set(-ROAD_WIDTH / 2 - 12, 11, 0);
bridge.castShadow = true;
motf.add(bridge);
const hill = new THREE.Mesh(new THREE.CylinderGeometry(20, 26, 8, 16), new THREE.MeshStandardMaterial({ color: 0x166534, roughness: 0.8 }));
hill.position.set(-ROAD_WIDTH / 2 - 12, 4, 0);
motf.add(hill);
return motf;
}
function createBurjKhalifaDetailed() {
const burj = new THREE.Group();
const tiers = [
{ r: 18, h: 42, y: 21 }, { r: 14.5, h: 45, y: 64.5 }, { r: 11.5, h: 48, y: 111 },
{ r: 9, h: 48, y: 159 }, { r: 6.5, h: 42, y: 204 }, { r: 4.2, h: 36, y: 243 }
];
const burjMat = new THREE.MeshStandardMaterial({ color: 0x38bdf8, metalness: 0.9, roughness: 0.15 });
tiers.forEach(t => {
const mesh = new THREE.Mesh(new THREE.CylinderGeometry(t.r * 0.82, t.r, t.h, 6), burjMat);
mesh.position.y = t.y;
mesh.castShadow = true;
burj.add(mesh);
});
const spire = new THREE.Mesh(new THREE.CylinderGeometry(0.25, 2.0, 70, 6), new THREE.MeshStandardMaterial({ color: 0xf1f5f9, metalness: 0.98 }));
spire.position.y = 295;
burj.add(spire);
return burj;
}
function createDubaiTower(type, h) {
const tower = new THREE.Group();
const body = new THREE.Mesh(new THREE.BoxGeometry(18, h, 18), new THREE.MeshStandardMaterial({ color: type === 1 ? 0x0284c7 : 0x1e3a8a, metalness: 0.85, roughness: 0.2 }));
body.position.y = h / 2;
body.castShadow = true;
tower.add(body);
return tower;
}
const roadMeshes = [];
for (let i = 0; i < ROAD_SEGMENTS; i++) {
const segment = new THREE.Group();
const roadMesh = new THREE.Mesh(new THREE.PlaneGeometry(ROAD_WIDTH, ROAD_LENGTH), asphaltMat);
roadMesh.rotation.x = -Math.PI / 2;
roadMesh.receiveShadow = true;
segment.add(roadMesh);
const leftSand = new THREE.Mesh(new THREE.PlaneGeometry(180, ROAD_LENGTH), sandMat);
leftSand.rotation.x = -Math.PI / 2;
leftSand.position.set(-ROAD_WIDTH / 2 - 90, -0.05, 0);
leftSand.receiveShadow = true;
const rightSand = new THREE.Mesh(new THREE.PlaneGeometry(180, ROAD_LENGTH), sandMat);
rightSand.rotation.x = -Math.PI / 2;
rightSand.position.set(ROAD_WIDTH / 2 + 90, -0.05, 0);
rightSand.receiveShadow = true;
segment.add(leftSand, rightSand);
const laneXPositions = [-ROAD_WIDTH * 0.25, 0, ROAD_WIDTH * 0.25];
const dashGeo = new THREE.PlaneGeometry(0.25, 5.5);
const dashMat = new THREE.MeshBasicMaterial({ color: 0xffffff });
laneXPositions.forEach(xPos => {
for (let z = -ROAD_LENGTH / 2; z < ROAD_LENGTH / 2; z += 12) {
const dash = new THREE.Mesh(dashGeo, dashMat);
dash.rotation.x = -Math.PI / 2;
dash.position.set(xPos, 0.02, z);
segment.add(dash);
}
});
for (let z = -ROAD_LENGTH / 2 + 10; z < ROAD_LENGTH / 2; z += 28) {
const lTree = createRealPalmTree();
lTree.position.set(-ROAD_WIDTH / 2 - 3.8, 0, z);
const rTree = createRealPalmTree();
rTree.position.set(ROAD_WIDTH / 2 + 3.8, 0, z + 14);
segment.add(lTree, rTree);
}
for (let z = -ROAD_LENGTH / 2 + 25; z < ROAD_LENGTH / 2; z += 60) {
const b1 = createDubaiTower(Math.floor(Math.random() * 2), 60 + Math.random() * 70);
b1.position.set(-ROAD_WIDTH / 2 - 36 - Math.random() * 15, 0, z);
const b2 = createDubaiTower(Math.floor(Math.random() * 2), 55 + Math.random() * 75);
b2.position.set(ROAD_WIDTH / 2 + 34 + Math.random() * 15, 0, z + 30);
segment.add(b1, b2);
}
if (i === 0) {
const motf = createMuseumOfTheFutureExact();
motf.position.z = -40;
segment.add(motf);
const burj = createBurjKhalifaDetailed();
burj.position.set(85, 0, -80);
segment.add(burj);
}
segment.position.z = -i * ROAD_LENGTH;
roadGroup.add(segment);
roadMeshes.push(segment);
}
function createMcLarenSupercar(colorHex, isPlayer = false, type = 'supercar') {
const car = new THREE.Group();
const paintMat = new THREE.MeshStandardMaterial({ color: colorHex, metalness: 0.9, roughness: 0.12 });
const glassMat = new THREE.MeshStandardMaterial({ color: 0x0a101d, metalness: 0.96, roughness: 0.04 });
const carbonMat = new THREE.MeshStandardMaterial({ color: 0x18181b, roughness: 0.35 });
if (type === 'suv') {
const body = new THREE.Mesh(new THREE.BoxGeometry(2.15, 1.3, 4.3), paintMat);
body.position.y = 1.05;
body.castShadow = true;
const cabin = new THREE.Mesh(new THREE.BoxGeometry(1.95, 0.78, 2.75), glassMat);
cabin.position.set(0, 1.74, -0.2);
cabin.castShadow = true;
car.add(body, cabin);
} else {
const mainBody = new THREE.Mesh(new THREE.BoxGeometry(1.92, 0.48, 4.0), paintMat);
mainBody.position.y = 0.46;
mainBody.castShadow = true;
const hood = new THREE.Mesh(new THREE.ConeGeometry(1.18, 1.45, 4), paintMat);
hood.rotation.y = Math.PI / 4;
hood.rotation.x = -Math.PI / 2;
hood.position.set(0, 0.44, -1.65);
const dome = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.44, 2.0), glassMat);
dome.position.set(0, 0.88, -0.15);
dome.castShadow = true;
const wing = new THREE.Mesh(new THREE.BoxGeometry(1.9, 0.06, 0.44), carbonMat);
wing.position.set(0, 1.08, 1.8);
car.add(mainBody, hood, dome, wing);
}
const wheelOffsets = [[-1.0, 0.38, 1.25], [1.0, 0.38, 1.25], [-1.0, 0.38, -1.25], [1.0, 0.38, -1.25]];
const wheels = [];
wheelOffsets.forEach(pos => {
const wGroup = new THREE.Group();
const tire = new THREE.Mesh(new THREE.CylinderGeometry(0.38, 0.38, 0.4, 16), new THREE.MeshStandardMaterial({ color: 0x18181b, roughness: 0.85 }));
tire.rotation.z = Math.PI / 2;
tire.castShadow = true;
const rim = new THREE.Mesh(new THREE.CylinderGeometry(0.25, 0.25, 0.41, 10), new THREE.MeshStandardMaterial({ color: 0xf8fafc, metalness: 0.95 }));
rim.rotation.z = Math.PI / 2;
wGroup.add(tire, rim);
wGroup.position.set(...pos);
car.add(wGroup);
wheels.push(wGroup);
});
return { group: car, wheels: wheels };
}
const playerCarObj = createMcLarenSupercar(0x0284c7, true, 'supercar');
const playerCar = playerCarObj.group;
scene.add(playerCar);
playerCar.position.set(0, 0, 2);
let isPlaying = false;
let score = 0;
let nearMisses = 0;
let bestScore = parseInt(localStorage.getItem('dubaiPhotoBest') || '0');
let speed = 72;
let playerX = 0;
let targetX = 0;
let enemies = [];
let particles = [];
let lastTime = performance.now();
document.getElementById('best-num').innerText = bestScore;
const DUBAI_LUXURY_COLORS = [0xf8fafc, 0x18181b, 0xdc2626, 0xf59e0b, 0x7c3aed, 0x059669];
function spawnTrafficCar() {
const lanes = [-5.6, -1.85, 1.85, 5.6];
const laneX = lanes[Math.floor(Math.random() * lanes.length)];
for (let e of enemies) {
if (Math.abs(e.mesh.position.x - laneX) < 2.0 && e.mesh.position.z < -115) return;
}
const randColor = DUBAI_LUXURY_COLORS[Math.floor(Math.random() * DUBAI_LUXURY_COLORS.length)];
const isSUV = Math.random() > 0.55;
const enemyCarObj = createMcLarenSupercar(randColor, false, isSUV ? 'suv' : 'supercar');
const enemyMesh = enemyCarObj.group;
const oncoming = Math.random() > 0.45;
if (oncoming) enemyMesh.rotation.y = Math.PI;
enemyMesh.position.set(laneX, 0, -150 - Math.random() * 30);
scene.add(enemyMesh);
enemies.push({
mesh: enemyMesh,
wheels: enemyCarObj.wheels,
speed: oncoming ? (speed * 0.42 + 14) : (-speed * 0.35 + (Math.random() * 12)),
passed: false,
nearMissChecked: false
});
}
function createExplosion(x, y, z) {
const count = 40;
const pGeo = new THREE.BoxGeometry(0.3, 0.3, 0.3);
for (let i = 0; i < count; i++) {
const p = new THREE.Mesh(pGeo, new THREE.MeshStandardMaterial({ color: Math.random() > 0.4 ? 0xf59e0b : 0xdc2626, metalness: 0.9 }));
p.position.set(x, y, z);
p.velocity = new THREE.Vector3((Math.random() - 0.5) * 20, Math.random() * 15 + 3, (Math.random() - 0.5) * 20);
scene.add(p);
particles.push(p);
}
}
const keys = { left: false, right: false };
function handleKeyDown(e) {
if (e.key === ' ' || e.key === 'Spacebar') {
if (!isPlaying) startGame();
}
if (e.key.toLowerCase() === 'c') toggleCameraView();
if (!isPlaying) return;
if (e.key === 'ArrowLeft' || e.key.toLowerCase() === 'a') keys.left = true;
if (e.key === 'ArrowRight' || e.key.toLowerCase() === 'd') keys.right = true;
}
function handleKeyUp(e) {
if (e.key === 'ArrowLeft' || e.key.toLowerCase() === 'a') keys.left = false;
if (e.key === 'ArrowRight' || e.key.toLowerCase() === 'd') keys.right = false;
}
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
document.getElementById('modal-btn').onclick = function(e) {
if (e) e.stopPropagation();
startGame();
};
document.getElementById('cam-btn').onclick = function(e) {
if (e) e.stopPropagation();
toggleCameraView();
};
document.getElementById('sound-btn').onclick = function(e) {
if (e) e.stopPropagation();
toggleAudio();
};
const setupTouch = (btn, dir) => {
btn.addEventListener('touchstart', (e) => { e.preventDefault(); keys[dir] = true; });
btn.addEventListener('touchend', (e) => { e.preventDefault(); keys[dir] = false; });
btn.addEventListener('mousedown', () => { keys[dir] = true; });
btn.addEventListener('mouseup', () => { keys[dir] = false; });
btn.addEventListener('mouseleave', () => { keys[dir] = false; });
};
setupTouch(document.getElementById('btn-left'), 'left');
setupTouch(document.getElementById('btn-right'), 'right');
function startGame() {
initAudio();
enemies.forEach(e => scene.remove(e.mesh));
enemies = [];
particles.forEach(p => scene.remove(p));
particles = [];
score = 0;
nearMisses = 0;
speed = 72;
playerX = 0;
targetX = 0;
playerCar.position.set(0, 0, 2);
playerCar.rotation.set(0, 0, 0);
document.getElementById('score-num').innerText = '0';
document.getElementById('game-modal').classList.add('hidden');
isPlaying = true;
lastTime = performance.now();
}
function triggerNearMiss() {
nearMisses++;
score += 50;
document.getElementById('score-num').innerText = score;
playSound('nearmiss');
const banner = document.getElementById('near-miss-banner');
banner.classList.add('show');
setTimeout(() => banner.classList.remove('show'), 650);
}
function gameOver() {
isPlaying = false;
playSound('crash');
createExplosion(playerCar.position.x, 0.8, playerCar.position.z);
if (score > bestScore) {
bestScore = score;
localStorage.setItem('dubaiPhotoBest', bestScore);
document.getElementById('best-num').innerText = bestScore;
}
document.getElementById('modal-title').innerText = 'HIGHWAY CRASH!';
document.getElementById('modal-desc').innerText = 'गाड़ी टकरा गई! दोबारा रेस लगाएं!';
document.getElementById('final-score').innerText = score;
document.getElementById('final-best').innerText = bestScore;
document.getElementById('final-misses').innerText = nearMisses;
document.getElementById('modal-stats').style.display = 'block';
document.getElementById('modal-btn').innerText = 'RESTART RACE';
document.getElementById('game-modal').classList.remove('hidden');
}
function animate(now) {
requestAnimationFrame(animate);
const dt = Math.min((now - lastTime) / 1000, 0.1);
lastTime = now;
if (isPlaying) {
const moveSpeed = 21.0;
if (keys.left) targetX -= moveSpeed * dt;
if (keys.right) targetX += moveSpeed * dt;
const MAX_X = 6.0;
targetX = Math.max(-MAX_X, Math.min(MAX_X, targetX));
const steerDiff = targetX - playerX;
playerX += steerDiff * 16 * dt;
playerCar.position.x = playerX;
playerCar.rotation.z = -steerDiff * 0.42;
playerCar.rotation.y = -steerDiff * 0.28;
playerCarObj.wheels.forEach(w => {
w.children[0].rotation.x += speed * 0.18 * dt;
});
if (cameraMode === 'chase') {
camera.position.x = playerX * 0.45;
camera.position.y = 4.3 + Math.sin(now * 0.014) * 0.025;
camera.position.z = 8.8;
camera.lookAt(playerX * 0.25, 1.3, -10);
} else {
camera.position.x = playerX;
camera.position.y = 1.08;
camera.position.z = 1.2;
camera.lookAt(playerX + (steerDiff * 0.5), 1.0, -25);
}
const roadScroll = speed * dt;
roadMeshes.forEach(mesh => {
mesh.position.z += roadScroll;
if (mesh.position.z > ROAD_LENGTH) {
mesh.position.z -= ROAD_LENGTH * ROAD_SEGMENTS;
}
});
if (Math.random() < 0.04 && enemies.length < 6) {
spawnTrafficCar();
}
for (let i = enemies.length - 1; i >= 0; i--) {
const e = enemies[i];
e.mesh.position.z += (speed + e.speed) * dt;
e.wheels.forEach(w => {
w.children[0].rotation.x += 14 * dt;
});
const dx = Math.abs(playerCar.position.x - e.mesh.position.x);
const dz = Math.abs(playerCar.position.z - e.mesh.position.z);
if (!e.nearMissChecked && dz < 2.0 && dx > 1.48 && dx < 2.5) {
e.nearMissChecked = true;
triggerNearMiss();
}
if (!e.passed && e.mesh.position.z > playerCar.position.z) {
e.passed = true;
score += 15;
document.getElementById('score-readout').innerText = score;
playSound('pass');
if (score % 60 === 0) speed += 4.2;
}
if (dx < 1.48 && dz < 3.4) {
gameOver();
break;
}
if (e.mesh.position.z > 25) {
scene.remove(e.mesh);
enemies.splice(i, 1);
}
}
updateEngineAudio(speed);
const displayKmh = Math.round(speed * 2.25);
document.getElementById('speed-readout').innerText = displayKmh;
document.getElementById('gear-num').innerText = Math.min(7, Math.max(1, Math.floor(displayKmh / 35) + 1));
}
for (let i = particles.length - 1; i >= 0; i--) {
const p = particles[i];
p.position.addScaledVector(p.velocity, dt);
p.velocity.y -= 28 * dt;
p.scale.multiplyScalar(0.95);
if (p.position.y <= 0 || p.scale.x < 0.05) {
scene.remove(p);
particles.splice(i, 1);
}
}
renderer.render(scene, camera);
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
requestAnimationFrame(animate);
</script>
</body>
</html>
```