<!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>3D Battle Royale Offline</title>
<style>
body { margin: 0; overflow: hidden; background: #111; font-family: 'Segoe UI', Arial, sans-serif; user-select: none; }
/* टॉप HUD */
#hud-top {
position: absolute; top: 10px; left: 10px; right: 10px;
display: flex; justify-content: space-between; align-items: flex-start;
z-index: 10; pointer-events: none;
}
.panel {
background: rgba(0, 0, 0, 0.65); color: white; padding: 8px 14px;
border-radius: 6px; border-left: 4px solid #ff9800; font-weight: bold; font-size: 14px;
}
#hp-bar-wrap { width: 140px; height: 10px; background: #333; margin-top: 4px; border-radius: 5px; overflow: hidden; }
#hp-bar { width: 100%; height: 100%; background: #4caf50; transition: 0.2s; }
#zone-alert {
position: absolute; top: 65px; left: 50%; transform: translateX(-50%);
background: rgba(33, 150, 243, 0.85); color: white; padding: 5px 15px;
border-radius: 20px; font-size: 13px; font-weight: bold; display: none; z-index: 12;
}
/* निशाना (Crosshair + Scope) */
#crosshair {
position: absolute; top: 45%; left: 50%; width: 26px; height: 26px;
transform: translate(-50%, -50%); pointer-events: none; z-index: 10;
border: 2px solid rgba(255,255,255,0.7); border-radius: 50%;
}
#crosshair::after {
content: ''; position: absolute; top: 11px; left: 11px; width: 4px; height: 4px;
background: red; border-radius: 50%;
}
#scope-overlay {
display: none; position: fixed; inset: 0; pointer-events: none; z-index: 9;
background: radial-gradient(circle, transparent 28%, rgba(0,0,0,0.88) 32%);
}
/* बायाँ जॉयस्टिक */
#joystick-zone {
position: absolute; bottom: 25px; left: 25px; width: 115px; height: 115px;
background: rgba(255, 255, 255, 0.15); border: 2px solid rgba(255,255,255,0.4);
border-radius: 50%; z-index: 15; touch-action: none;
}
#joystick-knob {
position: absolute; top: 32px; left: 32px; width: 50px; height: 50px;
background: rgba(255, 152, 0, 0.85); border-radius: 50%; pointer-events: none;
}
/* दायाँ कैमरा एरिया */
#look-zone { position: absolute; top: 0; right: 0; width: 55%; height: 100%; z-index: 5; touch-action: none; }
/* एक्शन बटन्स */
.btn {
position: absolute; border-radius: 50%; border: 2px solid rgba(255,255,255,0.85);
color: white; font-weight: bold; z-index: 15; touch-action: manipulation;
display: flex; flex-direction: column; align-items: center; justify-content: center;
box-shadow: 0 4px 8px rgba(0,0,0,0.5); font-size: 11px;
}
#fireBtn { bottom: 35px; right: 25px; width: 80px; height: 80px; background: radial-gradient(circle, #ff5722, #bf360c); font-size: 16px; }
#fireBtn:active { transform: scale(0.92); }
#jumpBtn { bottom: 130px; right: 25px; width: 52px; height: 52px; background: rgba(0,0,0,0.65); }
#scopeBtn { bottom: 130px; right: 90px; width: 52px; height: 52px; background: rgba(0,0,0,0.65); }
#glooBtn { bottom: 35px; right: 120px; width: 56px; height: 56px; background: rgba(0, 188, 212, 0.85); }
#medkitBtn { bottom: 35px; right: 185px; width: 52px; height: 52px; background: rgba(76, 175, 80, 0.85); }
#sprintBtn { bottom: 155px; left: 55px; width: 50px; height: 50px; background: rgba(255, 152, 0, 0.7); }
/* स्टार्ट और एंड स्क्रीन */
#overlayScreen {
position: fixed; inset: 0; background: rgba(10, 15, 25, 0.92);
color: white; display: flex; flex-direction: column; align-items: center; justify-content: center;
z-index: 30; text-align: center; padding: 20px;
}
.main-btn {
background: linear-gradient(45deg, #ff9800, #ff5722); color: white; border: none;
padding: 14px 35px; font-size: 20px; font-weight: bold; border-radius: 8px;
margin-top: 20px; cursor: pointer; box-shadow: 0 4px 15px rgba(255,87,34,0.5);
}
</style>
</head>
<body>
<div id="hud-top">
<div class="panel">
HP: <span id="hp-val">200</span>/200
<div id="hp-bar-wrap"><div id="hp-bar"></div></div>
</div>
<div class="panel" style="border-left-color: #00bcd4;">
ZONE: <span id="zone-rad">140</span>m
</div>
<div class="panel" style="border-left-color: #f44336;">
KILLS: <span id="kills-val">0</span> | ALIVE: <span id="alive-val">12</span>
</div>
</div>
<div id="zone-alert">⚠️ आप सेफ ज़ोन से बाहर हैं! अंदर जाएं!</div>
<div id="scope-overlay"></div>
<div id="crosshair"></div>
<div id="look-zone"></div>
<div id="joystick-zone"><div id="joystick-knob"></div></div>
<button class="btn" id="sprintBtn">RUN</button>
<button class="btn" id="fireBtn">FIRE</button>
<button class="btn" id="jumpBtn">JUMP</button>
<button class="btn" id="scopeBtn">2X</button>
<button class="btn" id="glooBtn">WALL<br>(<span id="gloo-val">4</span>)</button>
<button class="btn" id="medkitBtn">+HP<br>(<span id="med-val">3</span>)</button>
<div id="overlayScreen">
<h1 id="screenTitle" style="color:#ff9800; font-size:32px; margin-bottom:10px;">3D BATTLE ROYALE</h1>
<p id="screenSub" style="font-size:16px; color:#ccc; max-width:400px;">
पैराशूट से उतरें, दुश्मनों को हराएं, Gloo Wall से बचाव करें और सेफ ज़ोन के अंदर रहें!
</p>
<button class="main-btn" id="startBtn">START MATCH</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// साउंड इफेक्ट जनरेटर (बिना बाहरी ऑडियो फाइल के)
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function playGunSound() {
if (audioCtx.state === 'suspended') audioCtx.resume();
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(180, audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(40, audioCtx.currentTime + 0.12);
gain.gain.setValueAtTime(0.25, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.12);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
osc.stop(audioCtx.currentTime + 0.12);
}
// 1. सीन, कैमरा और रेंडरर
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
scene.fog = new THREE.Fog(0x87CEEB, 40, 180);
const camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 600);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// लाइटिंग
scene.add(new THREE.HemisphereLight(0xffffff, 0x444444, 0.85));
const sun = new THREE.DirectionalLight(0xffffff, 0.9);
sun.position.set(50, 80, 40);
scene.add(sun);
// 2. मैप और ज़मीन
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(360, 360),
new THREE.MeshStandardMaterial({ color: 0x38761d })
);
ground.rotation.x = -Math.PI / 2;
scene.add(ground);
// सेफ ज़ोन की नीली दीवार (Safe Zone Ring)
let zoneRadius = 140;
const zoneGeo = new THREE.CylinderGeometry(zoneRadius, zoneRadius, 25, 48, 1, true);
const zoneMat = new THREE.MeshBasicMaterial({ color: 0x00b0ff, transparent: true, opacity: 0.25, side: THREE.DoubleSide });
const safeZoneMesh = new THREE.Mesh(zoneGeo, zoneMat);
safeZoneMesh.position.y = 12.5;
scene.add(safeZoneMesh);
// 3. घर, पेड़ और कवर बनाना
const glooWalls = [];
function buildMap() {
const houseMat = new THREE.MeshStandardMaterial({ color: 0xd7ccc8 });
const roofMat = new THREE.MeshStandardMaterial({ color: 0x8d6e63 });
const treeWood = new THREE.MeshStandardMaterial({ color: 0x5d4037 });
const treeLeaf = new THREE.MeshStandardMaterial({ color: 0x1b5e20 });
for (let i = 0; i < 45; i++) {
const x = (Math.random() - 0.5) * 240;
const z = (Math.random() - 0.5) * 240;
if (Math.abs(x) < 12 && Math.abs(z) < 12) continue;
if (i % 3 === 0) {
// छोटा घर / कंपाउंड
const house = new THREE.Mesh(new THREE.BoxGeometry(7, 4.5, 7), houseMat);
house.position.set(x, 2.25, z);
const roof = new THREE.Mesh(new THREE.ConeGeometry(5.5, 2.5, 4), roofMat);
roof.position.set(x, 5.7, z);
roof.rotation.y = Math.PI / 4;
scene.add(house, roof);
} else {
// पेड़
const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.4, 0.6, 4.5), treeWood);
trunk.position.set(x, 2.25, z);
const leaves = new THREE.Mesh(new THREE.ConeGeometry(2.8, 6, 8), treeLeaf);
leaves.position.set(x, 6.5, z);
scene.add(trunk, leaves);
}
}
}
buildMap();
// 4. प्लेयर कैरेक्टर + पैराशूट
const player = new THREE.Group();
const pBody = new THREE.Mesh(new THREE.BoxGeometry(0.9, 1.2, 0.5), new THREE.MeshStandardMaterial({ color: 0x1565c0 }));
pBody.position.y = 1.5;
const pHead = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.6, 0.6), new THREE.MeshStandardMaterial({ color: 0xffcc99 }));
pHead.position.y = 2.45;
const pLegs = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.9, 0.45), new THREE.MeshStandardMaterial({ color: 0x212121 }));
pLegs.position.y = 0.45;
const pGun = new THREE.Mesh(new THREE.BoxGeometry(0.16, 0.22, 1.2), new THREE.MeshStandardMaterial({ color: 0x000000 }));
pGun.position.set(0.55, 1.6, -0.45);
// पैराशूट (लैंडिंग के समय दिखेगा)
const parachute = new THREE.Mesh(
new THREE.SphereGeometry(2.5, 12, 8, 0, Math.PI * 2, 0, Math.PI / 2),
new THREE.MeshStandardMaterial({ color: 0xff9800, side: THREE.DoubleSide })
);
parachute.position.y = 4.2;
player.add(pBody, pHead, pLegs, pGun, parachute);
player.position.set(0, 45, 0); // आसमान से शुरुआत!
scene.add(player);
// गेम वेरिएबल्स
let gameStarted = false, isGameOver = false;
let hp = 200, kills = 0, alive = 12, glooCount = 4, medCount = 3;
let yaw = 0, pitch = 0.15;
let velY = 0, isGrounded = false, isParachuting = true;
let isScoped = false, isSprinting = false;
const bullets = [], enemyBullets = [], enemies = [];
// 5. दुश्मन (Enemy Bots)
function createEnemies() {
for (let i = 0; i < 11; i++) {
const en = new THREE.Group();
const b = new THREE.Mesh(new THREE.BoxGeometry(0.9, 1.2, 0.5), new THREE.MeshStandardMaterial({ color: 0xc62828 }));
b.position.y = 1.5;
const h = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.6, 0.6), new THREE.MeshStandardMaterial({ color: 0xffcc99 }));
h.position.y = 2.45;
const l = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.9, 0.45), new THREE.MeshStandardMaterial({ color: 0x263238 }));
l.position.y = 0.45;
en.add(b, h, l);
en.position.set((Math.random() - 0.5) * 180, 0, (Math.random() - 0.5) * 180);
en.userData = { hp: 100, lastShot: 0 };
scene.add(en);
enemies.push(en);
}
}
createEnemies();
// 6. फायरिंग फंक्शन
function fireWeapon() {
if (!gameStarted || isGameOver || isParachuting) return;
playGunSound();
const bullet = new THREE.Mesh(
new THREE.SphereGeometry(0.12, 6, 6),
new THREE.MeshBasicMaterial({ color: 0xffeb3b })
);
bullet.position.copy(player.position);
bullet.position.y += 1.65;
const dir = new THREE.Vector3(0, 0, -1);
dir.applyEuler(new THREE.Euler(-pitch * 0.45, yaw, 0, 'YXZ'));
bullet.userData.vel = dir.multiplyScalar(2.6);
scene.add(bullet);
bullets.push(bullet);
}
// 7. Gloo Wall लगाना
function deployGlooWall() {
if (!gameStarted || isGameOver || isParachuting || glooCount <= 0) return;
glooCount--;
updateHUD();
const wall = new THREE.Mesh(
new THREE.BoxGeometry(3.8, 2.6, 0.4),
new THREE.MeshStandardMaterial({ color: 0x00e5ff, transparent: true, opacity: 0.85 })
);
const forward = new THREE.Vector3(-Math.sin(yaw), 0, -Math.cos(yaw));
wall.position.copy(player.position).addScaledVector(forward, 3.2);
wall.position.y = 1.3;
wall.rotation.y = yaw;
wall.userData = { hp: 150 };
scene.add(wall);
glooWalls.push(wall);
}
// 8. कंट्रोल्स (जॉयस्टिक, कैमरा, बटन्स)
let joyX = 0, joyY = 0;
const joyZone = document.getElementById('joystick-zone');
const joyKnob = document.getElementById('joystick-knob');
joyZone.addEventListener('touchmove', (e) => {
e.preventDefault();
const t = e.touches[0];
const r = joyZone.getBoundingClientRect();
const dx = t.clientX - (r.left + r.width / 2);
const dy = t.clientY - (r.top + r.height / 2);
const dist = Math.min(Math.hypot(dx, dy), 38);
const ang = Math.atan2(dy, dx);
joyX = Math.cos(ang) * (dist / 38);
joyY = Math.sin(ang) * (dist / 38);
joyKnob.style.transform = `translate(${Math.cos(ang) * dist}px, ${Math.sin(ang) * dist}px)`;
});
joyZone.addEventListener('touchend', () => {
joyX = 0; joyY = 0;
joyKnob.style.transform = `translate(0,0)`;
});
let lastX = 0, lastY = 0;
const lookZone = document.getElementById('look-zone');
lookZone.addEventListener('touchstart', (e) => { lastX = e.touches[0].clientX; lastY = e.touches[0].clientY; });
lookZone.addEventListener('touchmove', (e) => {
const sens = isScoped ? 0.003 : 0.007;
yaw -= (e.touches[0].clientX - lastX) * sens;
pitch = Math.max(-0.25, Math.min(0.6, pitch + (e.touches[0].clientY - lastY) * sens));
lastX = e.touches[0].clientX;
lastY = e.touches[0].clientY;
});
document.getElementById('fireBtn').addEventListener('touchstart', (e) => { e.preventDefault(); fireWeapon(); });
document.getElementById('fireBtn').addEventListener('click', fireWeapon);
document.getElementById('jumpBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
if (isGrounded) { velY = 0.36; isGrounded = false; }
});
document.getElementById('glooBtn').addEventListener('touchstart', (e) => { e.preventDefault(); deployGlooWall(); });
document.getElementById('medkitBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
if (medCount > 0 && hp < 200) {
medCount--;
hp = Math.min(200, hp + 80);
updateHUD();
}
});
document.getElementById('scopeBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
isScoped = !isScoped;
camera.fov = isScoped ? 32 : 65;
camera.updateProjectionMatrix();
document.getElementById('scope-overlay').style.display = isScoped ? 'block' : 'none';
});
document.getElementById('sprintBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
isSprinting = !isSprinting;
document.getElementById('sprintBtn').style.background = isSprinting ? '#ff5722' : 'rgba(255, 152, 0, 0.7)';
});
// कीबोर्ड सपोर्ट
const keys = {};
window.addEventListener('keydown', (e) => {
keys[e.key.toLowerCase()] = true;
if (e.key === ' ' && isGrounded) { velY = 0.36; isGrounded = false; }
if (e.key === 'f' || e.key === 'Enter') fireWeapon();
if (e.key === 'g') deployGlooWall();
});
window.addEventListener('keyup', (e) => keys[e.key.toLowerCase()] = false);
document.getElementById('startBtn').addEventListener('click', () => {
if (isGameOver) { location.reload(); return; }
document.getElementById('overlayScreen').style.display = 'none';
gameStarted = true;
});
function updateHUD() {
document.getElementById('hp-val').innerText = Math.max(0, Math.round(hp));
document.getElementById('hp-bar').style.width = (Math.max(0, hp) / 200 * 100) + '%';
document.getElementById('kills-val').innerText = kills;
document.getElementById('alive-val').innerText = alive;
document.getElementById('gloo-val').innerText = glooCount;
document.getElementById('med-val').innerText = medCount;
}
function finishGame(isBooyah) {
isGameOver = true;
document.getElementById('screenTitle').innerText = isBooyah ? "🏆 BOOYAH! #1" : "ELIMINATED!";
document.getElementById('screenSub').innerText = `कुल किल्स (Kills): ${kills}`;
document.getElementById('startBtn').innerText = "PLAY AGAIN";
document.getElementById('overlayScreen').style.display = 'flex';
}
// 9. मेन गेम लूप
let lastZoneDamageTime = 0;
function animate(time) {
requestAnimationFrame(animate);
if (!gameStarted || isGameOver) {
renderer.render(scene, camera);
return;
}
// पैराशूट लैंडिंग लॉजिक
if (isParachuting) {
player.position.y -= 0.25;
if (player.position.y <= 0) {
player.position.y = 0;
isParachuting = false;
isGrounded = true;
parachute.visible = false;
}
} else {
// सामान्य ग्रेविटी और जंप
player.position.y += velY;
if (player.position.y > 0) velY -= 0.02;
else { player.position.y = 0; velY = 0; isGrounded = true; }
}
// मूवमेंट
let mx = joyX, mz = joyY;
if (keys['w']) mz = -1;
if (keys['s']) mz = 1;
if (keys['a']) mx = -1;
if (keys['d']) mx = 1;
if (keys['q']) yaw += 0.04;
if (keys['e']) yaw -= 0.04;
player.rotation.y = yaw;
const moveSpeed = isSprinting ? 0.38 : 0.24;
const forward = new THREE.Vector3(-Math.sin(yaw), 0, -Math.cos(yaw));
const right = new THREE.Vector3(Math.cos(yaw), 0, -Math.sin(yaw));
player.position.addScaledVector(forward, -mz * moveSpeed);
player.position.addScaledVector(right, mx * moveSpeed);
// कैमरा पोज़िशन
const camOffset = isScoped ? new THREE.Vector3(0.4, 2.3, 1.2) : new THREE.Vector3(0.85, 3.2 + pitch * 3, 5.6);
camOffset.applyAxisAngle(new THREE.Vector3(0, 1, 0), yaw);
camera.position.copy(player.position).add(camOffset);
camera.lookAt(player.position.x, player.position.y + 1.8, player.position.z);
// सेफ ज़ोन सिकुड़ना और ज़ोन डैमेज
if (zoneRadius > 20) {
zoneRadius -= 0.012;
safeZoneMesh.scale.set(zoneRadius / 140, 1, zoneRadius / 140);
document.getElementById('zone-rad').innerText = Math.round(zoneRadius);
}
const distFromCenter = Math.hypot(player.position.x, player.position.z);
if (distFromCenter > zoneRadius) {
document.getElementById('zone-alert').style.display = 'block';
if (time - lastZoneDamageTime > 1000) {
lastZoneDamageTime = time;
hp -= 8;
updateHUD();
if (hp <= 0) finishGame(false);
}
} else {
document.getElementById('zone-alert').style.display = 'none';
}
// प्लेयर की गोलियाँ
for (let i = bullets.length - 1; i >= 0; i--) {
const b = bullets[i];
b.position.add(b.userData.vel);
if (b.position.distanceTo(player.position) > 150) {
scene.remove(b); bullets.splice(i, 1); continue;
}
for (let j = enemies.length - 1; j >= 0; j--) {
const en = enemies[j];
if (Math.hypot(b.position.x - en.position.x, b.position.z - en.position.z) < 1.0 && b.position.y < 3) {
// हेडशॉट या बॉडी शॉट चेक
const isHeadshot = b.position.y > 2.1;
en.userData.hp -= isHeadshot ? 100 : 35;
scene.remove(b); bullets.splice(i, 1);
if (en.userData.hp <= 0) {
scene.remove(en); enemies.splice(j, 1);
kills++; alive--;
updateHUD();
if (alive <= 1) finishGame(true);
}
break;
}
}
}
// दुश्मनों का AI
enemies.forEach(en => {
en.lookAt(player.position.x, 0, player.position.z);
const dist = en.position.distanceTo(player.position);
if (dist > 14 && dist < 95 && !isParachuting) en.translateZ(0.09);
if (dist < 60 && !isParachuting && time - en.userData.lastShot > 2000) {
en.userData.lastShot = time;
const eb = new THREE.Mesh(new THREE.SphereGeometry(0.15), new THREE.MeshBasicMaterial({ color: 0xff1744 }));
eb.position.copy(en.position);
eb.position.y += 1.5;
eb.userData.vel = new THREE.Vector3().subVectors(player.position, en.position).normalize().multiplyScalar(1.0);
scene.add(eb);
enemyBullets.push(eb);
}
});
// दुश्मन की गोलियाँ (Gloo Wall या प्लेयर से टकराना)
for (let i = enemyBullets.length - 1; i >= 0; i--) {
const eb = enemyBullets[i];
eb.position.add(eb.userData.vel);
// क्या गोली Gloo Wall से टकराई?
let hitWall = false;
for (let w = glooWalls.length - 1; w >= 0; w--) {
if (eb.position.distanceTo(glooWalls[w].position) < 2.1) {
glooWalls[w].userData.hp -= 25;
if (glooWalls[w].userData.hp <= 0) {
scene.remove(glooWalls[w]); glooWalls.splice(w, 1);
}
hitWall = true; break;
}
}
if (hitWall) { scene.remove(eb); enemyBullets.splice(i, 1); continue; }
// क्या गोली प्लेयर को लगी?
if (eb.position.distanceTo(player.position) < 1.3) {
hp -= 14;
updateHUD();
scene.remove(eb); enemyBullets.splice(i, 1);
if (hp <= 0) finishGame(false);
} else if (eb.position.distanceTo(player.position) > 120) {
scene.remove(eb); enemyBullets.splice(i, 1);
}
}
renderer.render(scene, camera);
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
animate(0);
</script>
</body>
</html>
2
2
144KB
614KB
808.0ms
128.0ms
808.0ms