<!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 - Glitch Free + Abilities</title>
<style>
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body { margin: 0; overflow: hidden; background: #111; font-family: 'Segoe UI', Arial, sans-serif; user-select: none; touch-action: none; }
/* टॉप HUD */
#hud-top {
position: absolute; top: 8px; left: 8px; right: 8px;
display: flex; justify-content: space-between; align-items: flex-start;
z-index: 10; pointer-events: none;
}
.panel {
background: rgba(0, 0, 0, 0.5); color: white; padding: 5px 10px;
border-radius: 5px; border-left: 3px solid #ff9800; font-weight: bold; font-size: 12px;
}
#hp-bar-wrap { width: 110px; height: 7px; background: rgba(255,255,255,0.2); margin-top: 3px; border-radius: 4px; overflow: hidden; }
#hp-bar { width: 100%; height: 100%; background: #4caf50; transition: 0.15s; }
#zone-alert {
position: absolute; top: 48px; left: 50%; transform: translateX(-50%);
background: rgba(33, 150, 243, 0.85); color: white; padding: 4px 12px;
border-radius: 15px; font-size: 11px; font-weight: bold; display: none; z-index: 12;
}
/* सटीक निशाना */
#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.9);
}
#crosshair::before { top: 10px; left: 0; width: 22px; height: 2px; }
#crosshair::after { top: 0; left: 10px; width: 2px; height: 22px; }
#scope-overlay {
display: none; position: fixed; inset: 0; pointer-events: none; z-index: 9;
background: radial-gradient(circle, transparent 26%, rgba(0,0,0,0.9) 30%);
}
/* बायाँ जॉयस्टिक */
#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.8); 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.5); font-size: 10px; text-align: center;
}
#fireBtn {
bottom: 20px; right: 18px; width: 72px; height: 72px;
background: rgba(255, 87, 34, 0.8); font-size: 14px; border-width: 2px;
}
#fireBtn:active { transform: scale(0.92); background: rgba(255, 87, 34, 1); }
#jumpBtn { bottom: 104px; right: 18px; width: 45px; height: 45px; }
#scopeBtn { bottom: 104px; right: 72px; width: 45px; height: 45px; }
#glooBtn { bottom: 20px; right: 100px; width: 46px; height: 46px; background: rgba(0, 188, 212, 0.6); }
#medkitBtn { bottom: 20px; right: 154px; width: 45px; height: 45px; background: rgba(76, 175, 80, 0.6); }
/* कैरेक्टर एबिलिटी बटन (SKILL) */
#abilityBtn {
bottom: 80px; right: 132px; width: 54px; height: 54px;
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.5); }
/* कैरेक्टर सिलेक्शन और स्टार्ट स्क्रीन */
#overlayScreen {
position: fixed; inset: 0; background: rgba(10, 15, 25, 0.94);
color: white; display: flex; flex-direction: column; align-items: center; justify-content: center;
z-index: 30; text-align: center; padding: 15px;
}
.ability-cards {
display: flex; gap: 10px; margin: 15px 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: 125px; cursor: pointer; transition: 0.2s;
}
.card.selected { border-color: #ff9800; background: rgba(255, 152, 0, 0.2); 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 35px; font-size: 18px; font-weight: bold; border-radius: 8px;
margin-top: 10px; cursor: pointer;
}
</style>
</head>
<body>
<div id="hud-top">
<div class="panel">
HP: <span id="hp-val">200</span>
<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>
<button class="btn" id="abilityBtn">SKILL<br><span id="skill-status">READY</span></button>
<div id="overlayScreen">
<h1 id="screenTitle" style="color:#ff9800; font-size:24px; margin:0;">अपनी कैरेक्टर एबिलिटी चुनें</h1>
<div class="ability-cards" id="cardContainer">
<div class="card selected" data-skill="alok">
<h3>⚡ हील + स्पीड</h3>
<p>5 सेकंड तक तेज़ दौड़ और लगातार +HP रिकवरी</p>
</div>
<div class="card" data-skill="chrono">
<h3>🛡️ एनर्जी शील्ड</h3>
<p>6 सेकंड तक 360° सुरक्षा कवच, दुश्मन की गोली बेअसर</p>
</div>
<div class="card" data-skill="wukong">
<h3>🌿 बुश पावर</h3>
<p>झाड़ी बनकर छिपें, दुश्मन हमला नहीं कर पाएंगे</p>
</div>
</div>
<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>
// कैरेक्टर एबिलिटी सिलेक्शन
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') {
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(0.2, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + duration);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
osc.stop(audioCtx.currentTime + duration);
}
// 1. सीन और कैमरा
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x7ec0ee);
scene.fog = new THREE.FogExp2(0x7ec0ee, 0.005);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 600);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);
scene.add(new THREE.HemisphereLight(0xffffff, 0x3b5323, 0.8));
const sun = new THREE.DirectionalLight(0xfff5e4, 1.0);
sun.position.set(60, 100, 50);
sun.castShadow = true;
sun.shadow.mapSize.width = 1024;
sun.shadow.mapSize.height = 1024;
const d = 120;
sun.shadow.camera.left = -d; sun.shadow.camera.right = d;
sun.shadow.camera.top = d; sun.shadow.camera.bottom = -d;
scene.add(sun);
// 2. मैप और ठोस बाधाएँ (Solid Colliders ताकि दीवार के आर-पार न जाएं)
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(380, 380),
new THREE.MeshStandardMaterial({ color: 0x3a6b27, roughness: 0.95 })
);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
const grid = new THREE.GridHelper(380, 76, 0x2d541e, 0x2d541e);
grid.position.y = 0.02;
grid.material.opacity = 0.22;
grid.material.transparent = true;
scene.add(grid);
let zoneRadius = 140;
const safeZoneMesh = new THREE.Mesh(
new THREE.CylinderGeometry(zoneRadius, zoneRadius, 25, 48, 1, true),
new THREE.MeshBasicMaterial({ color: 0x00b0ff, transparent: true, opacity: 0.22, side: THREE.DoubleSide })
);
safeZoneMesh.position.y = 12.5;
scene.add(safeZoneMesh);
const solidObjects = []; // घरों, पेड़ों और पत्थरों के कोलाइडर (x, z, radius)
const glooWalls = [];
function buildMap() {
const houseMat = new THREE.MeshStandardMaterial({ color: 0xd7ccc8, roughness: 0.8 });
const roofMat = new THREE.MeshStandardMaterial({ color: 0x795548, roughness: 0.7 });
const treeWood = new THREE.MeshStandardMaterial({ color: 0x4e342e });
const treeLeaf = new THREE.MeshStandardMaterial({ color: 0x1b5e20 });
const rockMat = new THREE.MeshStandardMaterial({ color: 0x757575, roughness: 0.9 });
for (let i = 0; i < 55; i++) {
const x = (Math.random() - 0.5) * 250;
const z = (Math.random() - 0.5) * 250;
if (Math.abs(x) < 15 && Math.abs(z) < 15) continue;
if (i % 4 === 0) {
const house = new THREE.Mesh(new THREE.BoxGeometry(7, 4.5, 7), houseMat);
house.position.set(x, 2.25, z);
house.castShadow = true; house.receiveShadow = true;
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);
solidObjects.push({ x, z, r: 4.3 });
} else if (i % 4 === 1) {
const rock = new THREE.Mesh(new THREE.DodecahedronGeometry(1.8, 0), rockMat);
rock.position.set(x, 1.2, z);
rock.castShadow = true; rock.receiveShadow = true;
scene.add(rock);
solidObjects.push({ x, z, r: 1.8 });
} else {
const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.35, 0.55, 4.5), treeWood);
trunk.position.set(x, 2.25, z);
trunk.castShadow = true;
const leaves = new THREE.Mesh(new THREE.ConeGeometry(2.8, 6.2, 8), treeLeaf);
leaves.position.set(x, 6.5, z);
leaves.castShadow = true;
scene.add(trunk, leaves);
solidObjects.push({ x, z, r: 0.8 });
}
}
}
buildMap();
// कोलिज़न चेक फंक्शन (दीवारों के आर-पार जाने से रोकता है)
function resolveCollisions(pos) {
// मैप बॉर्डर से बाहर न जाएं
pos.x = Math.max(-175, Math.min(175, pos.x));
pos.z = Math.max(-175, Math.min(175, 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.6;
if (dist < minDist && dist > 0.001) {
const push = (minDist - dist) / dist;
pos.x += dx * push;
pos.z += dz * push;
}
}
}
// 3. रियलिस्टिक कैरेक्टर क्रिएशन
function createRealisticHuman(shirtColor, pantsColor, hasParachute = false) {
const human = new THREE.Group();
const bodyContainer = new THREE.Group(); // बुश एबिलिटी के समय इसे छिपाएंगे
human.add(bodyContainer);
const skinMat = new THREE.MeshStandardMaterial({ color: 0xe0ac69, roughness: 0.55 });
const hairMat = new THREE.MeshStandardMaterial({ color: 0x1a1a1a, roughness: 0.85 });
const shirtMat = new THREE.MeshStandardMaterial({ color: shirtColor, roughness: 0.65 });
const vestMat = new THREE.MeshStandardMaterial({ color: 0x212121, roughness: 0.5 });
const pantsMat = new THREE.MeshStandardMaterial({ color: pantsColor, roughness: 0.75 });
const bootMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.4 });
const bagMat = new THREE.MeshStandardMaterial({ color: 0x3e2723, roughness: 0.8 });
// सिर
const headGroup = new THREE.Group();
headGroup.position.y = 2.34;
const headMesh = new THREE.Mesh(new THREE.SphereGeometry(0.24, 16, 16), skinMat);
headMesh.scale.set(0.92, 1.08, 0.96);
headGroup.add(headMesh);
const hairMesh = new THREE.Mesh(new THREE.SphereGeometry(0.255, 16, 16, 0, Math.PI * 2, 0, Math.PI * 0.52), hairMat);
hairMesh.scale.set(0.94, 1.05, 0.98);
hairMesh.rotation.x = -0.18;
headGroup.add(hairMesh);
const eyeGeo = new THREE.SphereGeometry(0.028, 8, 8);
const eyeMat = new THREE.MeshBasicMaterial({ color: 0x111111 });
const lEye = new THREE.Mesh(eyeGeo, eyeMat); lEye.position.set(-0.08, 0.02, -0.22);
const rEye = new THREE.Mesh(eyeGeo, eyeMat); rEye.position.set(0.08, 0.02, -0.22);
headGroup.add(lEye, rEye);
bodyContainer.add(headGroup);
// गर्दन व धड़
const neck = new THREE.Mesh(new THREE.CylinderGeometry(0.085, 0.105, 0.18, 12), skinMat);
neck.position.y = 2.05;
const torso = new THREE.Mesh(new THREE.CylinderGeometry(0.27, 0.22, 0.85, 14), 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, 14), 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, 10, 10), shirtMat);
const lArm = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.065, 0.48, 10), skinMat);
lArm.position.y = -0.24;
const lGlove = new THREE.Mesh(new THREE.SphereGeometry(0.072, 10, 10), 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, 10, 10), shirtMat);
const rArm = new THREE.Mesh(new THREE.CylinderGeometry(0.085, 0.07, 0.48, 10), 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.75 }));
const gunBarrel = new THREE.Mesh(new THREE.CylinderGeometry(0.018, 0.018, 0.42), new THREE.MeshStandardMaterial({ color: 0x333333 }));
gunBarrel.rotation.x = Math.PI / 2; gunBarrel.position.set(0, 0.03, -0.55);
const muzzleFlash = new THREE.Mesh(new THREE.SphereGeometry(0.14, 8, 8), new THREE.MeshBasicMaterial({ color: 0xffab00 }));
muzzleFlash.position.set(0, 0.03, -0.8);
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, 12), 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; });
// एबिलिटी विजुअल इफेक्ट्स (Alok Aura, Chrono Shield, Wukong Bush)
const auraRing = new THREE.Mesh(
new THREE.RingGeometry(1.1, 1.5, 32),
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, 24, 18),
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 parachute = null;
if (hasParachute) {
parachute = new THREE.Mesh(
new THREE.SphereGeometry(2.5, 14, 10, 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,
animTime: Math.random() * 10
};
return human;
}
function animateHumanLimbs(human, isMoving, speedMultiplier = 1) {
const limbs = human.userData.limbs;
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; // ग्लिच-फ्री बाउंस
} else {
limbs.leftLeg.rotation.x *= 0.8;
limbs.rightLeg.rotation.x *= 0.8;
limbs.leftArm.rotation.x *= 0.8;
limbs.rightArm.rotation.x = 0;
limbs.bodyContainer.position.y = 0;
}
}
const player = createRealisticHuman(0x1565c0, 0x263238, true);
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.08;
let velY = 0, isGrounded = false, isParachuting = true;
let isScoped = false, isSprinting = 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 < 11; i++) {
const en = createRealisticHuman(shirtColors[i % shirtColors.length], 0x212121, false);
en.position.set((Math.random() - 0.5) * 180, 0, (Math.random() - 0.5) * 180);
resolveCollisions(en.position);
en.userData.hp = 100;
en.userData.lastShot = 0;
scene.add(en);
enemies.push(en);
}
}
createEnemies();
// कैरेक्टर एबिलिटी एक्टिवेट करना
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;
}
// सटीक निशाना (Raycaster से सीधे Crosshair की दिशा में गोली दागना)
const raycaster = new THREE.Raycaster();
function fireWeapon() {
if (!gameStarted || isGameOver || isParachuting) return;
if (isBush) endAbilityEffect(); // गोली चलाने पर बुश हट जाएगा (Wukong रूल)
playSound(180, 38, 0.1, 'sawtooth');
const flash = player.userData.limbs.muzzleFlash;
flash.visible = true;
setTimeout(() => { flash.visible = false; }, 55);
// स्क्रीन के बीचो-बीच (Crosshair) से दिशा निकालना
raycaster.setFromCamera(new THREE.Vector2(0, 0), camera);
const targetPoint = new THREE.Vector3();
raycaster.ray.at(80, targetPoint);
const spawnPos = new THREE.Vector3(player.position.x, player.position.y + 1.75, player.position.z);
const dir = new THREE.Vector3().subVectors(targetPoint, spawnPos).normalize();
const bullet = new THREE.Mesh(
new THREE.SphereGeometry(0.11, 6, 6),
new THREE.MeshBasicMaterial({ color: 0xffeb3b })
);
bullet.position.copy(spawnPos);
bullet.userData.vel = dir.multiplyScalar(3.0);
scene.add(bullet);
bullets.push(bullet);
}
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);
}
// मल्टी-टच ग्लिच-फ्री कंट्रोल्स (Touch Identifier ट्रैक करके)
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();
const t = e.changedTouches[0];
joyTouchId = t.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);
// कैमरा रोटेशन (अलग Touch ID के साथ ताकि जॉयस्टिक के साथ स्मूद चले)
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.003 : 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);
document.getElementById('fireBtn').addEventListener('touchstart', (e) => { e.preventDefault(); fireWeapon(); });
document.getElementById('fireBtn').addEventListener('click', fireWeapon);
document.getElementById('abilityBtn').addEventListener('touchstart', (e) => { e.preventDefault(); activateAbility(); });
document.getElementById('abilityBtn').addEventListener('click', activateAbility);
document.getElementById('jumpBtn').addEventListener('touchstart', (e) => {
e.preventDefault();
if (isGrounded && !isParachuting) { 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 : 75;
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 ? 'rgba(255, 87, 34, 0.85)' : 'rgba(255, 152, 0, 0.5)';
});
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();
if (e.key === 'c') activateAbility();
});
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('cardContainer').style.display = 'none';
document.getElementById('startBtn').innerText = "PLAY AGAIN";
document.getElementById('overlayScreen').style.display = 'flex';
}
// मेन गेम लूप
let lastZoneDamageTime = 0, lastHealTime = 0;
function animate(time) {
requestAnimationFrame(animate);
if (!gameStarted || isGameOver) {
renderer.render(scene, camera);
return;
}
// Alok ऑरा हीलिंग और रोटेशन
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.28;
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 = isSprinting ? 0.36 : 0.23;
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);
// ठोस दीवारों से टकराव रोकना (Glitch-Free Collision)
resolveCollisions(player.position);
const isPlayerMoving = Math.hypot(mx, mz) > 0.05 && !isParachuting && isGrounded;
animateHumanLimbs(player, isPlayerMoving, (isSprinting ? 1.4 : 1.0) * speedBoost);
// साइड-बाय-साइड क्लियर कैमरा
const camOffset = isScoped
? new THREE.Vector3(0.65, 2.35, 0.9)
: new THREE.Vector3(1.55, 2.95 + 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 * 5, player.position.z + lookTarget.z);
// सेफ ज़ोन
if (zoneRadius > 20) {
zoneRadius -= 0.012;
safeZoneMesh.scale.set(zoneRadius / 140, 1, zoneRadius / 140);
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();
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) < 0.9 && b.position.y < 2.8) {
const isHeadshot = b.position.y > 2.05;
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 => {
const dist = en.position.distanceTo(player.position);
let enemyMoving = false;
if (!isBush && !isParachuting) {
en.lookAt(player.position.x, 0, player.position.z);
if (dist > 14 && dist < 95) {
en.translateZ(0.09);
resolveCollisions(en.position);
enemyMoving = true;
}
if (dist < 60 && 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.0);
scene.add(eb);
enemyBullets.push(eb);
}
}
animateHumanLimbs(en, enemyMoving, 0.9);
});
// दुश्मन की गोलियाँ (Chrono Shield और Gloo Wall से रुकेंगी)
for (let i = enemyBullets.length - 1; i >= 0; i--) {
const eb = enemyBullets[i];
eb.position.add(eb.userData.vel);
// Chrono एनर्जी शील्ड से गोली टकराकर खत्म
if (isShielded && eb.position.distanceTo(player.position) < 2.4) {
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) {
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();
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
160KB
631KB
1,485.0ms
216.0ms
1,485.0ms