rpg / index.html
CaffieneRats's picture
Add 3 files
dd86daa verified
Raw
History Blame Contribute Delete
17.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D RPG Adventure</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: 'Arial', sans-serif;
}
#game-container {
position: relative;
width: 100vw;
height: 100vh;
}
#ui {
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 20px;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
pointer-events: none;
z-index: 10;
}
#controls {
position: absolute;
bottom: 20px;
right: 20px;
z-index: 10;
background: rgba(0, 0, 0, 0.5);
padding: 10px;
border-radius: 10px;
color: white;
}
#start-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 20;
}
.btn {
background: linear-gradient(135deg, #6e8efb, #a777e3);
border: none;
color: white;
padding: 12px 24px;
margin: 10px;
border-radius: 30px;
cursor: pointer;
font-size: 18px;
font-weight: bold;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
pointer-events: auto;
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
.btn:active {
transform: translateY(1px);
}
#health-bar {
width: 200px;
height: 20px;
background: rgba(255, 0, 0, 0.3);
border-radius: 10px;
overflow: hidden;
margin-bottom: 10px;
}
#health-progress {
height: 100%;
width: 100%;
background: linear-gradient(90deg, #ff0000, #ff5e00);
transition: width 0.3s;
}
#score {
font-size: 24px;
margin-bottom: 10px;
}
#game-title {
font-size: 48px;
margin-bottom: 30px;
text-shadow: 0 0 10px #6e8efb, 0 0 20px #a777e3;
animation: glow 2s infinite alternate;
}
@keyframes glow {
from {
text-shadow: 0 0 10px #6e8efb, 0 0 20px #a777e3;
}
to {
text-shadow: 0 0 15px #6e8efb, 0 0 30px #a777e3, 0 0 40px #a777e3;
}
}
#game-over-screen, #victory-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 20;
}
</style>
</head>
<body>
<div id="game-container">
<div id="ui">
<div id="health-bar">
<div id="health-progress"></div>
</div>
<div id="score">Score: 0</div>
<div id="items">Items: 0/5</div>
</div>
<div id="controls">
<div>WASD: Move</div>
<div>Space: Jump</div>
<div>Mouse: Look around</div>
</div>
<div id="start-screen">
<h1 id="game-title">3D RPG Adventure</h1>
<p class="mb-8">Explore the world, collect items, and avoid obstacles!</p>
<button id="start-btn" class="btn">Start Game</button>
</div>
<div id="game-over-screen">
<h1 class="text-4xl font-bold mb-4">Game Over!</h1>
<p id="final-score" class="text-2xl mb-8">Your score: 0</p>
<button id="restart-btn" class="btn">Play Again</button>
</div>
<div id="victory-screen">
<h1 class="text-4xl font-bold mb-4">Victory!</h1>
<p id="victory-score" class="text-2xl mb-8">Your score: 0</p>
<button id="victory-restart-btn" class="btn">Play Again</button>
</div>
</div>
<script>
// Game variables
let scene, camera, renderer, player, controls;
let health = 100;
let score = 0;
let itemsCollected = 0;
let itemsTotal = 5;
let gameStarted = false;
let obstacles = [];
let collectibles = [];
let keys = {};
let playerVelocity = new THREE.Vector3();
let playerDirection = new THREE.Vector3();
let clock = new THREE.Clock();
// Initialize the game
function init() {
// Create scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB); // Sky blue
// Create camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 10, 20);
// Create renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.getElementById('game-container').appendChild(renderer.domElement);
// Add lights
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(10, 20, 10);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
scene.add(directionalLight);
// Create ground
const groundGeometry = new THREE.PlaneGeometry(100, 100);
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0x3a5f0b,
roughness: 0.8
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// Create player
const playerGeometry = new THREE.CapsuleGeometry(0.5, 1, 8, 16);
const playerMaterial = new THREE.MeshStandardMaterial({
color: 0x4169E1,
roughness: 0.3,
metalness: 0.5
});
player = new THREE.Mesh(playerGeometry, playerMaterial);
player.castShadow = true;
player.position.y = 1;
scene.add(player);
// Add camera controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target = player.position;
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Create obstacles
createObstacles();
// Create collectibles
createCollectibles();
// Event listeners
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', resetGame);
document.getElementById('victory-restart-btn').addEventListener('click', resetGame);
// Start game loop
animate();
}
function createObstacles() {
const obstacleGeometry = new THREE.BoxGeometry(3, 2, 3);
const obstacleMaterial = new THREE.MeshStandardMaterial({
color: 0x8B4513,
roughness: 0.7
});
for (let i = 0; i < 10; i++) {
const obstacle = new THREE.Mesh(obstacleGeometry, obstacleMaterial);
obstacle.castShadow = true;
obstacle.receiveShadow = true;
// Random position
obstacle.position.x = (Math.random() - 0.5) * 80;
obstacle.position.z = (Math.random() - 0.5) * 80;
obstacle.position.y = 1;
scene.add(obstacle);
obstacles.push(obstacle);
}
}
function createCollectibles() {
const collectibleGeometry = new THREE.SphereGeometry(0.5, 16, 16);
const collectibleMaterial = new THREE.MeshStandardMaterial({
color: 0xFFD700,
roughness: 0.2,
metalness: 0.8,
emissive: 0xFFD700,
emissiveIntensity: 0.5
});
for (let i = 0; i < itemsTotal; i++) {
const collectible = new THREE.Mesh(collectibleGeometry, collectibleMaterial);
collectible.castShadow = true;
// Random position
collectible.position.x = (Math.random() - 0.5) * 80;
collectible.position.z = (Math.random() - 0.5) * 80;
collectible.position.y = 0.5;
scene.add(collectible);
collectibles.push(collectible);
}
}
function startGame() {
document.getElementById('start-screen').style.display = 'none';
gameStarted = true;
resetGame();
}
function resetGame() {
// Hide game over/victory screens
document.getElementById('game-over-screen').style.display = 'none';
document.getElementById('victory-screen').style.display = 'none';
// Reset game state
health = 100;
score = 0;
itemsCollected = 0;
updateUI();
// Reset player position
player.position.set(0, 1, 0);
playerVelocity.set(0, 0, 0);
// Reset collectibles
collectibles.forEach(collectible => {
collectible.visible = true;
});
// Reset camera
camera.position.set(0, 10, 20);
controls.target.copy(player.position);
}
function updateUI() {
document.getElementById('health-progress').style.width = `${health}%`;
document.getElementById('score').textContent = `Score: ${score}`;
document.getElementById('items').textContent = `Items: ${itemsCollected}/${itemsTotal}`;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onKeyDown(event) {
keys[event.code] = true;
// Space to jump
if (event.code === 'Space' && player.position.y <= 1.1) {
playerVelocity.y = 5;
}
}
function onKeyUp(event) {
keys[event.code] = false;
}
function handlePlayerMovement(delta) {
playerDirection.set(0, 0, 0);
if (keys['KeyW']) playerDirection.z = -1;
if (keys['KeyS']) playerDirection.z = 1;
if (keys['KeyA']) playerDirection.x = -1;
if (keys['KeyD']) playerDirection.x = 1;
playerDirection.normalize();
// Apply movement relative to camera
const angle = Math.atan2(
camera.position.x - player.position.x,
camera.position.z - player.position.z
);
const moveX = playerDirection.x * Math.cos(angle) - playerDirection.z * Math.sin(angle);
const moveZ = playerDirection.z * Math.cos(angle) + playerDirection.x * Math.sin(angle);
playerVelocity.x = moveX * 10;
playerVelocity.z = moveZ * 10;
// Apply gravity
playerVelocity.y -= 20 * delta;
// Update position
player.position.x += playerVelocity.x * delta;
player.position.y += playerVelocity.y * delta;
player.position.z += playerVelocity.z * delta;
// Keep player on ground
if (player.position.y < 1) {
player.position.y = 1;
playerVelocity.y = 0;
}
// Check collisions with obstacles
obstacles.forEach(obstacle => {
const distance = player.position.distanceTo(obstacle.position);
if (distance < 2) {
// Push player away from obstacle
const direction = new THREE.Vector3().subVectors(player.position, obstacle.position).normalize();
player.position.add(direction.multiplyScalar(0.1));
// Reduce health
health -= 0.5;
updateUI();
if (health <= 0) {
gameOver();
}
}
});
// Check collection of items
collectibles.forEach((collectible, index) => {
if (collectible.visible) {
const distance = player.position.distanceTo(collectible.position);
if (distance < 1.5) {
collectible.visible = false;
itemsCollected++;
score += 100;
updateUI();
if (itemsCollected >= itemsTotal) {
victory();
}
}
}
});
}
function gameOver() {
document.getElementById('final-score').textContent = `Your score: ${score}`;
document.getElementById('game-over-screen').style.display = 'flex';
gameStarted = false;
}
function victory() {
score += 1000;
updateUI();
document.getElementById('victory-score').textContent = `Your score: ${score}`;
document.getElementById('victory-screen').style.display = 'flex';
gameStarted = false;
}
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
if (gameStarted) {
handlePlayerMovement(delta);
// Update camera to follow player
controls.target.copy(player.position);
camera.position.x = player.position.x;
camera.position.z = player.position.z + 10;
camera.position.y = player.position.y + 5;
controls.update();
}
// Rotate collectibles
collectibles.forEach(collectible => {
if (collectible.visible) {
collectible.rotation.y += delta;
}
});
renderer.render(scene, camera);
}
// Start the game
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=CaffieneRats/rpg" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>