3-3 / script.js
satana123's picture
Красивый 3д симулятор ходьбы от 3 лица как в gta 5
bca5fa3 verified
// Game State
let scene, camera, renderer;
let player, playerModel;
let moveSpeed = 0.1;
let runSpeed = 0.2;
let jumpHeight = 0.3;
let isJumping = false;
let velocity = { x: 0, y: 0, z: 0 };
let keys = {};
let mouseX = 0, mouseY = 0;
let isPaused = false;
let gameStartTime = Date.now();
let buildings = [];
let ground;
let clock = new THREE.Clock();
// Initialize Game
function init() {
// Create Scene
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x87CEEB, 10, 100);
scene.background = new THREE.Color(0x87CEEB);
// Setup Camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 10);
// Setup Renderer
renderer = new THREE.WebGLRenderer({
canvas: document.getElementById('gameCanvas'),
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Create Lighting
setupLighting();
// Create World
createGround();
createBuildings();
createPlayer();
// Setup Controls
setupControls();
// Start Game Loop
animate();
// Hide Loading Screen
setTimeout(() => {
document.getElementById('loadingScreen').style.display = 'none';
}, 2000);
}
function setupLighting() {
// Ambient Light
const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
scene.add(ambientLight);
// Directional Light (Sun)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(50, 100, 50);
directionalLight.castShadow = true;
directionalLight.shadow.camera.left = -50;
directionalLight.shadow.camera.right = 50;
directionalLight.shadow.camera.top = 50;
directionalLight.shadow.camera.bottom = -50;
directionalLight.shadow.camera.near = 0.1;
directionalLight.shadow.camera.far = 200;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
scene.add(directionalLight);
}
function createGround() {
const groundGeometry = new THREE.PlaneGeometry(200, 200);
const groundMaterial = new THREE.MeshLambertMaterial({
color: 0x3a5f3a,
side: THREE.DoubleSide
});
ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// Add road
const roadGeometry = new THREE.PlaneGeometry(10, 200);
const roadMaterial = new THREE.MeshLambertMaterial({ color: 0x333333 });
const road = new THREE.Mesh(roadGeometry, roadMaterial);
road.rotation.x = -Math.PI / 2;
road.position.y = 0.01;
road.receiveShadow = true;
scene.add(road);
}
function createBuildings() {
const buildingPositions = [
{ x: -20, z: -20, height: 30, width: 10, depth: 10 },
{ x: 20, z: -20, height: 25, width: 12, depth: 8 },
{ x: -20, z: 20, height: 35, width: 8, depth: 12 },
{ x: 20, z: 20, height: 40, width: 15, depth: 10 },
{ x: -40, z: 0, height: 20, width: 10, depth: 10 },
{ x: 40, z: 0, height: 28, width: 10, depth: 10 },
{ x: 0, z: -40, height: 32, width: 12, depth: 12 },
{ x: 0, z: 40, height: 24, width: 10, depth: 10 }
];
buildingPositions.forEach(pos => {
const buildingGeometry = new THREE.BoxGeometry(pos.width, pos.height, pos.depth);
const buildingMaterial = new THREE.MeshLambertMaterial({
color: new THREE.Color().setHSL(Math.random() * 0.1 + 0.5, 0.5, 0.6)
});
const building = new THREE.Mesh(buildingGeometry, buildingMaterial);
building.position.set(pos.x, pos.height / 2, pos.z);
building.castShadow = true;
building.receiveShadow = true;
buildings.push(building);
scene.add(building);
});
}
function createPlayer() {
// Player group
player = new THREE.Group();
// Body
const bodyGeometry = new THREE.CapsuleGeometry(0.5, 1.5, 4, 8);
const bodyMaterial = new THREE.MeshLambertMaterial({ color: 0x4169e1 });
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
body.position.y = 1.5;
body.castShadow = true;
player.add(body);
// Head
const headGeometry = new THREE.SphereGeometry(0.3, 16, 16);
const headMaterial = new THREE.MeshLambertMaterial({ color: 0xffdbac });
const head = new THREE.Mesh(headGeometry, headMaterial);
head.position.y = 2.7;
head.castShadow = true;
player.add(head);
player.position.set(0, 0, 0);
playerModel = player;
scene.add(player);
}
function setupControls() {
// Keyboard controls
document.addEventListener('keydown', (event) => {
keys[event.code] = true;
if (event.code === 'Space' && !isJumping) {
velocity.y = jumpHeight;
isJumping = true;
}
});
document.addEventListener('keyup', (event) => {
keys[event.code] = false;
});
// Mouse controls
document.addEventListener('mousemove', (event) => {
mouseX = (event.clientX / window.innerWidth) * 2 - 1;
mouseY = -(event.clientY / window.innerHeight) * 2 + 1;
});
// Window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// UI Controls
document.getElementById('startButton').addEventListener('click', () => {
document.getElementById('startScreen').style.display = 'none';
document.getElementById('hud').classList.remove('hidden');
document.body.requestPointerLock();
});
document.getElementById('togglePause').addEventListener('click', () => {
isPaused = !isPaused;
const btn = document.getElementById('togglePause');
btn.innerHTML = isPaused ?
'<i data-feather="play" class="w-4 h-4"></i><span>Resume</span>' :
'<i data-feather="pause" class="w-4 h-4"></i><span>Pause</span>';
feather.replace();
});
}
function updatePlayer() {
if (isPaused) return;
const speed = keys['ShiftLeft'] ? runSpeed : moveSpeed;
const moveVector = new THREE.Vector3();
// Calculate movement
if (keys['KeyW']) moveVector.z -= speed;
if (keys['KeyS']) moveVector.z += speed;
if (keys['KeyA']) moveVector.x -= speed;
if (keys['KeyD']) moveVector.x += speed;
// Apply movement relative to camera direction
const angle = camera.rotation.y;
const rotatedVector = moveVector.applyAxisAngle(new THREE.Vector3(0, 1, 0), angle);
player.position.x += rotatedVector.x;
player.position.z += rotatedVector.z;
// Apply gravity
velocity.y -= 0.015;
player.position.y += velocity.y;
// Ground collision
if (player.position.y <= 0) {
player.position.y = 0;
velocity.y = 0;
isJumping = false;
}
// Building collision (simple)
buildings.forEach(building => {
const distance = player.position.distanceTo(building.position);
const minDistance = 5; // Simple collision radius
if (distance < minDistance) {
const direction = new THREE.Vector3()
.subVectors(player.position, building.position)
.normalize();
player.position.copy(building.position).add(direction.multiplyScalar(minDistance));
}
});
// Update camera to follow player
const cameraOffset = new THREE.Vector3(0, 5, 10);
cameraOffset.applyAxisAngle(new THREE.Vector3(0, 1, 0), angle);
camera.position.copy(player.position).add(cameraOffset);
camera.lookAt(player.position);
// Camera rotation with mouse
camera.rotation.y = mouseX * Math.PI;
camera.rotation.x = mouseY * Math.PI / 4;
// Update HUD
updateHUD();
}
function updateHUD() {
// Position
document.getElementById('position').textContent =
`${Math.round(player.position.x)}, ${Math.round(player.position.z)}`;
// Speed
const currentSpeed = Math.sqrt(velocity.x ** 2 + velocity.z ** 2) * 100;
document.getElementById('speed').textContent = Math.round(currentSpeed);
// Game Time
const elapsed = Date.now() - gameStartTime;
const minutes = Math.floor(elapsed / 60000);
const seconds = Math.floor((elapsed % 60000) / 1000);
document.getElementById('gameTime').textContent =
`${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
// Update mini map
updateMiniMap();
}
function updateMiniMap() {
const canvas = document.getElementById('miniMap');
const ctx = canvas.getContext('2d');
canvas.width = 192;
canvas.height = 192;
// Clear
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, 192, 192);
// Draw player position
const mapX = (player.position.x + 100) * 0.96;
const mapZ = (player.position.z + 100) * 0.96;
ctx.fillStyle = '#4ade80';
ctx.beginPath();
ctx.arc(mapX, mapZ, 3, 0, Math.PI * 2);
ctx.fill();
// Draw buildings on map
ctx.fillStyle = '#6b7280';
buildings.forEach(building => {
const bX = (building.position.x + 100) * 0.96;
const bZ = (building.position.z + 100) * 0.96;
ctx.fillRect(bX - 5, bZ - 5, 10, 10);
});
}
function animate() {
requestAnimationFrame(animate);
if (!isPaused) {
updatePlayer();
// Animate player model (simple bobbing)
if (keys['KeyW'] || keys['KeyS'] || keys['KeyA'] || keys['KeyD']) {
player.rotation.y = camera.rotation.y;
player.position.y = Math.sin(Date.now() * 0.01) * 0.05;
}
}
renderer.render(scene, camera);
}
// Start the game when page loads
window.addEventListener('load', init);