<!DOCTYPE html>
<html lang="hi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>3D Battle Royale - 4K Ultra HD Edition</title>
<style>
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body { margin: 0; overflow: hidden; background: #000; font-family: 'Segoe UI', Arial, sans-serif; user-select: none; touch-action: none; }
/* मिनी-मैप रडार */
#minimap-container {
position: absolute; top: 10px; left: 10px; width: 114px; height: 114px;
border-radius: 50%; border: 2px solid rgba(255, 255, 255, 0.9);
background: rgba(10, 22, 10, 0.85); overflow: hidden; z-index: 15;
box-shadow: 0 4px 15px rgba(0,0,0,0.85); pointer-events: none;
}
#minimap { width: 100%; height: 100%; display: block; }
#location-name {
position: absolute; top: 127px; left: 14px; color: #fff; font-size: 11px;
font-weight: bold; text-shadow: 1px 1px 3px #000; z-index: 15; pointer-events: none;
background: rgba(0,0,0,0.55); padding: 2px 8px; border-radius: 4px;
}
/* टॉप दायाँ HUD + 4K बैज */
#hud-right {
position: absolute; top: 10px; right: 10px; display: flex; flex-direction: column;
align-items: flex-end; gap: 5px; z-index: 15;
}
.top-row { display: flex; gap: 6px; align-items: center; }
#quality-btn {
background: linear-gradient(45deg, #ffd700, #ff8f00); color: #000;
border: 1.5px solid #fff; padding: 4px 10px; border-radius: 5px;
font-weight: 900; font-size: 11px; cursor: pointer; box-shadow: 0 0 10px rgba(255,215,0,0.6);
}
.stat-box {
background: rgba(0, 0, 0, 0.65); color: white; padding: 5px 12px;
border-radius: 5px; border-right: 3px solid #ff9800; font-weight: bold; font-size: 12px;
pointer-events: none;
}
#kill-feed {
font-size: 11px; color: #ffeb3b; background: rgba(0,0,0,0.75);
padding: 4px 10px; border-radius: 4px; display: none; pointer-events: none;
}
#center-banner {
position: absolute; top: 18%; left: 50%; transform: translate(-50%, -50%);
color: #ff9800; font-size: 22px; font-weight: 900; text-shadow: 0 2px 10px #000;
letter-spacing: 1px; pointer-events: none; z-index: 22; display: none;
}
/* नीचे बीच में: वेपन, एमो और HP */
#bottom-center-hud {
position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%);
display: flex; flex-direction: column; align-items: center; gap: 5px;
z-index: 15; pointer-events: none;
}
#weapon-slots { display: flex; gap: 8px; pointer-events: auto; }
.w-slot {
background: rgba(0,0,0,0.68); border: 1.5px solid #666; color: #ccc;
padding: 4px 10px; border-radius: 5px; font-size: 11px; font-weight: bold; cursor: pointer;
}
.w-slot.active { border-color: #ff9800; background: rgba(255, 152, 0, 0.4); color: #fff; }
#hp-container {
width: 225px; background: rgba(0,0,0,0.72); padding: 4px 8px; border-radius: 6px;
border: 1px solid rgba(255,255,255,0.28);
}
#hp-text { color: white; font-size: 11px; font-weight: bold; display: flex; justify-content: space-between; }
#hp-bar-wrap { width: 100%; height: 7px; background: #222; margin-top: 2px; border-radius: 4px; overflow: hidden; }
#hp-bar { width: 100%; height: 100%; background: linear-gradient(90deg, #43a047, #8bc34a); transition: 0.15s; }
#damage-vignette {
position: fixed; inset: 0; pointer-events: none; z-index: 8; opacity: 0;
box-shadow: inset 0 0 75px 30px rgba(255, 0, 0, 0.85); transition: opacity 0.2s;
}
#reload-banner {
position: absolute; top: 38%; left: 50%; transform: translate(-50%, -50%);
background: rgba(0,0,0,0.85); color: #ffca28; padding: 5px 14px;
border-radius: 20px; font-size: 12px; font-weight: bold; display: none; z-index: 20;
border: 1px solid #ffca28;
}
#zone-alert {
position: absolute; top: 14px; left: 50%; transform: translateX(-50%);
background: rgba(3, 169, 244, 0.88); color: white; padding: 4px 14px;
border-radius: 15px; font-size: 11px; font-weight: bold; display: none; z-index: 15;
}
.dmg-popup {
position: absolute; font-weight: 900; font-size: 18px; pointer-events: none;
text-shadow: 1px 1px 4px #000; z-index: 20; animation: floatUp 0.7s ease-out forwards;
}
@keyframes floatUp {
0% { opacity: 1; transform: translateY(0) scale(1); }
100% { opacity: 0; transform: translateY(-48px) scale(1.25); }
}
/* क्रॉसहेयर + स्कोप */
#crosshair {
position: absolute; top: 50%; left: 50%; width: 22px; height: 22px;
transform: translate(-50%, -50%); pointer-events: none; z-index: 10;
}
#crosshair::before, #crosshair::after { content: ''; position: absolute; background: rgba(255, 255, 255, 0.92); transition: 0.1s; }
#crosshair::before { top: 10px; left: 0; width: 22px; height: 2px; }
#crosshair::after { top: 0; left: 10px; width: 2px; height: 22px; }
#crosshair.hit::before, #crosshair.hit::after { background: #ff1744; transform: scale(1.3); }
#scope-overlay {
display: none; position: fixed; inset: 0; pointer-events: none; z-index: 9;
background: radial-gradient(circle, transparent 24%, rgba(0,0,0,0.96) 28%);
}
/* कंट्रोल्स */
#joystick-zone {
position: absolute; bottom: 18px; left: 18px; width: 105px; height: 105px;
background: rgba(255, 255, 255, 0.12); border: 1.5px solid rgba(255,255,255,0.35);
border-radius: 50%; z-index: 15; touch-action: none;
}
#joystick-knob {
position: absolute; top: 32px; left: 32px; width: 40px; height: 40px;
background: rgba(255, 152, 0, 0.85); border-radius: 50%; pointer-events: none;
}
#look-zone { position: absolute; top: 0; right: 0; width: 65%; height: 100%; z-index: 5; touch-action: none; }
.btn {
position: absolute; border-radius: 50%; border: 1.5px solid rgba(255,255,255,0.8);
color: white; font-weight: bold; z-index: 15; touch-action: none;
display: flex; flex-direction: column; align-items: center; justify-content: center;
background: rgba(0, 0, 0, 0.55); font-size: 10px; text-align: center;
}
#fireBtn {
bottom: 20px; right: 18px; width: 74px; height: 74px;
background: rgba(255, 87, 34, 0.85); font-size: 14px; border-width: 2px;
}
#fireBtn:active { transform: scale(0.92); background: #ff5722; }
#jumpBtn { bottom: 106px; right: 18px; width: 44px; height: 44px; }
#crouchBtn { bottom: 158px; right: 20px; width: 42px; height: 42px; }
#scopeBtn { bottom: 106px; right: 72px; width: 44px; height: 44px; }
#reloadBtn { bottom: 158px; right: 72px; width: 42px; height: 42px; background: rgba(255, 193, 7, 0.45); }
#glooBtn { bottom: 20px; right: 102px; width: 46px; height: 46px; background: rgba(0, 188, 212, 0.65); }
#grenadeBtn { bottom: 20px; right: 156px; width: 44px; height: 44px; background: rgba(244, 67, 54, 0.65); }
#medkitBtn { bottom: 20px; right: 208px; width: 44px; height: 44px; background: rgba(76, 175, 80, 0.65); }
#abilityBtn {
bottom: 82px; right: 134px; width: 52px; height: 52px;
background: linear-gradient(135deg, #ff9800, #e91e63);
border: 2px solid #fff; font-size: 10px; box-shadow: 0 0 12px rgba(255, 152, 0, 0.7);
}
#abilityBtn.cooldown { background: rgba(80, 80, 80, 0.7); box-shadow: none; border-color: #888; }
#sprintBtn { bottom: 132px; left: 44px; width: 42px; height: 42px; background: rgba(255, 152, 0, 0.55); }
/* लॉबी स्क्रीन */
#overlayScreen {
position: fixed; inset: 0; background: radial-gradient(circle at center, #261c1a, #090d12);
color: white; display: flex; flex-direction: column; align-items: center; justify-content: center;
z-index: 30; text-align: center; padding: 15px;
}
.uhd-badge {
background: linear-gradient(90deg, #ffd700, #ff9800); color: #000;
padding: 3px 12px; border-radius: 20px; font-weight: 900; font-size: 11px;
margin-bottom: 6px; letter-spacing: 1px;
}
.ability-cards { display: flex; gap: 10px; margin: 12px 0; flex-wrap: wrap; justify-content: center; }
.card {
background: rgba(255,255,255,0.08); border: 2px solid #555; border-radius: 10px;
padding: 10px; width: 130px; cursor: pointer; transition: 0.2s;
}
.card.selected { border-color: #ff9800; background: rgba(255, 152, 0, 0.25); transform: scale(1.04); }
.card h3 { margin: 4px 0; font-size: 13px; color: #ff9800; }
.card p { margin: 0; font-size: 11px; color: #ddd; }
.main-btn {
background: linear-gradient(45deg, #ff9800, #ff5722); color: white; border: none;
padding: 12px 38px; font-size: 18px; font-weight: bold; border-radius: 8px;
margin-top: 10px; cursor: pointer; box-shadow: 0 4px 15px rgba(255, 87, 34, 0.5);
}
</style>
</head>
<body>
<div id="damage-vignette"></div>
<div id="reload-banner">🔄 RELOADING...</div>
<div id="center-banner"></div>
<div id="minimap-container"><canvas id="minimap" width="114" height="114"></canvas></div>
<div id="location-name">📍 CLOCK TOWER</div>
<div id="hud-right">
<div class="top-row">
<button id="quality-btn">4K ULTRA</button>
<div class="stat-box">ALIVE: <span id="alive-val">15</span> | KILLS: <span id="kills-val">0</span></div>
</div>
<div class="stat-box" style="border-right-color: #00e5ff;">ZONE: <span id="zone-rad">165</span>m</div>
<div id="kill-feed"></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>
<div id="bottom-center-hud">
<div id="weapon-slots">
<div class="w-slot active" id="slot-ak">1. AK-47 [<span id="ammo-ak">30</span>/30]</div>
<div class="w-slot" id="slot-awm">2. AWM [<span id="ammo-awm">5</span>/5]</div>
</div>
<div id="hp-container">
<div id="hp-text"><span>HP: <span id="hp-val">200</span>/200</span><span>🛡️ VEST LVL 3</span></div>
<div id="hp-bar-wrap"><div id="hp-bar"></div></div>
</div>
</div>
<button class="btn" id="fireBtn">FIRE</button>
<button class="btn" id="jumpBtn">JUMP</button>
<button class="btn" id="crouchBtn">SIT</button>
<button class="btn" id="scopeBtn">SCOPE</button>
<button class="btn" id="reloadBtn">RELOAD</button>
<button class="btn" id="glooBtn">WALL<br>(<span id="gloo-val">4</span>)</button>
<button class="btn" id="grenadeBtn">BOMB<br>(<span id="nade-val">3</span>)</button>
<button class="btn" id="medkitBtn">+HP<br>(<span id="med-val">3</span>)</button>
<button class="btn" id="abilityBtn">SKILL<br><span id="skill-status">READY</span></button>
<div id="overlayScreen">
<div class="uhd-badge">4K ULTRA HD • 2048px SHADOWS • PBR</div>
<h1 id="screenTitle" style="color:#ff9800; font-size:24px; margin:0;">BATTLE ROYALE 3D: 4K EDITION</h1>
<p style="font-size:12px; color:#ccc; margin:4px 0 8px;">1024px HD टेक्सचर, 16x एनिसोट्रॉपिक फिल्टरिंग, शार्प शैडोज़ और रियलिस्टिक एक्शन</p>
<div class="ability-cards" id="cardContainer">
<div class="card selected" data-skill="alok">
<h3>⚡ हील + स्पीड</h3>
<p>5s तेज़ दौड़ और लगातार +HP रिकवरी</p>
</div>
<div class="card" data-skill="chrono">
<h3>🛡️ एनर्जी शील्ड</h3>
<p>6s 360° सुरक्षा कवच, गोली अंदर नहीं आएगी</p>
</div>
<div class="card" data-skill="wukong">
<h3>🌿 बुश पावर</h3>
<p>झाड़ी बनकर छिपें, दुश्मन देख नहीं पाएंगे</p>
</div>
</div>
<button class="main-btn" id="startBtn">START 4K MATCH</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// ==========================================
// 1. 4K रेंडरर और हाई-डेफिनिशन टेक्सचर सेटअप
// ==========================================
const renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: "high-performance" });
renderer.setSize(window.innerWidth, window.innerHeight);
// 4K पिक्सल डेंसिटी (Ultra-Sharp Pixel Ratio)
let is4KMode = true;
const ultraDPR = Math.max(window.devicePixelRatio || 2, 2.5);
renderer.setPixelRatio(ultraDPR);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.1;
renderer.outputEncoding = THREE.sRGBEncoding;
document.body.appendChild(renderer.domElement);
const maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
// 4K क्वालिटी टॉगल बटन (4K ULTRA vs 60 FPS)
const qualityBtn = document.getElementById('quality-btn');
qualityBtn.addEventListener('click', () => {
is4KMode = !is4KMode;
if (is4KMode) {
renderer.setPixelRatio(ultraDPR);
qualityBtn.innerText = "4K ULTRA";
qualityBtn.style.background = "linear-gradient(45deg, #ffd700, #ff8f00)";
} else {
renderer.setPixelRatio(1.25);
qualityBtn.innerText = "HD 60FPS";
qualityBtn.style.background = "#4caf50";
}
});
// 1024x1024 हाई-रेज़ोल्यूशन प्रोसीजरल PBR टेक्सचर्स
function create4KGrassTexture() {
const c = document.createElement('canvas'); c.width = 1024; c.height = 1024;
const ctx = c.getContext('2d');
ctx.fillStyle = '#366322'; ctx.fillRect(0, 0, 1024, 1024);
for (let i = 0; i < 45000; i++) {
const x = Math.random() * 1024, y = Math.random() * 1024;
const r = Math.random();
ctx.fillStyle = r < 0.4 ? '#234215' : (r < 0.85 ? '#4f8534' : '#689f38');
ctx.fillRect(x, y, 2, 5);
}
const tex = new THREE.CanvasTexture(c);
tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set(60, 60);
tex.anisotropy = maxAnisotropy;
return tex;
}
function create4KRoadTexture() {
const c = document.createElement('canvas'); c.width = 512; c.height = 1024;
const ctx = c.getContext('2d');
ctx.fillStyle = '#222222'; ctx.fillRect(0, 0, 512, 1024);
for (let i = 0; i < 18000; i++) {
ctx.fillStyle = Math.random() > 0.5 ? '#181818' : '#323232';
ctx.fillRect(Math.random()*512, Math.random()*1024, 2, 2);
}
ctx.fillStyle = '#e0e0e0'; ctx.fillRect(22, 0, 14, 1024); ctx.fillRect(476, 0, 14, 1024);
ctx.fillStyle = '#ffca28'; ctx.fillRect(248, 60, 16, 360); ctx.fillRect(248, 560, 16, 360);
const tex = new THREE.CanvasTexture(c);
tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set(1, 34);
tex.anisotropy = maxAnisotropy;
return tex;
}
function create4KHouseWallTexture() {
const c = document.createElement('canvas'); c.width = 1024; c.height = 1024;
const ctx = c.getContext('2d');
ctx.fillStyle = '#d7ccc8'; ctx.fillRect(0, 0, 1024, 1024);
// ईंटों का बारीक 4K पैटर्न
for (let y = 0; y < 1024; y += 32) {
ctx.fillStyle = 'rgba(0,0,0,0.08)';
ctx.fillRect(0, y, 1024, 3);
for (let x = (y % 64 === 0 ? 0 : 32); x < 1024; x += 64) {
ctx.fillRect(x, y, 3, 32);
}
}
// खिड़की और दरवाज़ा
ctx.fillStyle = '#3e2723'; ctx.fillRect(160, 280, 220, 260);
ctx.fillStyle = '#ffecb3'; ctx.fillRect(184, 304, 172, 212);
ctx.fillStyle = '#4e342e'; ctx.fillRect(580, 380, 220, 644);
const tex = new THREE.CanvasTexture(c);
tex.anisotropy = maxAnisotropy;
return tex;
}
let selectedAbility = 'alok';
document.querySelectorAll('.card').forEach(card => {
card.addEventListener('click', () => {
document.querySelectorAll('.card').forEach(c => c.classList.remove('selected'));
card.classList.add('selected');
selectedAbility = card.getAttribute('data-skill');
});
});
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function playSound(freqStart, freqEnd, duration, type = 'sawtooth', vol = 0.2) {
if (audioCtx.state === 'suspended') audioCtx.resume();
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = type;
osc.frequency.setValueAtTime(freqStart, audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(freqEnd, audioCtx.currentTime + duration);
gain.gain.setValueAtTime(vol, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + duration);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
osc.stop(audioCtx.currentTime + duration);
}
function playExplosionSound() {
playSound(95, 18, 0.65, 'sawtooth', 0.45);
playSound(60, 12, 0.75, 'square', 0.35);
}
// 2. सीन, 2048px 4K शैडोज़ और वेदर
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xd99b66);
scene.fog = new THREE.FogExp2(0xd9a070, 0.004);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 850);
const hemiLight = new THREE.HemisphereLight(0xffe0b2, 0x2e4221, 0.85);
scene.add(hemiLight);
const sun = new THREE.DirectionalLight(0xffb74d, 1.3);
sun.position.set(110, 95, 80);
sun.castShadow = true;
// 4K अल्ट्रा-शार्प शैडो मैप (2048x2048)
sun.shadow.mapSize.width = 2048;
sun.shadow.mapSize.height = 2048;
sun.shadow.bias = -0.0005;
const d = 155;
sun.shadow.camera.left = -d; sun.shadow.camera.right = d;
sun.shadow.camera.top = d; sun.shadow.camera.bottom = -d;
scene.add(sun);
const sunDisc = new THREE.Mesh(
new THREE.SphereGeometry(18, 32, 32),
new THREE.MeshBasicMaterial({ color: 0xffe082, fog: false })
);
sunDisc.position.set(280, 210, 200);
scene.add(sunDisc);
// 3D बादल
const clouds = [];
const cloudMat = new THREE.MeshBasicMaterial({ color: 0xffe0b2, transparent: true, opacity: 0.65 });
for (let i = 0; i < 24; i++) {
const cloud = new THREE.Group();
for (let j = 0; j < 3; j++) {
const puff = new THREE.Mesh(new THREE.SphereGeometry(6 + Math.random() * 5, 12, 12), cloudMat);
puff.position.set(j * 6, Math.random() * 2, Math.random() * 4);
puff.scale.set(1.5, 0.5, 1.0);
cloud.add(puff);
}
cloud.position.set((Math.random() - 0.5) * 480, 75 + Math.random() * 25, (Math.random() - 0.5) * 480);
scene.add(cloud); clouds.push(cloud);
}
// 3D बारिश सिस्टम
const rainCount = 850;
const rainGeo = new THREE.BufferGeometry();
const rainPos = new Float32Array(rainCount * 3);
for (let i = 0; i < rainCount * 3; i += 3) {
rainPos[i] = (Math.random() - 0.5) * 140;
rainPos[i+1] = Math.random() * 45;
rainPos[i+2] = (Math.random() - 0.5) * 140;
}
rainGeo.setAttribute('position', new THREE.BufferAttribute(rainPos, 3));
const rainSystem = new THREE.Points(rainGeo, new THREE.PointsMaterial({ color: 0xbbdefb, size: 0.22, transparent: true, opacity: 0.65 }));
rainSystem.visible = false;
scene.add(rainSystem);
// चारों तरफ ऊँचे पहाड़
const mountainMat = new THREE.MeshStandardMaterial({ color: 0x4e342e, roughness: 0.95 });
for (let i = 0; i < 26; i++) {
const ang = (i / 26) * Math.PI * 2;
const mHeight = 50 + Math.random() * 45;
const mountain = new THREE.Mesh(new THREE.ConeGeometry(40, mHeight, 9), mountainMat);
mountain.position.set(Math.cos(ang) * 240, mHeight / 2 - 2, Math.sin(ang) * 240);
scene.add(mountain);
}
// 3. 4K मैप, सड़कें और इमारतें
const MAP_SIZE = 440;
const grassTex = create4KGrassTexture();
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(MAP_SIZE, MAP_SIZE),
new THREE.MeshStandardMaterial({ map: grassTex, bumpMap: grassTex, bumpScale: 0.18, roughness: 0.92 })
);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
const roadTex = create4KRoadTexture();
const roadMat = new THREE.MeshStandardMaterial({ map: roadTex, bumpMap: roadTex, bumpScale: 0.1, roughness: 0.88 });
const road1 = new THREE.Mesh(new THREE.PlaneGeometry(12, MAP_SIZE), roadMat);
road1.rotation.x = -Math.PI / 2; road1.position.y = 0.03; road1.receiveShadow = true;
const road2 = new THREE.Mesh(new THREE.PlaneGeometry(12, MAP_SIZE), roadMat);
road2.rotation.x = -Math.PI / 2; road2.rotation.z = Math.PI / 2; road2.position.y = 0.03; road2.receiveShadow = true;
scene.add(road1, road2);
let zoneRadius = 165;
const safeZoneMesh = new THREE.Mesh(
new THREE.CylinderGeometry(zoneRadius, zoneRadius, 32, 64, 1, true),
new THREE.MeshBasicMaterial({ color: 0x00b0ff, transparent: true, opacity: 0.22, side: THREE.DoubleSide })
);
safeZoneMesh.position.y = 16;
scene.add(safeZoneMesh);
const solidObjects = [], glooWalls = [], lootItems = [], sparks = [], grenades = [], shells = [];
function buildFullMap() {
const houseWallTex = create4KHouseWallTexture();
const houseMat = new THREE.MeshStandardMaterial({ map: houseWallTex, bumpMap: houseWallTex, bumpScale: 0.15, roughness: 0.78 });
const roofMat = new THREE.MeshStandardMaterial({ color: 0x5d4037, roughness: 0.72 });
const towerMat = new THREE.MeshStandardMaterial({ color: 0x8d6e63, roughness: 0.8 });
const treeWood = new THREE.MeshStandardMaterial({ color: 0x3e2723 });
const treeLeaf = new THREE.MeshStandardMaterial({ color: 0x1b5e20 });
const rockMat = new THREE.MeshStandardMaterial({ color: 0x616161, roughness: 0.88 });
// CLOCK TOWER
const clockBase = new THREE.Mesh(new THREE.BoxGeometry(9, 15, 9), towerMat);
clockBase.position.set(0, 7.5, -35); clockBase.castShadow = true; clockBase.receiveShadow = true;
const clockTop = new THREE.Mesh(new THREE.ConeGeometry(7, 5, 4), roofMat);
clockTop.position.set(0, 17.5, -35); clockTop.rotation.y = Math.PI / 4;
const clockDial = new THREE.Mesh(new THREE.CircleGeometry(2.1, 32), new THREE.MeshBasicMaterial({ color: 0xfff8e1 }));
clockDial.position.set(0, 11.5, -30.4);
scene.add(clockBase, clockTop, clockDial);
solidObjects.push({ x: 0, z: -35, r: 5.5 });
// BIMASAKTI STRIP TOWER
const bimaTower = new THREE.Mesh(new THREE.CylinderGeometry(3.5, 5.2, 24, 16), new THREE.MeshStandardMaterial({ color: 0x455a64, metalness: 0.3, roughness: 0.6 }));
bimaTower.position.set(65, 12, 45); bimaTower.castShadow = true; bimaTower.receiveShadow = true;
scene.add(bimaTower);
solidObjects.push({ x: 65, z: 45, r: 4.8 });
for (let i = 0; i < 75; i++) {
const x = (Math.random() - 0.5) * 330;
const z = (Math.random() - 0.5) * 330;
if (Math.abs(x) < 13 || Math.abs(z) < 13 || Math.hypot(x, z + 35) < 16) continue;
if (i % 4 === 0) {
const house = new THREE.Mesh(new THREE.BoxGeometry(7.5, 4.6, 7.5), houseMat);
house.position.set(x, 2.3, z); house.castShadow = true; house.receiveShadow = true;
const roof = new THREE.Mesh(new THREE.ConeGeometry(5.8, 2.6, 4), roofMat);
roof.position.set(x, 5.9, z); roof.rotation.y = Math.PI / 4; roof.castShadow = true;
scene.add(house, roof);
solidObjects.push({ x, z, r: 4.6 });
} else if (i % 4 === 1) {
const rock = new THREE.Mesh(new THREE.DodecahedronGeometry(1.9, 1), rockMat);
rock.position.set(x, 1.2, z); rock.castShadow = true; rock.receiveShadow = true;
scene.add(rock);
solidObjects.push({ x, z, r: 1.9 });
} else {
const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.35, 0.55, 4.5, 12), treeWood);
trunk.position.set(x, 2.25, z); trunk.castShadow = true;
const leaves = new THREE.Mesh(new THREE.ConeGeometry(2.8, 6.2, 12), treeLeaf);
leaves.position.set(x, 6.5, z); leaves.castShadow = true;
scene.add(trunk, leaves);
solidObjects.push({ x, z, r: 0.8 });
}
}
const grassBladeMat = new THREE.MeshStandardMaterial({ color: 0x2e5e1e, roughness: 0.9 });
for (let g = 0; g < 180; g++) {
const gx = (Math.random() - 0.5) * 260;
const gz = (Math.random() - 0.5) * 260;
if (Math.abs(gx) < 8 || Math.abs(gz) < 8) continue;
const tuft = new THREE.Mesh(new THREE.ConeGeometry(0.45, 0.75, 6), grassBladeMat);
tuft.position.set(gx, 0.35, gz);
scene.add(tuft);
}
for (let i = 0; i < 30; i++) {
const lx = (Math.random() - 0.5) * 250;
const lz = (Math.random() - 0.5) * 250;
const types = ['medkit', 'gloo', 'grenade'];
spawnLootBox(lx, lz, types[i % 3]);
}
}
function spawnLootBox(x, z, type) {
const colors = { medkit: 0x00e676, gloo: 0x00e5ff, grenade: 0xff5252, crate: 0xffd700 };
const box = new THREE.Mesh(
new THREE.BoxGeometry(type === 'crate' ? 1.3 : 0.95, 0.65, type === 'crate' ? 1.3 : 0.95),
new THREE.MeshStandardMaterial({ color: colors[type], emissive: colors[type], emissiveIntensity: 0.35, metalness: 0.3, roughness: 0.4 })
);
box.position.set(x, 0.45, z);
box.castShadow = true;
box.userData = { type };
scene.add(box);
lootItems.push(box);
}
buildFullMap();
let airdropObj = null;
function triggerAirdrop() {
const ax = (Math.random() - 0.5) * 120;
const az = (Math.random() - 0.5) * 120;
const group = new THREE.Group();
const crate = new THREE.Mesh(
new THREE.BoxGeometry(2.4, 2.4, 2.4),
new THREE.MeshStandardMaterial({ color: 0x1565c0, metalness: 0.5, roughness: 0.35 })
);
crate.castShadow = true;
const stripe = new THREE.Mesh(
new THREE.BoxGeometry(2.46, 0.5, 2.46),
new THREE.MeshBasicMaterial({ color: 0xffeb3b })
);
const chute = new THREE.Mesh(
new THREE.SphereGeometry(3.8, 16, 12, 0, Math.PI * 2, 0, Math.PI / 2),
new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.DoubleSide })
);
chute.position.y = 5.5;
const smokeBeam = new THREE.Mesh(
new THREE.CylinderGeometry(0.4, 1.2, 45, 16, 1, true),
new THREE.MeshBasicMaterial({ color: 0xff1744, transparent: true, opacity: 0.35, side: THREE.DoubleSide })
);
smokeBeam.position.y = 22.5;
smokeBeam.visible = false;
group.add(crate, stripe, chute, smokeBeam);
group.position.set(ax, 65, az);
group.userData = { landed: false, looted: false, chute, smokeBeam };
scene.add(group);
airdropObj = group;
showCenterBanner("📦 AIRDROP INCOMING!");
}
function showCenterBanner(text) {
const b = document.getElementById('center-banner');
b.innerText = text; b.style.display = 'block';
setTimeout(() => { b.style.display = 'none'; }, 2400);
}
function resolveCollisions(pos) {
pos.x = Math.max(-195, Math.min(195, pos.x));
pos.z = Math.max(-195, Math.min(195, pos.z));
for (let i = 0; i < solidObjects.length; i++) {
const obj = solidObjects[i];
const dx = pos.x - obj.x;
const dz = pos.z - obj.z;
const dist = Math.hypot(dx, dz);
const minDist = obj.r + 0.65;
if (dist < minDist && dist > 0.001) {
const push = (minDist - dist) / dist;
pos.x += dx * push;
pos.z += dz * push;
}
}
}
function spawnHitSparks(pos, color = 0xffeb3b, count = 7) {
for (let i = 0; i < count; i++) {
const s = new THREE.Mesh(new THREE.SphereGeometry(0.1, 6, 6), new THREE.MeshBasicMaterial({ color }));
s.position.copy(pos);
s.userData.vel = new THREE.Vector3((Math.random()-0.5)*0.5, Math.random()*0.4, (Math.random()-0.5)*0.5);
s.userData.life = 18;
scene.add(s);
sparks.push(s);
}
}
function ejectBulletShell() {
const shell = new THREE.Mesh(
new THREE.CylinderGeometry(0.025, 0.025, 0.11, 8),
new THREE.MeshStandardMaterial({ color: 0xffd54f, metalness: 0.9, roughness: 0.2 })
);
const right = new THREE.Vector3(Math.cos(yaw), 0, -Math.sin(yaw));
shell.position.copy(player.position).addScaledVector(right, 0.55);
shell.position.y += 1.75;
shell.userData = {
vel: right.multiplyScalar(0.14 + Math.random()*0.06).add(new THREE.Vector3(0, 0.14, 0)),
life: 40
};
scene.add(shell);
shells.push(shell);
}
// 4. हाई-पॉली 4K कैरेक्टर मॉडल
function createRealisticHuman(shirtColor, pantsColor, isEnemy = false) {
const human = new THREE.Group();
const bodyContainer = new THREE.Group();
human.add(bodyContainer);
const skinMat = new THREE.MeshStandardMaterial({ color: 0xe0ac69, roughness: 0.45 });
const hairMat = new THREE.MeshStandardMaterial({ color: 0x1a1a1a, roughness: 0.85 });
const shirtMat = new THREE.MeshStandardMaterial({ color: shirtColor, roughness: 0.6 });
const vestMat = new THREE.MeshStandardMaterial({ color: 0x212121, metalness: 0.25, roughness: 0.45 });
const pantsMat = new THREE.MeshStandardMaterial({ color: pantsColor, roughness: 0.72 });
const bootMat = new THREE.MeshStandardMaterial({ color: 0x111111, metalness: 0.2, roughness: 0.35 });
const bagMat = new THREE.MeshStandardMaterial({ color: 0x3e2723, roughness: 0.78 });
const headGroup = new THREE.Group();
headGroup.position.y = 2.34;
const headMesh = new THREE.Mesh(new THREE.SphereGeometry(0.24, 24, 24), skinMat);
headMesh.scale.set(0.92, 1.08, 0.96);
const hairMesh = new THREE.Mesh(new THREE.SphereGeometry(0.255, 24, 24, 0, Math.PI * 2, 0, Math.PI * 0.52), hairMat);
hairMesh.scale.set(0.94, 1.05, 0.98); hairMesh.rotation.x = -0.18;
const glasses = new THREE.Mesh(new THREE.BoxGeometry(0.32, 0.07, 0.08), new THREE.MeshStandardMaterial({ color: 0x050505, metalness: 0.95, roughness: 0.1 }));
glasses.position.set(0, 0.03, -0.22);
headGroup.add(headMesh, hairMesh, glasses);
bodyContainer.add(headGroup);
const neck = new THREE.Mesh(new THREE.CylinderGeometry(0.085, 0.105, 0.18, 16), skinMat);
neck.position.y = 2.05;
const torso = new THREE.Mesh(new THREE.CylinderGeometry(0.27, 0.22, 0.85, 20), shirtMat);
torso.scale.set(1.12, 1, 0.68); torso.position.y = 1.56;
const vest = new THREE.Mesh(new THREE.CylinderGeometry(0.285, 0.24, 0.62, 20), vestMat);
vest.scale.set(1.14, 1, 0.72); vest.position.y = 1.6;
const backpack = new THREE.Mesh(new THREE.BoxGeometry(0.36, 0.48, 0.22), bagMat);
backpack.position.set(0, 1.62, 0.24);
bodyContainer.add(neck, torso, vest, backpack);
const leftArmPivot = new THREE.Group();
leftArmPivot.position.set(-0.37, 1.9, 0);
const lShoulder = new THREE.Mesh(new THREE.SphereGeometry(0.105, 14, 14), shirtMat);
const lArm = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.065, 0.48, 14), skinMat);
lArm.position.y = -0.24;
const lGlove = new THREE.Mesh(new THREE.SphereGeometry(0.072, 14, 14), bootMat);
lGlove.position.y = -0.5;
leftArmPivot.add(lShoulder, lArm, lGlove);
bodyContainer.add(leftArmPivot);
const rightArmPivot = new THREE.Group();
rightArmPivot.position.set(0.37, 1.9, 0);
const rShoulder = new THREE.Mesh(new THREE.SphereGeometry(0.105, 14, 14), shirtMat);
const rArm = new THREE.Mesh(new THREE.CylinderGeometry(0.085, 0.07, 0.48, 14), skinMat);
rArm.rotation.x = Math.PI / 2.25; rArm.position.set(0, -0.08, -0.22);
const gunGroup = new THREE.Group();
const gunBody = new THREE.Mesh(new THREE.BoxGeometry(0.075, 0.13, 0.85), new THREE.MeshStandardMaterial({ color: 0x1a1a1a, metalness: 0.85, roughness: 0.25 }));
const gunBarrel = new THREE.Mesh(new THREE.CylinderGeometry(0.018, 0.018, 0.45, 12), new THREE.MeshStandardMaterial({ color: 0x333333, metalness: 0.9, roughness: 0.2 }));
gunBarrel.rotation.x = Math.PI / 2; gunBarrel.position.set(0, 0.03, -0.55);
const muzzleFlash = new THREE.Mesh(new THREE.SphereGeometry(0.15, 10, 10), new THREE.MeshBasicMaterial({ color: 0xffab00 }));
muzzleFlash.position.set(0, 0.03, -0.82); muzzleFlash.visible = false;
gunGroup.add(gunBody, gunBarrel, muzzleFlash);
gunGroup.position.set(0, -0.14, -0.52);
rightArmPivot.add(rShoulder, rArm, gunGroup);
bodyContainer.add(rightArmPivot);
function buildLeg(xPos) {
const legPivot = new THREE.Group();
legPivot.position.set(xPos, 1.12, 0);
const leg = new THREE.Mesh(new THREE.CylinderGeometry(0.11, 0.08, 0.96, 16), pantsMat);
leg.position.y = -0.48;
const boot = new THREE.Mesh(new THREE.BoxGeometry(0.17, 0.16, 0.34), bootMat);
boot.position.set(0, -1.02, -0.06);
legPivot.add(leg, boot);
return legPivot;
}
const leftLegPivot = buildLeg(-0.15);
const rightLegPivot = buildLeg(0.15);
bodyContainer.add(leftLegPivot, rightLegPivot);
bodyContainer.traverse(o => { if(o.isMesh && o !== muzzleFlash) o.castShadow = true; });
const auraRing = new THREE.Mesh(
new THREE.RingGeometry(1.1, 1.5, 40),
new THREE.MeshBasicMaterial({ color: 0xffd700, side: THREE.DoubleSide, transparent: true, opacity: 0.75 })
);
auraRing.rotation.x = -Math.PI / 2; auraRing.position.y = 0.08; auraRing.visible = false;
human.add(auraRing);
const shieldDome = new THREE.Mesh(
new THREE.SphereGeometry(2.3, 28, 22),
new THREE.MeshBasicMaterial({ color: 0x00e5ff, wireframe: true, transparent: true, opacity: 0.45 })
);
shieldDome.position.y = 1.4; shieldDome.visible = false;
human.add(shieldDome);
const bushMesh = new THREE.Mesh(
new THREE.DodecahedronGeometry(1.35, 1),
new THREE.MeshStandardMaterial({ color: 0x2e7d32, roughness: 0.9 })
);
bushMesh.position.y = 1.15; bushMesh.visible = false;
human.add(bushMesh);
let hpBarMesh = null;
if (isEnemy) {
const hpBg = new THREE.Mesh(new THREE.PlaneGeometry(1.0, 0.12), new THREE.MeshBasicMaterial({ color: 0x000000, side: THREE.DoubleSide }));
hpBg.position.y = 2.85;
hpBarMesh = new THREE.Mesh(new THREE.PlaneGeometry(0.96, 0.09), new THREE.MeshBasicMaterial({ color: 0xff1744, side: THREE.DoubleSide }));
hpBarMesh.position.set(0, 2.85, 0.01);
human.add(hpBg, hpBarMesh);
}
let parachute = null;
if (!isEnemy) {
parachute = new THREE.Mesh(
new THREE.SphereGeometry(2.5, 18, 12, 0, Math.PI * 2, 0, Math.PI / 2),
new THREE.MeshStandardMaterial({ color: 0xff9800, side: THREE.DoubleSide })
);
parachute.position.y = 4.3;
human.add(parachute);
}
human.userData.limbs = {
bodyContainer, leftArm: leftArmPivot, rightArm: rightArmPivot,
leftLeg: leftLegPivot, rightLeg: rightLegPivot,
parachute, muzzleFlash, auraRing, shieldDome, bushMesh, hpBarMesh,
animTime: Math.random() * 10
};
return human;
}
let lastStepPhase = 0;
function animateHumanLimbs(human, isMoving, speedMultiplier = 1, isCrouching = false, isPlayer = false) {
const limbs = human.userData.limbs;
limbs.bodyContainer.scale.y = isCrouching ? 0.72 : 1.0;
if (isMoving) {
limbs.animTime += 0.18 * speedMultiplier;
const swing = Math.sin(limbs.animTime) * 0.68;
limbs.leftLeg.rotation.x = swing;
limbs.rightLeg.rotation.x = -swing;
limbs.leftArm.rotation.x = -swing * 0.85;
limbs.rightArm.rotation.x = Math.sin(limbs.animTime * 2) * 0.04;
limbs.bodyContainer.position.y = Math.abs(Math.cos(limbs.animTime)) * 0.06;
if (isPlayer) {
const phase = Math.floor(limbs.animTime / Math.PI);
if (phase !== lastStepPhase) {
lastStepPhase = phase;
playSound(120, 50, 0.05, 'triangle', 0.06);
}
}
} else {
limbs.animTime += 0.05;
limbs.leftLeg.rotation.x *= 0.8;
limbs.rightLeg.rotation.x *= 0.8;
limbs.leftArm.rotation.x *= 0.8;
limbs.rightArm.rotation.x = Math.sin(limbs.animTime) * 0.02;
limbs.bodyContainer.position.y = Math.sin(limbs.animTime) * 0.015;
}
}
const player = createRealisticHuman(0x1565c0, 0x263238, false);
player.position.set(0, 50, 0);
scene.add(player);
// गेम वेरिएबल्स
let gameStarted = false, isGameOver = false;
let hp = 200, kills = 0, alive = 15, glooCount = 4, medCount = 3, nadeCount = 3;
let currentWeapon = 'ak';
let ammo = { ak: 30, awm: 5 };
let maxAmmo = { ak: 30, awm: 5 };
let isReloading = false, isFiringHeld = false, lastShotTime = 0, recoilOffset = 0;
let yaw = 0, pitch = 0.08;
let velY = 0, isGrounded = false, isParachuting = true;
let isScoped = false, isSprinting = false, isCrouching = false;
let abilityActive = false, abilityCooldown = false;
let isShielded = false, isBush = false, speedBoost = 1.0;
const bullets = [], enemyBullets = [], enemies = [];
function createEnemies() {
const shirtColors = [0xc62828, 0x6a1b9a, 0x2e7d32, 0xef6c00];
for (let i = 0; i < 14; i++) {
const en = createRealisticHuman(shirtColors[i % shirtColors.length], 0x212121, true);
en.position.set((Math.random() - 0.5) * 230, 0, (Math.random() - 0.5) * 230);
resolveCollisions(en.position);
en.userData.hp = 100;
en.userData.lastShot = 0;
en.userData.strafeDir = Math.random() > 0.5 ? 1 : -1;
en.userData.name = `ProBot_${i + 1}`;
scene.add(en);
enemies.push(en);
}
}
createEnemies();
document.getElementById('slot-ak').addEventListener('click', () => switchWeapon('ak'));
document.getElementById('slot-awm').addEventListener('click', () => switchWeapon('awm'));
function switchWeapon(w) {
if (isReloading) return;
currentWeapon = w;
document.getElementById('slot-ak').classList.toggle('active', w === 'ak');
document.getElementById('slot-awm').classList.toggle('active', w === 'awm');
if (isScoped) {
camera.fov = w === 'awm' ? 16 : 35;
camera.updateProjectionMatrix();
}
}
function reloadWeapon() {
if (isReloading || ammo[currentWeapon] === maxAmmo[currentWeapon]) return;
isReloading = true;
document.getElementById('reload-banner').style.display = 'block';
playSound(300, 600, 0.25, 'square', 0.15);
setTimeout(() => {
ammo[currentWeapon] = maxAmmo[currentWeapon];
isReloading = false;
document.getElementById('reload-banner').style.display = 'none';
updateHUD();
playSound(600, 800, 0.15, 'sine', 0.15);
}, 1200);
}
function showDamagePopup(worldPos, dmg, isHead) {
const vec = worldPos.clone(); vec.y += 2.7; vec.project(camera);
const x = (vec.x * 0.5 + 0.5) * window.innerWidth;
const y = (-(vec.y * 0.5) + 0.5) * window.innerHeight;
const el = document.createElement('div');
el.className = 'dmg-popup';
el.style.left = x + 'px'; el.style.top = y + 'px';
el.style.color = isHead ? '#ff1744' : '#ffeb3b';
el.innerText = isHead ? `-${dmg} HEADSHOT!` : `-${dmg}`;
document.body.appendChild(el);
setTimeout(() => el.remove(), 700);
}
function showKillFeed(msg) {
const feed = document.getElementById('kill-feed');
feed.innerText = msg; feed.style.display = 'block';
setTimeout(() => { feed.style.display = 'none'; }, 2500);
}
function triggerHitmarker() {
const ch = document.getElementById('crosshair');
ch.classList.add('hit');
setTimeout(() => ch.classList.remove('hit'), 120);
}
function triggerDamageFlash() {
const vig = document.getElementById('damage-vignette');
vig.style.opacity = '1';
setTimeout(() => { vig.style.opacity = '0'; }, 220);
}
function activateAbility() {
if (!gameStarted || isGameOver || isParachuting || abilityActive || abilityCooldown) return;
abilityActive = true;
playSound(400, 900, 0.35, 'sine');
const limbs = player.userData.limbs;
const btn = document.getElementById('abilityBtn');
const statusTxt = document.getElementById('skill-status');
statusTxt.innerText = "ACTIVE";
let duration = 5000;
if (selectedAbility === 'alok') { limbs.auraRing.visible = true; speedBoost = 1.55; duration = 5000; }
else if (selectedAbility === 'chrono') { limbs.shieldDome.visible = true; isShielded = true; duration = 6000; }
else if (selectedAbility === 'wukong') { limbs.bodyContainer.visible = false; limbs.bushMesh.visible = true; isBush = true; duration = 7000; }
setTimeout(() => {
endAbilityEffect();
abilityCooldown = true; btn.classList.add('cooldown');
let cd = 10; statusTxt.innerText = cd + "s";
const timer = setInterval(() => {
cd--;
if (cd <= 0) { clearInterval(timer); abilityCooldown = false; btn.classList.remove('cooldown'); statusTxt.innerText = "READY"; }
else statusTxt.innerText = cd + "s";
}, 1000);
}, duration);
}
function endAbilityEffect() {
abilityActive = false;
const limbs = player.userData.limbs;
limbs.auraRing.visible = false; limbs.shieldDome.visible = false;
limbs.bushMesh.visible = false; limbs.bodyContainer.visible = true;
speedBoost = 1.0; isShielded = false; isBush = false;
}
const raycaster = new THREE.Raycaster();
function fireWeapon() {
if (!gameStarted || isGameOver || isParachuting || isReloading) return;
if (ammo[currentWeapon] <= 0) { reloadWeapon(); return; }
const now = performance.now();
const cooldown = currentWeapon === 'awm' ? 850 : 135;
if (now - lastShotTime < cooldown) return;
lastShotTime = now;
ammo[currentWeapon]--;
updateHUD();
if (ammo[currentWeapon] === 0) setTimeout(reloadWeapon, 250);
if (isBush) endAbilityEffect();
playSound(currentWeapon === 'awm' ? 105 : 185, 32, currentWeapon === 'awm' ? 0.25 : 0.1, 'sawtooth', 0.25);
recoilOffset = currentWeapon === 'awm' ? 0.14 : 0.045;
ejectBulletShell();
const flash = player.userData.limbs.muzzleFlash;
flash.visible = true;
setTimeout(() => { flash.visible = false; }, 55);
raycaster.setFromCamera(new THREE.Vector2(0, 0), camera);
const targetPoint = new THREE.Vector3();
raycaster.ray.at(130, targetPoint);
const spawnHeight = isCrouching ? 1.25 : 1.75;
const spawnPos = new THREE.Vector3(player.position.x, player.position.y + spawnHeight, player.position.z);
const dir = new THREE.Vector3().subVectors(targetPoint, spawnPos).normalize();
const bullet = new THREE.Mesh(
new THREE.CylinderGeometry(0.04, 0.04, 1.4, 8),
new THREE.MeshBasicMaterial({ color: currentWeapon === 'awm' ? 0x00e5ff : 0xffeb3b })
);
bullet.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir);
bullet.position.copy(spawnPos);
bullet.userData.vel = dir.multiplyScalar(currentWeapon === 'awm' ? 5.0 : 3.4);
bullet.userData.dmg = currentWeapon === 'awm' ? 120 : 35;
scene.add(bullet);
bullets.push(bullet);
}
function throwGrenade() {
if (!gameStarted || isGameOver || isParachuting || nadeCount <= 0) return;
nadeCount--; updateHUD();
if (isBush) endAbilityEffect();
playSound(300, 500, 0.15, 'sine');
const nade = new THREE.Mesh(
new THREE.SphereGeometry(0.22, 12, 12),
new THREE.MeshStandardMaterial({ color: 0x33691e, metalness: 0.5 })
);
nade.position.copy(player.position);
nade.position.y += 1.8;
const forward = new THREE.Vector3(-Math.sin(yaw), 0.35, -Math.cos(yaw)).normalize();
nade.userData = { vel: forward.multiplyScalar(0.65), timer: 135 };
scene.add(nade);
grenades.push(nade);
}
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: 160 };
scene.add(wall); glooWalls.push(wall);
}
// मल्टी-टच कंट्रोल्स
let joyX = 0, joyY = 0, joyTouchId = null;
const joyZone = document.getElementById('joystick-zone');
const joyKnob = document.getElementById('joystick-knob');
joyZone.addEventListener('touchstart', (e) => { e.preventDefault(); joyTouchId = e.changedTouches[0].identifier; });
joyZone.addEventListener('touchmove', (e) => {
e.preventDefault();
for (let i = 0; i < e.changedTouches.length; i++) {
const t = e.changedTouches[i];
if (t.identifier === joyTouchId) {
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), 32);
const ang = Math.atan2(dy, dx);
joyX = Math.cos(ang) * (dist / 32);
joyY = Math.sin(ang) * (dist / 32);
joyKnob.style.transform = `translate(${Math.cos(ang) * dist}px, ${Math.sin(ang) * dist}px)`;
}
}
});
const resetJoy = (e) => {
for (let i = 0; i < e.changedTouches.length; i++) {
if (e.changedTouches[i].identifier === joyTouchId) {
joyTouchId = null; joyX = 0; joyY = 0; joyKnob.style.transform = `translate(0,0)`;
}
}
};
joyZone.addEventListener('touchend', resetJoy); joyZone.addEventListener('touchcancel', resetJoy);
let lookTouchId = null, lastX = 0, lastY = 0;
const lookZone = document.getElementById('look-zone');
lookZone.addEventListener('touchstart', (e) => {
if (lookTouchId === null) {
const t = e.changedTouches[0]; lookTouchId = t.identifier;
lastX = t.clientX; lastY = t.clientY;
}
});
lookZone.addEventListener('touchmove', (e) => {
for (let i = 0; i < e.changedTouches.length; i++) {
const t = e.changedTouches[i];
if (t.identifier === lookTouchId) {
const sens = isScoped ? 0.0024 : 0.0068;
yaw -= (t.clientX - lastX) * sens;
pitch = Math.max(-0.22, Math.min(0.55, pitch + (t.clientY - lastY) * sens));
lastX = t.clientX; lastY = t.clientY;
}
}
});
const resetLook = (e) => {
for (let i = 0; i < e.changedTouches.length; i++) {
if (e.changedTouches[i].identifier === lookTouchId) lookTouchId = null;
}
};
lookZone.addEventListener('touchend', resetLook); lookZone.addEventListener('touchcancel', resetLook);
const fireBtn = document.getElementById('fireBtn');
fireBtn.addEventListener('touchstart', (e) => { e.preventDefault(); isFiringHeld = true; fireWeapon(); });
fireBtn.addEventListener('touchend', () => { isFiringHeld = false; });
fireBtn.addEventListener('mousedown', () => { isFiringHeld = true; fireWeapon(); });
fireBtn.addEventListener('mouseup', () => { isFiringHeld = false; });
document.getElementById('abilityBtn').addEventListener('touchstart', (e) => { e.preventDefault(); activateAbility(); });
document.getElementById('abilityBtn').addEventListener('click', activateAbility);
document.getElementById('reloadBtn').addEventListener('touchstart', (e) => { e.preventDefault(); reloadWeapon(); });
document.getElementById('reloadBtn').addEventListener('click', reloadWeapon);
document.getElementById('grenadeBtn').addEventListener('touchstart', (e) => { e.preventDefault(); throwGrenade(); });
document.getElementById('grenadeBtn').addEventListener('click', throwGrenade);
document.getElementById('jumpBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
if (isGrounded && !isParachuting) { isCrouching = false; velY = 0.36; isGrounded = false; }
});
document.getElementById('crouchBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
if (isGrounded && !isParachuting) {
isCrouching = !isCrouching;
document.getElementById('crouchBtn').style.background = isCrouching ? 'rgba(255, 152, 0, 0.8)' : 'rgba(0, 0, 0, 0.55)';
}
});
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(); playSound(500, 800, 0.2, 'sine'); }
});
document.getElementById('scopeBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
isScoped = !isScoped;
camera.fov = isScoped ? (currentWeapon === 'awm' ? 16 : 35) : 75;
camera.updateProjectionMatrix();
document.getElementById('scope-overlay').style.display = isScoped ? 'block' : 'none';
});
document.getElementById('sprintBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
isSprinting = !isSprinting; isCrouching = false;
document.getElementById('sprintBtn').style.background = isSprinting ? 'rgba(255, 87, 34, 0.85)' : 'rgba(255, 152, 0, 0.55)';
});
const keys = {};
window.addEventListener('keydown', (e) => {
keys[e.key.toLowerCase()] = true;
if (e.key === ' ' && isGrounded) { isCrouching = false; velY = 0.36; isGrounded = false; }
if (e.key === 'f' || e.key === 'Enter') fireWeapon();
if (e.key === 'r') reloadWeapon();
if (e.key === 'b') throwGrenade();
if (e.key === 'g') deployGlooWall();
if (e.key === 'c') activateAbility();
if (e.key === '1') switchWeapon('ak');
if (e.key === '2') switchWeapon('awm');
});
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;
setTimeout(triggerAirdrop, 12000);
});
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;
document.getElementById('nade-val').innerText = nadeCount;
document.getElementById('ammo-ak').innerText = ammo.ak;
document.getElementById('ammo-awm').innerText = ammo.awm;
}
function finishGame(isBooyah) {
isGameOver = true;
document.getElementById('screenTitle').innerText = isBooyah ? "🏆 BOOYAH! #1" : "ELIMINATED!";
document.getElementById('cardContainer').style.display = 'none';
document.getElementById('startBtn').innerText = "PLAY AGAIN";
document.getElementById('overlayScreen').style.display = 'flex';
}
const miniCanvas = document.getElementById('minimap');
const mCtx = miniCanvas.getContext('2d');
function drawMiniMap() {
const w = miniCanvas.width, h = miniCanvas.height, cx = w / 2, cy = h / 2;
const scale = 0.28;
mCtx.clearRect(0, 0, w, h);
mCtx.fillStyle = '#183317'; mCtx.fillRect(0, 0, w, h);
mCtx.fillStyle = '#444';
mCtx.fillRect(cx - player.position.x * scale - 2, 0, 4, h);
mCtx.fillRect(0, cy - player.position.z * scale - 2, w, 4);
mCtx.strokeStyle = '#00e5ff'; mCtx.lineWidth = 2;
mCtx.beginPath();
mCtx.arc(cx - player.position.x * scale, cy - player.position.z * scale, zoneRadius * scale, 0, Math.PI * 2);
mCtx.stroke();
if (airdropObj && !airdropObj.userData.looted) {
mCtx.fillStyle = '#00e676';
mCtx.beginPath();
mCtx.arc(cx + (airdropObj.position.x - player.position.x) * scale, cy + (airdropObj.position.z - player.position.z) * scale, 4, 0, Math.PI * 2);
mCtx.fill();
}
mCtx.fillStyle = '#ffeb3b';
lootItems.forEach(l => {
mCtx.fillRect(cx + (l.position.x - player.position.x) * scale - 1.5, cy + (l.position.z - player.position.z) * scale - 1.5, 3, 3);
});
mCtx.fillStyle = '#ff1744';
enemies.forEach(en => {
mCtx.beginPath();
mCtx.arc(cx + (en.position.x - player.position.x) * scale, cy + (en.position.z - player.position.z) * scale, 3, 0, Math.PI * 2);
mCtx.fill();
});
mCtx.save(); mCtx.translate(cx, cy); mCtx.rotate(-yaw);
mCtx.fillStyle = '#ffffff';
mCtx.beginPath(); mCtx.moveTo(0, -6); mCtx.lineTo(4, 5); mCtx.lineTo(0, 2); mCtx.lineTo(-4, 5); mCtx.closePath(); mCtx.fill();
mCtx.restore();
const locEl = document.getElementById('location-name');
if (Math.hypot(player.position.x, player.position.z + 35) < 45) locEl.innerText = "📍 CLOCK TOWER";
else if (Math.hypot(player.position.x - 65, player.position.z - 45) < 45) locEl.innerText = "📍 BIMASAKTI STRIP";
else if (player.position.x < -40) locEl.innerText = "📍 POCHINOK";
else locEl.innerText = "📍 BERMUDA VALLEY";
}
let lastZoneDamageTime = 0, lastHealTime = 0, isRaining = false;
function animate(time) {
requestAnimationFrame(animate);
if (!gameStarted || isGameOver) { renderer.render(scene, camera); return; }
if (isFiringHeld && currentWeapon === 'ak') fireWeapon();
if (time > 25000 && !isRaining) {
isRaining = true;
rainSystem.visible = true;
scene.background = new THREE.Color(0x546e7a);
scene.fog = new THREE.FogExp2(0x546e7a, 0.0055);
showCenterBanner("🌧️ WEATHER CHANGED: RAIN");
}
if (isRaining) {
rainSystem.position.set(player.position.x, 0, player.position.z);
const positions = rainSystem.geometry.attributes.position.array;
for (let i = 1; i < positions.length; i += 3) {
positions[i] -= 0.9;
if (positions[i] < 0) positions[i] = 45;
}
rainSystem.geometry.attributes.position.needsUpdate = true;
}
if (airdropObj && !airdropObj.userData.looted) {
if (!airdropObj.userData.landed) {
airdropObj.position.y -= 0.14;
if (airdropObj.position.y <= 1.2) {
airdropObj.position.y = 1.2;
airdropObj.userData.landed = true;
airdropObj.userData.chute.visible = false;
airdropObj.userData.smokeBeam.visible = true;
}
} else if (airdropObj.position.distanceTo(player.position) < 3.2) {
airdropObj.userData.looted = true;
airdropObj.userData.smokeBeam.visible = false;
hp = 200; medCount += 2; glooCount += 2; nadeCount += 2;
ammo.ak = 30; ammo.awm = 5;
updateHUD();
playSound(500, 1000, 0.3, 'sine');
showCenterBanner("🎁 AIRDROP LOOTED! FULL HP & AMMO!");
}
}
for (let i = shells.length - 1; i >= 0; i--) {
const sh = shells[i];
sh.position.add(sh.userData.vel);
sh.rotation.x += 0.3; sh.rotation.z += 0.2;
if (sh.position.y > 0.05) sh.userData.vel.y -= 0.015;
else { sh.position.y = 0.05; sh.userData.vel.set(0,0,0); }
sh.userData.life--;
if (sh.userData.life <= 0) { scene.remove(sh); shells.splice(i, 1); }
}
clouds.forEach(c => { c.position.x += 0.03; if (c.position.x > 250) c.position.x = -250; });
for (let i = sparks.length - 1; i >= 0; i--) {
const s = sparks[i];
s.position.add(s.userData.vel);
s.userData.life--;
if (s.userData.life <= 0) { scene.remove(s); sparks.splice(i, 1); }
}
for (let i = grenades.length - 1; i >= 0; i--) {
const g = grenades[i];
g.position.add(g.userData.vel);
g.userData.vel.y -= 0.025;
if (g.position.y <= 0.22) {
g.position.y = 0.22;
g.userData.vel.x *= 0.85; g.userData.vel.z *= 0.85; g.userData.vel.y = 0;
}
g.userData.timer--;
if (g.userData.timer <= 0) {
playExplosionSound();
spawnHitSparks(g.position, 0xff5722, 24);
spawnHitSparks(g.position, 0xffeb3b, 16);
for (let j = enemies.length - 1; j >= 0; j--) {
const en = enemies[j];
if (en.position.distanceTo(g.position) < 11) {
showDamagePopup(en.position, 200, true);
showKillFeed(`💥 आपने ${en.userData.name} को Grenade से उड़ाया!`);
spawnLootBox(en.position.x, en.position.z, 'crate');
scene.remove(en); enemies.splice(j, 1);
kills++; alive--; updateHUD();
if (alive <= 1) finishGame(true);
}
}
scene.remove(g); grenades.splice(i, 1);
}
}
if (abilityActive && selectedAbility === 'alok') {
player.userData.limbs.auraRing.rotation.z += 0.05;
if (time - lastHealTime > 500 && hp < 200) { lastHealTime = time; hp = Math.min(200, hp + 6); updateHUD(); }
}
if (isParachuting) {
player.position.y -= 0.3;
if (player.position.y <= 0) {
player.position.y = 0; isParachuting = false; isGrounded = true;
if (player.userData.limbs.parachute) player.userData.limbs.parachute.visible = false;
}
} else if (!isGrounded) {
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 baseSpeed = isCrouching ? 0.13 : (isSprinting ? 0.36 : 0.24);
const moveSpeed = baseSpeed * speedBoost;
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);
resolveCollisions(player.position);
for (let i = lootItems.length - 1; i >= 0; i--) {
const item = lootItems[i];
item.rotation.y += 0.04;
if (item.position.distanceTo(player.position) < 2.2 && !isParachuting) {
const t = item.userData.type;
if (t === 'medkit') medCount++;
else if (t === 'gloo') glooCount++;
else if (t === 'grenade') nadeCount++;
else if (t === 'crate') { medCount++; glooCount++; hp = Math.min(200, hp + 40); }
updateHUD(); playSound(600, 950, 0.12, 'sine');
scene.remove(item); lootItems.splice(i, 1);
}
}
const isPlayerMoving = Math.hypot(mx, mz) > 0.05 && !isParachuting && isGrounded;
animateHumanLimbs(player, isPlayerMoving, (isSprinting ? 1.4 : 1.0) * speedBoost, isCrouching, true);
recoilOffset *= 0.82;
const camHeight = isCrouching ? 2.25 : 2.95;
const camOffset = isScoped
? new THREE.Vector3(0.65, isCrouching ? 1.75 : 2.35, 0.8)
: new THREE.Vector3(1.55, camHeight + pitch * 2.5, 4.8);
camOffset.applyAxisAngle(new THREE.Vector3(0, 1, 0), yaw);
camera.position.copy(player.position).add(camOffset);
const lookTarget = new THREE.Vector3(0, 1.9, -15);
lookTarget.applyAxisAngle(new THREE.Vector3(0, 1, 0), yaw);
camera.lookAt(player.position.x + lookTarget.x, player.position.y + 1.8 - (pitch - recoilOffset) * 5, player.position.z + lookTarget.z);
if (zoneRadius > 22) {
zoneRadius -= 0.012;
safeZoneMesh.scale.set(zoneRadius / 165, 1, zoneRadius / 165);
document.getElementById('zone-rad').innerText = Math.round(zoneRadius);
}
if (Math.hypot(player.position.x, player.position.z) > zoneRadius) {
document.getElementById('zone-alert').style.display = 'block';
if (time - lastZoneDamageTime > 1000) {
lastZoneDamageTime = time; hp -= 8; updateHUD(); triggerDamageFlash();
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) > 190) { 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) < 0.9 && b.position.y < 2.8) {
const isHeadshot = b.position.y > 2.05;
const finalDmg = isHeadshot ? b.userData.dmg * 2.5 : b.userData.dmg;
en.userData.hp -= finalDmg;
triggerHitmarker();
spawnHitSparks(b.position, isHeadshot ? 0xff1744 : 0xffeb3b);
showDamagePopup(en.position, Math.round(finalDmg), isHeadshot);
scene.remove(b); bullets.splice(i, 1);
if (en.userData.limbs.hpBarMesh) {
en.userData.limbs.hpBarMesh.scale.x = Math.max(0.01, en.userData.hp / 100);
}
if (en.userData.hp <= 0) {
showKillFeed(`🔥 आपने ${en.userData.name} को ${isHeadshot ? 'HEADSHOT से' : ''} मारा!`);
spawnLootBox(en.position.x, en.position.z, 'crate');
scene.remove(en); enemies.splice(j, 1);
kills++; alive--; updateHUD();
if (kills === 2) showCenterBanner("🔥 DOUBLE KILL!");
else if (kills === 3) showCenterBanner("⚡ TRIPLE KILL!");
else if (kills >= 5) showCenterBanner("👑 UNSTOPPABLE!");
if (alive <= 1) finishGame(true);
}
break;
}
}
}
enemies.forEach(en => {
const dist = en.position.distanceTo(player.position);
let enemyMoving = false;
if (!isBush && !isParachuting) {
en.lookAt(player.position.x, 0, player.position.z);
if (dist > 16 && dist < 105) {
en.translateZ(0.095);
en.translateX(0.03 * en.userData.strafeDir);
resolveCollisions(en.position); enemyMoving = true;
}
if (dist < 65 && time - en.userData.lastShot > 2000) {
en.userData.lastShot = time;
const eb = new THREE.Mesh(new THREE.SphereGeometry(0.14), new THREE.MeshBasicMaterial({ color: 0xff1744 }));
eb.position.copy(en.position); eb.position.y += 1.65;
eb.userData.vel = new THREE.Vector3().subVectors(player.position, en.position).normalize().multiplyScalar(1.05);
scene.add(eb); enemyBullets.push(eb);
}
}
animateHumanLimbs(en, enemyMoving, 0.9, false, false);
});
for (let i = enemyBullets.length - 1; i >= 0; i--) {
const eb = enemyBullets[i];
eb.position.add(eb.userData.vel);
if (isShielded && eb.position.distanceTo(player.position) < 2.4) {
spawnHitSparks(eb.position, 0x00e5ff);
scene.remove(eb); enemyBullets.splice(i, 1); continue;
}
let hitWall = false;
for (let w = glooWalls.length - 1; w >= 0; w--) {
if (eb.position.distanceTo(glooWalls[w].position) < 2.1) {
spawnHitSparks(eb.position, 0x00e5ff);
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.2) {
hp -= 14; updateHUD(); triggerDamageFlash();
scene.remove(eb); enemyBullets.splice(i, 1);
if (hp <= 0) finishGame(false);
} else if (eb.position.distanceTo(player.position) > 130) {
scene.remove(eb); enemyBullets.splice(i, 1);
}
}
drawMiniMap();
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
189KB
660KB
10,046.0ms
296.0ms
10,046.0ms