escape-room / script.js
Xnix677's picture
Pero no me deja entrar al juego, haz que el juego se abra inmediatamente sin tener un menú de inicio
87bce5e verified
Raw
History Blame Contribute Delete
18.8 kB
// Game variables
let scene, camera, renderer, controls;
let player, walls = [], enemies = [], coins = [], emojis = [], powerups = [];
let score = 0, timeLeft = 60, gameActive = false, gameOver = false;
let playerSpeed = 5, invincible = false, doublePoints = false;
let clock = new THREE.Clock();
let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false;
// Audio elements
const bgMusic = document.getElementById('bg-music');
const coinSound = document.getElementById('coin-sound');
const enemySound = document.getElementById('enemy-sound');
const winSound = document.getElementById('win-sound');
const loseSound = document.getElementById('lose-sound');
// UI elements
const scoreDisplay = document.getElementById('score-display');
const timerDisplay = document.getElementById('timer');
// Initialize the game
function init() {
// Create scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
// Create camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 1.6, 0);
// Create renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Add pointer lock controls
controls = new THREE.PointerLockControls(camera, renderer.domElement);
// Create player
createPlayer();
// Generate maze
generateMaze();
// Add lights
addLights();
// Add event listeners
setupEventListeners();
// Start render loop
animate();
// Setup restart button
document.getElementById('restart-btn').addEventListener('click', restartGame);
}
// Create player
function createPlayer() {
// Create player with better 3D model
const group = new THREE.Group();
// Body
const body = new THREE.Mesh(
new THREE.BoxGeometry(0.5, 1, 0.3),
new THREE.MeshStandardMaterial({ color: 0x4ECDC4 })
);
body.position.y = 0.5;
// Head
const head = new THREE.Mesh(
new THREE.SphereGeometry(0.3, 16, 16),
new THREE.MeshStandardMaterial({ color: 0xFFD166 })
);
head.position.y = 1.15;
// Eyes
const eyeGeometry = new THREE.SphereGeometry(0.05, 8, 8);
const leftEye = new THREE.Mesh(eyeGeometry, new THREE.MeshStandardMaterial({ color: 0x000000 }));
const rightEye = new THREE.Mesh(eyeGeometry, new THREE.MeshStandardMaterial({ color: 0x000000 }));
leftEye.position.set(0.1, 1.15, 0.25);
rightEye.position.set(-0.1, 1.15, 0.25);
group.add(body);
group.add(head);
group.add(leftEye);
group.add(rightEye);
player = group;
player.castShadow = true;
player.position.y = 0.85;
scene.add(player);
}
// Generate maze
function generateMaze() {
const size = 30;
const gridSize = 15;
// Add skybox
const skyGeometry = new THREE.BoxGeometry(100, 100, 100);
const skyMaterial = new THREE.MeshBasicMaterial({
color: 0x87CEEB,
side: THREE.BackSide
});
const skybox = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(skybox);
const maze = [];
// Create grid
for (let i = 0; i < gridSize; i++) {
maze[i] = [];
for (let j = 0; j < gridSize; j++) {
maze[i][j] = Math.random() > 0.7 ? 1 : 0;
}
}
// Ensure exit path
maze[0][0] = 0;
maze[gridSize-1][gridSize-1] = 0;
// Create walls
for (let i = 0; i < gridSize; i++) {
for (let j = 0; j < gridSize; j++) {
if (maze[i][j] === 1) {
const wall = new THREE.Mesh(
new THREE.BoxGeometry(size/gridSize, 2, size/gridSize),
new THREE.MeshStandardMaterial({ color: 0xFFD166 })
);
wall.position.x = (i - gridSize/2) * (size/gridSize);
wall.position.z = (j - gridSize/2) * (size/gridSize);
wall.position.y = 1;
wall.castShadow = true;
wall.receiveShadow = true;
scene.add(wall);
walls.push(wall);
}
}
}
// Create coins
for (let i = 0; i < 30; i++) {
createCoin();
}
// Create enemies
for (let i = 0; i < 5; i++) {
createEnemy();
}
// Create powerups
for (let i = 0; i < 3; i++) {
createPowerup();
}
// Create exit
const exit = new THREE.Mesh(
new THREE.BoxGeometry(size/gridSize, 2, size/gridSize),
new THREE.MeshStandardMaterial({ color: 0x06D6A0, transparent: true, opacity: 0.5 })
);
exit.position.x = (gridSize/2 - 0.5) * (size/gridSize);
exit.position.z = (gridSize/2 - 0.5) * (size/gridSize);
exit.position.y = 1;
scene.add(exit);
exit.isExit = true;
walls.push(exit);
}
function createCoin() {
const coin = new THREE.Mesh(
new THREE.CylinderGeometry(0.3, 0.3, 0.1, 32),
new THREE.MeshStandardMaterial({
color: 0xFFD700,
metalness: 0.9,
roughness: 0.1
})
);
coin.castShadow = true;
coin.rotation.x = Math.PI / 2;
coin.position.set(
(Math.random() - 0.5) * 18,
0.5,
(Math.random() - 0.5) * 18
);
coin.castShadow = true;
coin.isCoin = true;
scene.add(coin);
coins.push(coin);
}
function createEnemy() {
const enemy = new THREE.Mesh(
new THREE.ConeGeometry(0.4, 1.2, 4),
new THREE.MeshStandardMaterial({
color: 0xFF6B6B,
emissive: 0x880000,
emissiveIntensity: 0.2
})
);
enemy.position.set(
(Math.random() - 0.5) * 18,
0.5,
(Math.random() - 0.5) * 18
);
enemy.castShadow = true;
enemy.speed = 0.02 + Math.random() * 0.03;
enemy.direction = new THREE.Vector3(Math.random() - 0.5, 0, Math.random() - 0.5).normalize();
scene.add(enemy);
enemies.push(enemy);
// Create emoji above enemy
const emoji = document.createElement('div');
emoji.className = 'enemy-emote';
emoji.textContent = ['😈', '👹', '👻', '🤡', '👾'][Math.floor(Math.random() * 5)];
document.getElementById('ui').appendChild(emo);
emojis.push({ element: emoji, enemy: enemy });
}
function addLights() {
// Ambient light
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// Directional light (sun)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(10, 20, 10);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 50;
directionalLight.shadow.camera.left = -20;
directionalLight.shadow.camera.right = 20;
directionalLight.shadow.camera.top = 20;
directionalLight.shadow.camera.bottom = -20;
scene.add(directionalLight);
// Hemisphere light for more natural outdoor lighting
const hemisphereLight = new THREE.HemisphereLight(0x87CEEB, 0x006400, 0.3);
scene.add(hemisphereLight);
// Add some point lights for better 3D effect
const pointLight1 = new THREE.PointLight(0xFFD166, 0.5, 10);
pointLight1.position.set(5, 3, 5);
scene.add(pointLight1);
const pointLight2 = new THREE.PointLight(0x4ECDC4, 0.5, 10);
pointLight2.position.set(-5, 3, -5);
scene.add(pointLight2);
}
function setupEventListeners() {
// Movement controls
document.addEventListener('keydown', (event) => {
switch (event.code) {
case 'KeyW':
case 'ArrowUp': moveForward = true; break;
case 'KeyA':
case 'ArrowLeft': moveLeft = true; break;
case 'KeyS':
case 'ArrowDown': moveBackward = true; break;
case 'KeyD':
case 'ArrowRight': moveRight = true; break;
}
});
document.addEventListener('keyup', (event) => {
switch (event.code) {
case 'KeyW':
case 'ArrowUp': moveForward = false; break;
case 'KeyA':
case 'ArrowLeft': moveLeft = false; break;
case 'KeyS':
case 'ArrowDown': moveBackward = false; break;
case 'KeyD':
case 'ArrowRight': moveRight = false; break;
}
});
// Touch controls
const upBtn = document.getElementById('up');
const leftBtn = document.getElementById('left');
const downBtn = document.getElementById('down');
const rightBtn = document.getElementById('right');
const lookBtn = document.getElementById('look');
// Touch start events
upBtn.addEventListener('touchstart', (e) => { e.preventDefault(); moveForward = true; });
leftBtn.addEventListener('touchstart', (e) => { e.preventDefault(); moveLeft = true; });
downBtn.addEventListener('touchstart', (e) => { e.preventDefault(); moveBackward = true; });
rightBtn.addEventListener('touchstart', (e) => { e.preventDefault(); moveRight = true; });
lookBtn.addEventListener('touchstart', (e) => {
e.preventDefault();
if (!controls.isLocked) {
controls.lock();
}
});
// Touch end events
upBtn.addEventListener('touchend', (e) => { e.preventDefault(); moveForward = false; });
leftBtn.addEventListener('touchend', (e) => { e.preventDefault(); moveLeft = false; });
downBtn.addEventListener('touchend', (e) => { e.preventDefault(); moveBackward = false; });
rightBtn.addEventListener('touchend', (e) => { e.preventDefault(); moveRight = false; });
// Mouse events for desktop
upBtn.addEventListener('mousedown', () => moveForward = true);
leftBtn.addEventListener('mousedown', () => moveLeft = true);
downBtn.addEventListener('mousedown', () => moveBackward = true);
rightBtn.addEventListener('mousedown', () => moveRight = true);
lookBtn.addEventListener('mousedown', () => {
if (!controls.isLocked) {
controls.lock();
}
});
upBtn.addEventListener('mouseup', () => moveForward = false);
leftBtn.addEventListener('mouseup', () => moveLeft = false);
downBtn.addEventListener('mouseup', () => moveBackward = false);
rightBtn.addEventListener('mouseup', () => moveRight = false);
// Pointer lock controls
const lockChangeAlert = () => {
if (document.pointerLockElement === renderer.domElement) {
controls.isLocked = true;
} else {
controls.isLocked = false;
}
};
document.addEventListener('pointerlockchange', lockChangeAlert, false);
// Window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
}
function startGame() {
// This function is now empty since we start the game automatically
}
function restartGame() {
// Reset all game state
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
// Clear all arrays
walls = [];
enemies = [];
coins = [];
powerups = [];
emojis.forEach(emoji => emoji.element.remove());
emojis = [];
// Reset variables
score = 0;
timeLeft = 60;
gameActive = false;
gameOver = false;
playerSpeed = 5;
invincible = false;
doublePoints = false;
// Update UI
scoreDisplay.textContent = `Coins: ${score}`;
timerDisplay.textContent = `Time: ${timeLeft}`;
// Hide end screen
document.getElementById('end-screen').style.display = 'none';
document.getElementById('start-screen').style.display = 'flex';
// Rebuild game elements
createPlayer();
generateMaze();
addLights();
// Reattach camera
controls.getObject().position.set(0, 1.6, 0);
camera.position.set(0, 1.6, 0);
camera.lookAt(0, 1.6, -1);
}
function endGame(win) {
gameOver = true;
gameActive = false;
if (controls.isLocked) {
controls.unlock();
}
const endScreen = document.getElementById('end-screen');
const endMessage = document.getElementById('end-message');
endScreen.style.display = 'flex';
if (win) {
endMessage.textContent = `You Escaped!\nFinal Score: ${score}`;
endMessage.style.animation = 'rainbow 2s infinite';
winSound.play();
} else {
endMessage.textContent = `Time's Up!\nFinal Score: ${score}`;
endMessage.style.color = '#FF6B6B';
loseSound.play();
}
}
function createPowerup() {
const types = ['speed', 'invincible', 'double'];
const type = types[Math.floor(Math.random() * types.length)];
let color, shape;
switch(type) {
case 'speed':
color = 0x00FF00;
shape = new THREE.SphereGeometry(0.4);
break;
case 'invincible':
color = 0x0000FF;
shape = new THREE.TetrahedronGeometry(0.5);
break;
case 'double':
color = 0xFF00FF;
shape = new THREE.OctahedronGeometry(0.4);
break;
}
const powerup = new THREE.Mesh(
shape,
new THREE.MeshStandardMaterial({
color: color,
emissive: color,
emissiveIntensity: 0.3
})
);
powerup.position.set(
(Math.random() - 0.5) * 28,
0.5,
(Math.random() - 0.5) * 28
);
powerup.castShadow = true;
powerup.type = type;
scene.add(powerup);
powerups.push(powerup);
}
function checkCollisions() {
// Check coin collisions
for (let i = coins.length - 1; i >= 0; i--) {
const coin = coins[i];
if (player.position.distanceTo(coin.position) < 1) {
scene.remove(coin);
coins.splice(i, 1);
score += doublePoints ? 20 : 10;
scoreDisplay.textContent = `Coins: ${score}`;
coinSound.play();
createCoin();
}
}
// Check powerup collisions
for (let i = powerups.length - 1; i >= 0; i--) {
const powerup = powerups[i];
if (player.position.distanceTo(powerup.position) < 1) {
scene.remove(powerup);
powerups.splice(i, 1);
switch(powerup.type) {
case 'speed':
playerSpeed = 8;
setTimeout(() => playerSpeed = 5, 10000);
break;
case 'invincible':
invincible = true;
setTimeout(() => invincible = false, 15000);
break;
case 'double':
doublePoints = true;
setTimeout(() => doublePoints = false, 20000);
break;
}
coinSound.play();
}
}
// Check wall collisions
const playerBox = new THREE.Box3().setFromObject(player);
for (const wall of walls) {
const wallBox = new THREE.Box3().setFromObject(wall);
if (playerBox.intersectsBox(wallBox)) {
if (wall.isExit) {
endGame(true);
} else {
// Simple collision response
const direction = new THREE.Vector3().subVectors(player.position, wall.position).normalize();
player.position.add(direction.multiplyScalar(0.1));
}
}
}
// Check enemy collisions
for (let i = 0; i < enemies.length; i++) {
const enemy = enemies[i];
if (player.position.distanceTo(enemy.position) < 1 && !invincible) {
score = Math.max(0, score - 5);
scoreDisplay.textContent = `Coins: ${score}`;
enemySound.play();
// Push player away
const direction = new THREE.Vector3().subVectors(player.position, enemy.position).normalize();
player.position.add(direction.multiplyScalar(1.5));
}
}
}
function updateEnemies() {
for (let i = 0; i < enemies.length; i++) {
const enemy = enemies[i];
// Simple AI - change direction randomly
if (Math.random() < 0.01) {
enemy.direction = new THREE.Vector3(Math.random() - 0.5, 0, Math.random() - 0.5).normalize();
}
// Move enemy
enemy.position.add(enemy.direction.clone().multiplyScalar(enemy.speed));
// Boundary check
if (enemy.position.x > 9 || enemy.position.x < -9 || enemy.position.z > 9 || enemy.position.z < -9) {
enemy.direction.negate();
}
// Wall collision
const enemyBox = new THREE.Box3().setFromObject(enemy);
for (const wall of walls) {
const wallBox = new THREE.Box3().setFromObject(wall);
if (enemyBox.intersectsBox(wallBox) && !wall.isExit) {
enemy.direction.negate();
break;
}
}
// Update emoji position
if (emojis[i]) {
const emoji = emojis[i].element;
const screenPos = enemy.position.clone().project(camera);
emoji.style.left = `${(screenPos.x * 0.5 + 0.5) * window.innerWidth}px`;
emoji.style.top = `${(-(screenPos.y * 0.5) + 0.5) * window.innerHeight - 50}px`;
// Show emoji when enemy is close
const distance = player.position.distanceTo(enemy.position);
emoji.style.opacity = distance < 5 ? '1' : '0';
}
}
}
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
if (gameActive && controls.isLocked) {
// Player movement
const speed = playerSpeed * delta;
if (moveForward) {
controls.moveForward(speed);
}
if (moveBackward) {
controls.moveForward(-speed);
}
if (moveLeft) {
controls.moveRight(-speed);
}
if (moveRight) {
controls.moveRight(speed);
}
// Update player position
player.position.copy(controls.getObject().position);
player.position.y = 0.85;
// Check collisions
checkCollisions();
// Update enemies
updateEnemies();
}
renderer.render(scene, camera);
}
// Start the game
init();