Meta Description" name="description" />
<!DOCTYPE html>
<html lang="ru">
<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 Standoff Shooter</title>
<style>
body {
margin:0; padding:0; overflow:hidden; background:#000;
touch-action: none; font-family: Arial, sans-serif;
}
canvas { display:block; }
#ui { position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none; color:white; }
.btn {
pointer-events:all; background:rgba(255,255,255,0.2); color:white;
border:2px solid rgba(255,255,255,0.5); border-radius:50%;
display:flex; align-items:center; justify-content:center;
font-size:15px; position:absolute;
}
#crosshair {
position:absolute; top:50%; left:50%; font-size:45px;
transform:translate(-50%,-50%); opacity:0.6; pointer-events:none;
}
#orientationWarning {
position:absolute; top:0; left:0; width:100%; height:100%;
background:rgba(0,0,0,0.95); display:none; flex-direction:column;
align-items:center; justify-content:center; color:#ff0; font-size:28px;
z-index: 100;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
<div id="ui">
<div id="crosshair">+</div>
<!-- Главное меню -->
<div id="mainMenu">
<div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center;">
<h1 style="font-size:48px; margin:10px; text-shadow: 0 0 10px #0f0;">3D SHOOTER</h1>
<p style="margin:5px; color:#0f0;">в стиле Standoff 2</p>
<br>
<button onclick="startGame()" style="width:280px; height:75px; font-size:26px; border-radius:15px; margin:12px;">ИГРАТЬ</button><br>
<button onclick="showSettings()" style="width:280px; height:65px; font-size:22px; border-radius:15px;">НАСТРОЙКИ</button>
</div>
</div>
<!-- Игровой UI -->
<div id="gameUI" style="display:none;">
<div id="joystickArea" style="position:absolute; bottom:40px; left:30px; width:160px; height:160px; border:3px solid rgba(255,255,255,0.25); border-radius:50%;"></div>
<div id="btnCrouch" class="btn" style="bottom:110px; left:220px; width:75px; height:75px;">Присесть</div>
<div id="btnJump" class="btn" style="bottom:110px; left:310px; width:75px; height:75px;">Прыжок</div>
<div id="btnFire" class="btn" style="bottom:50px; right:70px; width:120px; height:120px; background:#c00; font-size:20px;">FIRE</div>
</div>
<!-- Предупреждение о повороте экрана -->
<div id="orientationWarning">
<div>📱 ПОВЕРНИТЕ ТЕЛЕФОН ГОРИЗОНТАЛЬНО</div>
<div style="font-size:18px; margin-top:20px; color:#aaa;">Для комфортной игры</div>
</div>
</div>
<script>
// ==================== THREE.JS ====================
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x4488ff);
scene.fog = new THREE.Fog(0x4488ff, 20, 200);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
scene.add(new THREE.AmbientLight(0xaaaaaa));
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(10, 30, 15);
scene.add(dirLight);
const floor = new THREE.Mesh(new THREE.PlaneGeometry(300, 300), new THREE.MeshLambertMaterial({color: 0x226622}));
floor.rotation.x = -Math.PI/2;
scene.add(floor);
let player = { height: 1.8, speed: 0.17, velocityY: 0, canJump: true, crouch: false };
camera.position.y = player.height;
const weapons = { m4: { recoil: 9, firerate: 110 } };
let currentWeapon = weapons.m4;
let lastShot = 0;
let moveDir = { x: 0, z: 0 };
let sensitivity = 0.003;
// ==================== ПРОВЕРКА ОРИЕНТАЦИИ ====================
function checkOrientation() {
const warning = document.getElementById('orientationWarning');
if (window.innerWidth < window.innerHeight) {
warning.style.display = 'flex'; // Портретный режим
} else {
warning.style.display = 'none'; // Ландшафтный режим
}
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
checkOrientation();
});
// Попытка принудительной блокировки
function lockOrientation() {
if (screen.orientation && screen.orientation.lock) {
screen.orientation.lock('landscape').catch(err => {
console.log("Автоблокировка не сработала:", err);
});
}
}
// ==================== ФУНКЦИИ ИГРЫ ====================
function shoot() {
const now = Date.now();
if (now - lastShot < currentWeapon.firerate) return;
lastShot = now;
camera.rotation.x -= currentWeapon.recoil * 0.008;
}
function jump() {
if (player.canJump) {
player.velocityY = 0.37;
player.canJump = false;
}
}
function toggleCrouch() {
player.crouch = !player.crouch;
camera.position.y = player.crouch ? 1.15 : player.height;
player.speed = player.crouch ? 0.10 : 0.17;
}
function startGame() {
document.getElementById('mainMenu').style.display = 'none';
document.getElementById('gameUI').style.display = 'block';
lockOrientation();
checkOrientation();
}
function showSettings() {
let sens = prompt("Чувствительность прицела (0.001 — 0.006):", sensitivity);
if (sens) sensitivity = parseFloat(sens);
}
// ==================== ЦИКЛ ====================
function animate() {
requestAnimationFrame(animate);
const forward = new THREE.Vector3(0,0,-1).applyQuaternion(camera.quaternion);
const right = new THREE.Vector3(1,0,0).applyQuaternion(camera.quaternion);
forward.y = right.y = 0;
forward.normalize();
right.normalize();
camera.position.x += (forward.x * moveDir.x + right.x * moveDir.z) * player.speed;
camera.position.z += (forward.z * moveDir.x + right.z * moveDir.z) * player.speed;
player.velocityY -= 0.022;
camera.position.y += player.velocityY;
if (camera.position.y < player.height) {
camera.position.y = player.height;
player.velocityY = 0;
player.canJump = true;
}
renderer.render(scene, camera);
}
animate();
// Кнопки
document.getElementById('btnFire').addEventListener('touchstart', shoot);
document.getElementById('btnFire').addEventListener('mousedown', shoot);
document.getElementById('btnJump').addEventListener('click', jump);
document.getElementById('btnCrouch').addEventListener('click', toggleCrouch);
// Keyboard
document.addEventListener('keydown', e => {
switch(e.code) {
case 'KeyW': moveDir.x = 1; break;
case 'KeyS': moveDir.x = -1; break;
case 'KeyA': moveDir.z = -1; break;
case 'KeyD': moveDir.z = 1; break;
case 'Space': jump(); break;
}
});
document.addEventListener('keyup', e => {
if (['KeyW','KeyS'].includes(e.code)) moveDir.x = 0;
if (['KeyA','KeyD'].includes(e.code)) moveDir.z = 0;
});
// Mouse look
renderer.domElement.addEventListener('click', () => renderer.domElement.requestPointerLock());
document.addEventListener('mousemove', e => {
if (document.pointerLockElement) {
camera.rotation.y -= e.movementX * sensitivity;
camera.rotation.x -= e.movementY * sensitivity;
camera.rotation.x = Math.max(-1.4, Math.min(1.4, camera.rotation.x));
}
});
checkOrientation();
</script>
</body>
</html>2
2
130KB
610KB
733.0ms
112.0ms
733.0ms