|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Pixel Quest 3D: Find Your Friend</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> |
|
<style> |
|
body { |
|
margin: 0; |
|
overflow: hidden; |
|
font-family: 'Press Start 2P', cursive; |
|
image-rendering: pixelated; |
|
} |
|
|
|
canvas { |
|
display: block; |
|
image-rendering: pixelated; |
|
} |
|
|
|
@font-face { |
|
font-family: 'Press Start 2P'; |
|
src: url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); |
|
} |
|
|
|
.pixel-border { |
|
border: 4px solid #fff; |
|
box-shadow: 0 0 0 4px #000, inset 0 0 0 4px #000; |
|
} |
|
|
|
.quiz-option { |
|
transition: all 0.1s; |
|
border: 3px solid #fff; |
|
box-shadow: 0 0 0 3px #000; |
|
} |
|
|
|
.quiz-option:hover { |
|
background-color: #4a5568; |
|
transform: translateY(-2px); |
|
} |
|
|
|
.quiz-option.correct { |
|
background-color: #48bb78; |
|
} |
|
|
|
.quiz-option.wrong { |
|
background-color: #f56565; |
|
} |
|
|
|
.pixel-text { |
|
text-shadow: 3px 3px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; |
|
} |
|
|
|
.health-bar { |
|
height: 10px; |
|
background-color: #4a5568; |
|
border: 2px solid #000; |
|
} |
|
|
|
.health-fill { |
|
height: 100%; |
|
background-color: #48bb78; |
|
transition: width 0.3s; |
|
} |
|
|
|
|
|
.controls-info { |
|
position: absolute; |
|
bottom: 20px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
background-color: rgba(0, 0, 0, 0.7); |
|
padding: 10px; |
|
border-radius: 5px; |
|
color: white; |
|
text-align: center; |
|
font-size: 12px; |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-900"> |
|
<div id="game-container" class="relative w-full h-screen"> |
|
|
|
<div id="start-screen" class="absolute inset-0 flex flex-col items-center justify-center bg-gray-900 z-10"> |
|
<h1 class="text-4xl md:text-6xl text-green-400 mb-8 pixel-text">PIXEL QUEST 3D</h1> |
|
<p class="text-xl text-white mb-12 pixel-text">Find Your Lost Friend!</p> |
|
<div class="flex mb-8"> |
|
<div class="w-16 h-16 bg-red-500 pixel-border mr-4"></div> |
|
<div class="w-16 h-16 bg-blue-500 pixel-border"></div> |
|
</div> |
|
<button id="start-btn" class="px-8 py-4 bg-green-500 hover:bg-green-600 text-white font-bold pixel-border transition-all transform hover:scale-105"> |
|
START ADVENTURE |
|
</button> |
|
<div class="mt-8 text-white text-sm pixel-text"> |
|
Controls: WASD to move, Space to jump, F to attack |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="quiz-modal" class="hidden absolute inset-0 flex items-center justify-center z-20 bg-black bg-opacity-70"> |
|
<div class="bg-gray-800 p-6 rounded-lg w-11/12 max-w-md pixel-border"> |
|
<h2 id="quiz-question" class="text-xl text-white mb-6 pixel-text"></h2> |
|
<div id="quiz-options" class="space-y-3"></div> |
|
<div id="quiz-feedback" class="mt-4 text-yellow-300 hidden pixel-text"></div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="end-screen" class="hidden absolute inset-0 flex flex-col items-center justify-center bg-gray-900 z-10"> |
|
<h1 id="end-title" class="text-4xl md:text-6xl text-green-400 mb-8 pixel-text">FRIEND FOUND!</h1> |
|
<div class="flex items-center mb-8"> |
|
<div class="w-32 h-32 bg-red-500 pixel-border mr-4"></div> |
|
<div class="w-32 h-32 bg-blue-500 pixel-border"></div> |
|
</div> |
|
<p id="final-score" class="text-xl text-white mb-12 pixel-text"></p> |
|
<button id="restart-btn" class="px-8 py-4 bg-green-500 hover:bg-green-600 text-white font-bold pixel-border transition-all transform hover:scale-105"> |
|
PLAY AGAIN |
|
</button> |
|
</div> |
|
|
|
|
|
<div id="game-over-screen" class="hidden absolute inset-0 flex flex-col items-center justify-center bg-gray-900 z-10"> |
|
<h1 class="text-4xl md:text-6xl text-red-500 mb-8 pixel-text">GAME OVER</h1> |
|
<p id="game-over-score" class="text-xl text-white mb-12 pixel-text"></p> |
|
<button id="game-over-restart-btn" class="px-8 py-4 bg-green-500 hover:bg-green-600 text-white font-bold pixel-border transition-all transform hover:scale-105"> |
|
TRY AGAIN |
|
</button> |
|
</div> |
|
|
|
|
|
<div id="ui-container" class="absolute top-4 left-4 z-10 hidden"> |
|
<div class="bg-gray-800 bg-opacity-70 p-3 rounded pixel-border"> |
|
<p class="text-white pixel-text">Score: <span id="score-display">0</span></p> |
|
<p class="text-white pixel-text">Quizzes: <span id="quiz-count">0</span>/4</p> |
|
<div class="mt-2"> |
|
<p class="text-white pixel-text mb-1">Health:</p> |
|
<div class="health-bar"> |
|
<div id="health-fill" class="health-fill" style="width: 100%"></div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="controls-info" class="controls-info hidden text-white pixel-text"> |
|
WASD: Move | SPACE: Jump | F: Attack Obstacles |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
let scene, camera, renderer; |
|
let player, platforms = [], checkpoints = [], coins = [], obstacles = []; |
|
let playerVelocity = { x: 0, y: 0, z: 0 }; |
|
let playerSpeed = 0.2; |
|
let jumpForce = 0.4; |
|
let gravity = 0.02; |
|
let isJumping = false; |
|
let gamePaused = false; |
|
let score = 0; |
|
let quizzesCompleted = 0; |
|
let currentCheckpoint = null; |
|
let friendFound = false; |
|
let keys = {}; |
|
let worldWidth = 100; |
|
let worldDepth = 20; |
|
let friend; |
|
let playerHealth = 100; |
|
let lastObstacleHitTime = 0; |
|
let obstacleHitCooldown = 1000; |
|
let playerDirection = new THREE.Vector3(); |
|
let cameraOffset = new THREE.Vector3(0, 3, -5); |
|
|
|
|
|
const quizQuestions = [ |
|
{ |
|
question: "What is your friend's favorite color?", |
|
options: ["Blue", "Green", "Red", "Yellow"], |
|
correct: 0 |
|
}, |
|
{ |
|
question: "Where did you first meet your friend?", |
|
options: ["At school", "At the park", "At a party", "Online"], |
|
correct: 1 |
|
}, |
|
{ |
|
question: "What's your friend's favorite food?", |
|
options: ["Pizza", "Sushi", "Burgers", "Tacos"], |
|
correct: 2 |
|
}, |
|
{ |
|
question: "What was your last adventure together?", |
|
options: ["Hiking", "Movie marathon", "Road trip", "Camping"], |
|
correct: 3 |
|
} |
|
]; |
|
|
|
|
|
function init() { |
|
|
|
scene = new THREE.Scene(); |
|
scene.background = new THREE.Color(0x87CEEB); |
|
|
|
|
|
const aspect = window.innerWidth / window.innerHeight; |
|
camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000); |
|
camera.position.set(0, 5, 15); |
|
camera.lookAt(0, 0, 0); |
|
|
|
|
|
renderer = new THREE.WebGLRenderer({ antialias: false }); |
|
renderer.setPixelRatio(window.devicePixelRatio > 1 ? 2 : 1); |
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
renderer.shadowMap.enabled = true; |
|
document.getElementById('game-container').appendChild(renderer.domElement); |
|
|
|
|
|
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); |
|
scene.add(ambientLight); |
|
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); |
|
directionalLight.position.set(10, 20, 10); |
|
directionalLight.castShadow = true; |
|
directionalLight.shadow.mapSize.width = 1024; |
|
directionalLight.shadow.mapSize.height = 1024; |
|
scene.add(directionalLight); |
|
|
|
|
|
createWorld(); |
|
|
|
|
|
createPlayer(); |
|
|
|
|
|
createCheckpoints(); |
|
|
|
|
|
createObstacles(); |
|
|
|
|
|
createFriend(); |
|
|
|
|
|
window.addEventListener('resize', onWindowResize); |
|
document.addEventListener('keydown', onKeyDown); |
|
document.addEventListener('keyup', onKeyUp); |
|
|
|
|
|
document.getElementById('start-btn').addEventListener('click', startGame); |
|
document.getElementById('restart-btn').addEventListener('click', restartGame); |
|
document.getElementById('game-over-restart-btn').addEventListener('click', restartGame); |
|
} |
|
|
|
function createWorld() { |
|
|
|
const groundGeometry = new THREE.BoxGeometry(worldWidth, 1, worldDepth); |
|
const groundMaterial = new THREE.MeshStandardMaterial({ |
|
color: 0x2e8b57, |
|
roughness: 1.0 |
|
}); |
|
const ground = new THREE.Mesh(groundGeometry, groundMaterial); |
|
ground.position.y = -0.5; |
|
ground.receiveShadow = true; |
|
scene.add(ground); |
|
|
|
|
|
const platformPositions = [ |
|
{ x: 10, y: 2, z: 0, width: 8, depth: 8 }, |
|
{ x: 25, y: 3, z: 5, width: 6, depth: 6 }, |
|
{ x: 40, y: 4, z: -3, width: 10, depth: 10 }, |
|
{ x: 60, y: 2, z: 2, width: 12, depth: 8 }, |
|
{ x: 80, y: 5, z: 0, width: 8, depth: 8 } |
|
]; |
|
|
|
platformPositions.forEach(pos => { |
|
const platformGeometry = new THREE.BoxGeometry(pos.width, 1, pos.depth); |
|
const platformMaterial = new THREE.MeshStandardMaterial({ |
|
color: 0x8b4513, |
|
roughness: 1.0 |
|
}); |
|
const platform = new THREE.Mesh(platformGeometry, platformMaterial); |
|
platform.position.set(pos.x, pos.y, pos.z); |
|
platform.receiveShadow = true; |
|
scene.add(platform); |
|
platforms.push(platform); |
|
}); |
|
|
|
|
|
for (let i = 0; i < 20; i++) { |
|
const coinGeometry = new THREE.CylinderGeometry(0.5, 0.5, 0.2, 16); |
|
const coinMaterial = new THREE.MeshStandardMaterial({ color: 0xffd700 }); |
|
const coin = new THREE.Mesh(coinGeometry, coinMaterial); |
|
|
|
|
|
let x, y, z; |
|
if (Math.random() > 0.5) { |
|
|
|
const platform = platforms[Math.floor(Math.random() * platforms.length)]; |
|
x = platform.position.x + (Math.random() - 0.5) * (platform.geometry.parameters.width - 2); |
|
y = platform.position.y + 1; |
|
z = platform.position.z + (Math.random() - 0.5) * (platform.geometry.parameters.depth - 2); |
|
} else { |
|
|
|
x = Math.random() * worldWidth; |
|
y = 0.5; |
|
z = (Math.random() - 0.5) * (worldDepth - 4); |
|
} |
|
|
|
coin.position.set(x, y, z); |
|
coin.rotation.x = Math.PI / 2; |
|
coin.userData.isCoin = true; |
|
scene.add(coin); |
|
coins.push(coin); |
|
} |
|
} |
|
|
|
function createPlayer() { |
|
|
|
const playerGeometry = new THREE.BoxGeometry(1, 2, 1); |
|
const playerMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 }); |
|
player = new THREE.Mesh(playerGeometry, playerMaterial); |
|
player.position.set(0, 1, 0); |
|
player.castShadow = true; |
|
scene.add(player); |
|
} |
|
|
|
function createCheckpoints() { |
|
|
|
const checkpointPositions = [ |
|
{ x: 15, y: 0, z: 0 }, |
|
{ x: 30, y: 0, z: 0 }, |
|
{ x: 50, y: 0, z: 0 }, |
|
{ x: 70, y: 0, z: 0 } |
|
]; |
|
|
|
checkpointPositions.forEach((pos, index) => { |
|
const checkpointGeometry = new THREE.BoxGeometry(2, 2, 2); |
|
const checkpointMaterial = new THREE.MeshStandardMaterial({ |
|
color: 0xffff00, |
|
transparent: true, |
|
opacity: 0.7 |
|
}); |
|
const checkpoint = new THREE.Mesh(checkpointGeometry, checkpointMaterial); |
|
checkpoint.position.set(pos.x, pos.y + 1, pos.z); |
|
checkpoint.userData.isCheckpoint = true; |
|
checkpoint.userData.quizIndex = index; |
|
scene.add(checkpoint); |
|
checkpoints.push(checkpoint); |
|
}); |
|
} |
|
|
|
function createObstacles() { |
|
|
|
const obstaclePositions = [ |
|
{ x: 5, y: 1, z: 3, width: 1, height: 2, depth: 1 }, |
|
{ x: 20, y: 1, z: -2, width: 1, height: 2, depth: 1 }, |
|
{ x: 35, y: 1, z: 4, width: 1, height: 2, depth: 1 }, |
|
{ x: 45, y: 1, z: -3, width: 1, height: 2, depth: 1 }, |
|
{ x: 65, y: 1, z: 2, width: 1, height: 2, depth: 1 } |
|
]; |
|
|
|
obstaclePositions.forEach(pos => { |
|
const obstacleGeometry = new THREE.BoxGeometry(pos.width, pos.height, pos.depth); |
|
const obstacleMaterial = new THREE.MeshStandardMaterial({ |
|
color: 0x8b0000, |
|
roughness: 1.0 |
|
}); |
|
const obstacle = new THREE.Mesh(obstacleGeometry, obstacleMaterial); |
|
obstacle.position.set(pos.x, pos.y + pos.height/2, pos.z); |
|
obstacle.castShadow = true; |
|
obstacle.receiveShadow = true; |
|
obstacle.userData.isObstacle = true; |
|
obstacle.userData.health = 30; |
|
scene.add(obstacle); |
|
obstacles.push(obstacle); |
|
}); |
|
} |
|
|
|
function createFriend() { |
|
|
|
const friendGeometry = new THREE.BoxGeometry(1, 2, 1); |
|
const friendMaterial = new THREE.MeshStandardMaterial({ color: 0x0000ff }); |
|
friend = new THREE.Mesh(friendGeometry, friendMaterial); |
|
friend.position.set(worldWidth - 5, 1, 0); |
|
friend.castShadow = true; |
|
friend.userData.isFriend = true; |
|
scene.add(friend); |
|
} |
|
|
|
function startGame() { |
|
document.getElementById('start-screen').classList.add('hidden'); |
|
document.getElementById('ui-container').classList.remove('hidden'); |
|
document.getElementById('controls-info').classList.remove('hidden'); |
|
animate(); |
|
} |
|
|
|
function restartGame() { |
|
|
|
score = 0; |
|
quizzesCompleted = 0; |
|
friendFound = false; |
|
gamePaused = false; |
|
playerHealth = 100; |
|
|
|
|
|
player.position.set(0, 1, 0); |
|
playerVelocity = { x: 0, y: 0, z: 0 }; |
|
|
|
|
|
document.getElementById('score-display').textContent = '0'; |
|
document.getElementById('quiz-count').textContent = '0/4'; |
|
document.getElementById('health-fill').style.width = '100%'; |
|
document.getElementById('end-screen').classList.add('hidden'); |
|
document.getElementById('game-over-screen').classList.add('hidden'); |
|
document.getElementById('ui-container').classList.remove('hidden'); |
|
document.getElementById('controls-info').classList.remove('hidden'); |
|
|
|
|
|
clearScene(); |
|
createWorld(); |
|
createPlayer(); |
|
createCheckpoints(); |
|
createObstacles(); |
|
createFriend(); |
|
|
|
|
|
animate(); |
|
} |
|
|
|
function clearScene() { |
|
|
|
while(scene.children.length > 0) { |
|
const obj = scene.children[0]; |
|
if (!(obj instanceof THREE.Light) && !(obj instanceof THREE.Camera)) { |
|
scene.remove(obj); |
|
} |
|
} |
|
|
|
|
|
platforms = []; |
|
checkpoints = []; |
|
coins = []; |
|
obstacles = []; |
|
} |
|
|
|
function showQuiz(quizIndex) { |
|
gamePaused = true; |
|
currentCheckpoint = quizIndex; |
|
|
|
const quiz = quizQuestions[quizIndex]; |
|
document.getElementById('quiz-question').textContent = quiz.question; |
|
|
|
const optionsContainer = document.getElementById('quiz-options'); |
|
optionsContainer.innerHTML = ''; |
|
|
|
quiz.options.forEach((option, i) => { |
|
const optionBtn = document.createElement('button'); |
|
optionBtn.className = 'w-full p-3 bg-gray-700 text-white quiz-option pixel-text'; |
|
optionBtn.textContent = option; |
|
optionBtn.addEventListener('click', () => checkAnswer(i)); |
|
optionsContainer.appendChild(optionBtn); |
|
}); |
|
|
|
document.getElementById('quiz-feedback').classList.add('hidden'); |
|
document.getElementById('quiz-modal').classList.remove('hidden'); |
|
} |
|
|
|
function checkAnswer(answerIndex) { |
|
const quiz = quizQuestions[currentCheckpoint]; |
|
const options = document.querySelectorAll('.quiz-option'); |
|
|
|
if (answerIndex === quiz.correct) { |
|
|
|
options[answerIndex].classList.add('correct'); |
|
document.getElementById('quiz-feedback').textContent = 'Correct!'; |
|
document.getElementById('quiz-feedback').classList.remove('hidden'); |
|
|
|
setTimeout(() => { |
|
quizzesCompleted++; |
|
document.getElementById('quiz-count').textContent = `${quizzesCompleted}/4`; |
|
document.getElementById('quiz-modal').classList.add('hidden'); |
|
gamePaused = false; |
|
|
|
|
|
const checkpoint = checkpoints[currentCheckpoint]; |
|
scene.remove(checkpoint); |
|
checkpoints[currentCheckpoint] = null; |
|
|
|
|
|
score += 100; |
|
document.getElementById('score-display').textContent = score; |
|
|
|
|
|
playerVelocity.x = 0; |
|
playerVelocity.z = 0; |
|
}, 1000); |
|
} else { |
|
|
|
options[answerIndex].classList.add('wrong'); |
|
options[quiz.correct].classList.add('correct'); |
|
document.getElementById('quiz-feedback').textContent = 'Try again!'; |
|
document.getElementById('quiz-feedback').classList.remove('hidden'); |
|
} |
|
} |
|
|
|
function onWindowResize() { |
|
const aspect = window.innerWidth / window.innerHeight; |
|
camera.aspect = aspect; |
|
camera.updateProjectionMatrix(); |
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
} |
|
|
|
function onKeyDown(event) { |
|
keys[event.code] = true; |
|
|
|
|
|
if (event.code === 'Space' && !isJumping && !gamePaused) { |
|
playerVelocity.y = jumpForce; |
|
isJumping = true; |
|
} |
|
|
|
|
|
if (event.code === 'KeyF' && !gamePaused) { |
|
attackObstacle(); |
|
} |
|
} |
|
|
|
function onKeyUp(event) { |
|
keys[event.code] = false; |
|
} |
|
|
|
function attackObstacle() { |
|
const playerBox = new THREE.Box3().setFromObject(player); |
|
|
|
obstacles.forEach((obstacle, index) => { |
|
if (obstacle && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(obstacle))) { |
|
|
|
obstacle.userData.health -= 10; |
|
|
|
|
|
if (obstacle.userData.health <= 0) { |
|
scene.remove(obstacle); |
|
obstacles[index] = null; |
|
score += 50; |
|
document.getElementById('score-display').textContent = score; |
|
} |
|
} |
|
}); |
|
} |
|
|
|
function checkCollisions() { |
|
|
|
let onGround = false; |
|
const playerBox = new THREE.Box3().setFromObject(player); |
|
|
|
platforms.forEach(platform => { |
|
const platformBox = new THREE.Box3().setFromObject(platform); |
|
if (playerBox.intersectsBox(platformBox)) { |
|
|
|
if (player.position.y > platform.position.y + 0.9) { |
|
player.position.y = platform.position.y + 1 + player.geometry.parameters.height / 2; |
|
playerVelocity.y = 0; |
|
isJumping = false; |
|
onGround = true; |
|
} |
|
} |
|
}); |
|
|
|
|
|
if (player.position.y <= 0) { |
|
player.position.y = 0; |
|
playerVelocity.y = 0; |
|
isJumping = false; |
|
onGround = true; |
|
} |
|
|
|
|
|
coins.forEach((coin, index) => { |
|
if (coin && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(coin))) { |
|
scene.remove(coin); |
|
coins[index] = null; |
|
score += 10; |
|
document.getElementById('score-display').textContent = score; |
|
} |
|
}); |
|
|
|
|
|
checkpoints.forEach((checkpoint, index) => { |
|
if (checkpoint && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(checkpoint))) { |
|
showQuiz(index); |
|
} |
|
}); |
|
|
|
|
|
const currentTime = Date.now(); |
|
obstacles.forEach(obstacle => { |
|
if (obstacle && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(obstacle))) { |
|
if (currentTime - lastObstacleHitTime > obstacleHitCooldown) { |
|
playerHealth -= 10; |
|
lastObstacleHitTime = currentTime; |
|
document.getElementById('health-fill').style.width = `${playerHealth}%`; |
|
|
|
|
|
player.material.color.setHex(0xff0000); |
|
setTimeout(() => { |
|
player.material.color.setHex(0xff0000); |
|
}, 200); |
|
|
|
|
|
if (playerHealth <= 0) { |
|
gameOver(); |
|
} |
|
} |
|
} |
|
}); |
|
|
|
|
|
if (!friendFound && new THREE.Box3().setFromObject(player).intersectsBox(new THREE.Box3().setFromObject(friend)) && quizzesCompleted === 4) { |
|
friendFound = true; |
|
gamePaused = true; |
|
|
|
|
|
document.getElementById('final-score').textContent = `Final Score: ${score}`; |
|
document.getElementById('end-screen').classList.remove('hidden'); |
|
document.getElementById('ui-container').classList.add('hidden'); |
|
document.getElementById('controls-info').classList.add('hidden'); |
|
} |
|
|
|
return onGround; |
|
} |
|
|
|
function gameOver() { |
|
gamePaused = true; |
|
document.getElementById('game-over-score').textContent = `Score: ${score}`; |
|
document.getElementById('game-over-screen').classList.remove('hidden'); |
|
document.getElementById('ui-container').classList.add('hidden'); |
|
document.getElementById('controls-info').classList.add('hidden'); |
|
} |
|
|
|
function updateCamera() { |
|
|
|
const targetPosition = new THREE.Vector3(); |
|
targetPosition.copy(player.position); |
|
|
|
|
|
const offset = cameraOffset.clone(); |
|
|
|
|
|
targetPosition.add(offset); |
|
|
|
|
|
camera.position.lerp(targetPosition, 0.1); |
|
|
|
|
|
camera.lookAt(player.position); |
|
} |
|
|
|
function animate() { |
|
if (gamePaused) return; |
|
|
|
requestAnimationFrame(animate); |
|
|
|
|
|
const moveSpeed = playerSpeed; |
|
const moveVector = new THREE.Vector3(0, 0, 0); |
|
|
|
if (keys['KeyW'] || keys['ArrowUp']) { |
|
moveVector.z -= moveSpeed; |
|
} |
|
if (keys['KeyS'] || keys['ArrowDown']) { |
|
moveVector.z += moveSpeed; |
|
} |
|
if (keys['KeyA'] || keys['ArrowLeft']) { |
|
moveVector.x -= moveSpeed; |
|
} |
|
if (keys['KeyD'] || keys['ArrowRight']) { |
|
moveVector.x += moveSpeed; |
|
} |
|
|
|
|
|
if (moveVector.length() > 0) { |
|
moveVector.normalize().multiplyScalar(moveSpeed); |
|
|
|
|
|
if (moveVector.x !== 0 || moveVector.z !== 0) { |
|
player.rotation.y = Math.atan2(moveVector.x, moveVector.z); |
|
} |
|
} |
|
|
|
|
|
playerVelocity.x = moveVector.x; |
|
playerVelocity.z = moveVector.z; |
|
|
|
|
|
playerVelocity.y -= gravity; |
|
|
|
|
|
player.position.x += playerVelocity.x; |
|
player.position.y += playerVelocity.y; |
|
player.position.z += playerVelocity.z; |
|
|
|
|
|
checkCollisions(); |
|
|
|
|
|
updateCamera(); |
|
|
|
renderer.render(scene, camera); |
|
} |
|
|
|
|
|
init(); |
|
</script> |
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=DevForML/3d-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
</html> |