elder-derp / index.html
zab12's picture
Add 2 files
bde53c5 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2D Elden Ring</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=MedievalSharp&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #111;
font-family: 'MedievalSharp', cursive;
overflow: hidden;
height: 100vh;
color: #ccc;
}
#game-container {
position: relative;
width: 100%;
height: 100%;
background: linear-gradient(to bottom, #001a33, #000);
overflow: hidden;
}
#game-canvas {
display: block;
background-color: #000;
position: absolute;
top: 0;
left: 0;
}
#hud {
position: absolute;
top: 20px;
left: 20px;
z-index: 100;
color: #fff;
text-shadow: 0 0 5px #000;
font-size: 24px;
}
#health-bar {
width: 200px;
height: 30px;
border: 3px solid #500;
background-color: #300;
position: relative;
margin-bottom: 10px;
}
#health-fill {
height: 100%;
width: 100%;
background-color: #f00;
position: absolute;
transition: width 0.3s;
}
#stamina-bar {
width: 200px;
height: 15px;
border: 2px solid #060;
background-color: #030;
position: relative;
}
#stamina-fill {
height: 100%;
width: 100%;
background-color: #0f0;
position: absolute;
transition: width 0.1s;
}
#enemy-info {
position: absolute;
top: 20px;
right: 20px;
z-index: 100;
color: #fff;
text-shadow: 0 0 5px #000;
font-size: 24px;
}
#title-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.95) 100%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 200;
}
#title {
font-size: 72px;
color: #d4af37;
text-shadow: 0 0 10px #000, 0 0 20px #d4af37;
margin-bottom: 40px;
letter-spacing: 5px;
}
#start-button {
padding: 15px 40px;
font-size: 24px;
font-family: 'MedievalSharp', cursive;
background: linear-gradient(to bottom, #d4af37, #a67c00);
color: #000;
border: none;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
}
#start-button:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0,0,0,0.6);
}
#controls {
position: absolute;
bottom: 20px;
left: 20px;
font-size: 16px;
color: #aaa;
}
#message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0,0,0,0.7);
color: #fff;
padding: 20px 40px;
border: 2px solid #d4af37;
border-radius: 5px;
font-size: 24px;
z-index: 300;
display: none;
}
</style>
</head>
<body>
<div id="game-container">
<canvas id="game-canvas"></canvas>
<div id="hud">
<div id="health-bar">
<div id="health-fill"></div>
</div>
<div id="stamina-bar">
<div id="stamina-fill"></div>
</div>
<div id="runes">Runes: 0</div>
</div>
<div id="enemy-info">
<div id="enemy-health-bar-container">
<div id="enemy-health-bar"></div>
</div>
<div id="enemy-name"></div>
</div>
<div id="controls">
<p>WASD: Move | Space: Jump | Left Click: Attack | Shift: Roll</p>
<p>E: Interact | Q: Use Item | R: Cast Spell</p>
</div>
<div id="title-screen">
<h1 id="title">ELDEN RING</h1>
<button id="start-button">START GAME</button>
</div>
<div id="message"></div>
</div>
<script>
// Game setup
const canvas = document.getElementById('game-canvas');
const ctx = canvas.getContext('2d');
const titleScreen = document.getElementById('title-screen');
const startButton = document.getElementById('start-button');
const healthFill = document.getElementById('health-fill');
const staminaFill = document.getElementById('stamina-fill');
const runesDisplay = document.getElementById('runes');
const enemyHealthBar = document.getElementById('enemy-health-bar');
const enemyNameDisplay = document.getElementById('enemy-name');
const messageDisplay = document.getElementById('message');
// Resize canvas to full window
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Game state
let gameRunning = false;
let runes = 0;
let playerHealth = 100;
let playerMaxHealth = 100;
let playerStamina = 100;
let playerMaxStamina = 100;
let selectedEnemy = null;
// Player properties
const player = {
x: canvas.width / 4,
y: canvas.height / 2,
width: 60,
height: 100,
speed: 5,
jumpPower: 15,
isJumping: false,
isAttacking: false,
isRolling: false,
direction: 1, // 1 = right, -1 = left
velX: 0,
velY: 0,
frame: 0,
attackCooldown: 0,
rollCooldown: 0,
invulnerable: 0
};
// Enemy types
const enemies = [
{
name: "Godrick Soldier",
health: 50,
maxHealth: 50,
damage: 10,
width: 60,
height: 90,
speed: 2,
x: 800,
y: canvas.height - 100
},
{
name: "Margit's Phantom",
health: 100,
maxHealth: 100,
damage: 20,
width: 70,
height: 110,
speed: 3,
x: 1200,
y: canvas.height - 110
}
];
// Level elements
const platforms = [
{ x: 0, y: canvas.height - 50, width: canvas.width * 2, height: 50 },
{ x: 500, y: canvas.height - 200, width: 200, height: 20 },
{ x: 900, y: canvas.height - 300, width: 200, height: 20 }
];
const bonfire = {
x: 400,
y: canvas.height - 70,
width: 40,
height: 40,
lit: false
};
// Start game
startButton.addEventListener('click', () => {
titleScreen.style.display = 'none';
gameRunning = true;
startGame();
});
function startGame() {
// Reset player
player.x = canvas.width / 4;
player.y = canvas.height / 2;
player.health = 100;
player.stamina = 100;
player.velX = 0;
player.velY = 0;
player.isJumping = false;
player.isAttacking = false;
player.isRolling = false;
player.invulnerable = 0;
// Reset enemies
enemies.forEach(enemy => {
enemy.health = enemy.maxHealth;
});
bonfire.lit = false;
runes = 0;
updateHUD();
// Start game loop
gameLoop();
}
// Controls
const keys = {};
document.addEventListener('keydown', (e) => {
keys[e.key.toLowerCase()] = true;
// Quick restart
if (e.key === '`') {
if (!gameRunning) {
titleScreen.style.display = 'none';
gameRunning = true;
startGame();
}
}
});
document.addEventListener('keyup', (e) => {
keys[e.key.toLowerCase()] = false;
});
canvas.addEventListener('click', (e) => {
if (player.attackCooldown <= 0 && player.stamina > 10 && !player.isJumping && gameRunning) {
player.isAttacking = true;
player.attackCooldown = 20;
player.stamina -= 10;
// Check if attack hits enemy
const attackRange = player.direction === 1 ?
{ x: player.x + player.width, y: player.y, width: 50, height: player.height } :
{ x: player.x - 50, y: player.y, width: 50, height: player.height };
for (const enemy of enemies) {
if (checkCollision(attackRange, enemy)) {
enemy.health -= 20;
if (enemy.health <= 0) {
runes += 50;
enemy.health = 0;
displayMessage(`${enemy.name} defeated! +50 Runes`);
}
updateHUD();
}
}
}
});
// Game loop
function gameLoop() {
if (!gameRunning) return;
update();
render();
requestAnimationFrame(gameLoop);
}
function update() {
// Player movement
if (player.isRolling || player.isAttacking) {
player.velX *= 0.9;
} else {
if (keys['a'] || keys['arrowleft']) {
player.velX = -player.speed;
player.direction = -1;
} else if (keys['d'] || keys['arrowright']) {
player.velX = player.speed;
player.direction = 1;
} else {
player.velX *= 0.8;
}
}
// Jumping
if ((keys['w'] || keys['arrowup'] || keys[' ']) && !player.isJumping && player.velY === 0) {
player.velY = -player.jumpPower;
player.isJumping = true;
}
// Rolling
if (keys['shift'] && !player.isRolling && !player.isAttacking && player.stamina > 15) {
player.isRolling = true;
player.rollCooldown = 40;
player.invulnerable = 30;
player.stamina -= 15;
player.velX = player.direction * player.speed * 2;
}
// Gravity
player.velY += 0.8;
// Apply velocity
player.x += player.velX;
player.y += player.velY;
// Platform collision
let onGround = false;
for (const platform of platforms) {
if (
player.x < platform.x + platform.width &&
player.x + player.width > platform.x &&
player.y < platform.y + platform.height &&
player.y + player.height > platform.y &&
player.velY > 0
) {
player.y = platform.y - player.height;
player.velY = 0;
player.isJumping = false;
onGround = true;
}
}
// Boundary checks
if (player.x < 0) player.x = 0;
if (player.x + player.width > canvas.width * 2) player.x = canvas.width * 2 - player.width;
if (player.y + player.height > canvas.height) {
player.y = canvas.height - player.height;
player.velY = 0;
player.isJumping = false;
onGround = true;
}
// Check bonfire
if (
Math.abs(player.x - bonfire.x) < 50 &&
Math.abs((player.y + player.height) - (bonfire.y + bonfire.height)) < 50 &&
keys['e']
) {
if (!bonfire.lit) {
bonfire.lit = true;
playerHealth = playerMaxHealth;
playerStamina = playerMaxStamina;
displayMessage("Bonfire lit. Health and stamina restored.");
// Reset enemies
enemies.forEach(enemy => {
enemy.health = enemy.maxHealth;
});
}
}
// Enemy updates
selectedEnemy = null;
for (const enemy of enemies) {
if (enemy.health <= 0) continue;
// Simple AI - follow player if on same platform
const playerPlatform = getPlatformUnder(player);
const enemyPlatform = getPlatformUnder(enemy);
if (playerPlatform === enemyPlatform) {
if (player.x < enemy.x) {
enemy.x -= enemy.speed;
} else {
enemy.x += enemy.speed;
}
}
// Check if enemy is attacking player
if (
Math.abs(player.x - enemy.x) < 80 &&
Math.abs(player.y - enemy.y) < player.height &&
player.invulnerable <= 0
) {
if (playerHealth > 0) {
playerHealth -= enemy.damage;
player.invulnerable = 30;
displayMessage(`Hit by ${enemy.name}! -${enemy.damage} HP`);
if (playerHealth <= 0) {
playerHealth = 0;
displayMessage("YOU DIED", 3000);
setTimeout(() => {
gameRunning = false;
titleScreen.style.display = 'flex';
}, 3000);
}
}
}
// Check if player has targeted this enemy
if (Math.abs(player.x - enemy.x) < 200 && Math.abs(player.y - enemy.y) < 100) {
selectedEnemy = enemy;
}
}
// Update cooldowns
if (player.attackCooldown > 0) player.attackCooldown--;
else player.isAttacking = false;
if (player.rollCooldown > 0) player.rollCooldown--;
else player.isRolling = false;
if (player.invulnerable > 0) player.invulnerable--;
// Regenerate stamina when not moving
if (player.velX === 0 && player.velY === 0 && onGround) {
playerStamina = Math.min(playerMaxStamina, playerStamina + 0.5);
} else {
playerStamina = Math.min(playerMaxStamina, playerStamina + 0.1);
}
updateHUD();
updateCamera();
}
function getPlatformUnder(entity) {
for (let i = 0; i < platforms.length; i++) {
if (
entity.x + entity.width > platforms[i].x &&
entity.x < platforms[i].x + platforms[i].width &&
Math.abs((entity.y + entity.height) - platforms[i].y) < 5
) {
return i;
}
}
return -1;
}
function updateHUD() {
healthFill.style.width = `${(playerHealth / playerMaxHealth) * 100}%`;
staminaFill.style.width = `${(playerStamina / playerMaxStamina) * 100}%`;
runesDisplay.textContent = `Runes: ${runes}`;
if (selectedEnemy) {
enemyHealthBar.style.width = `${(selectedEnemy.health / selectedEnemy.maxHealth) * 100}%`;
enemyHealthBar.style.backgroundColor = selectedEnemy.health > 50 ? '#0f0' :
selectedEnemy.health > 25 ? '#ff0' : '#f00';
enemyNameDisplay.textContent = selectedEnemy.name;
} else {
enemyHealthBar.style.width = '0%';
enemyNameDisplay.textContent = '—';
}
}
let cameraX = 0;
function updateCamera() {
// Simple camera follow with some lead space
cameraX = player.x - canvas.width / 4;
cameraX = Math.max(0, Math.min(canvas.width * 2 - canvas.width, cameraX));
}
function displayMessage(text, duration = 1500) {
messageDisplay.textContent = text;
messageDisplay.style.display = 'block';
setTimeout(() => {
messageDisplay.style.display = 'none';
}, duration);
}
function checkCollision(rect1, rect2) {
return (
rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y
);
}
function render() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw background
if (canvas.width >= 768) { // Only draw detailed background on larger screens
// Stars
ctx.fillStyle = '#fff';
for (let i = 0; i < 100; i++) {
const x = (i * 300 + (Math.sin(Date.now() / 1000 + i) * 100)) % (canvas.width * 2);
const y = (Math.sin(i) * 100 + i * 50) % canvas.height;
const size = 1 + Math.random();
ctx.fillRect(x - cameraX, y, size, size);
}
// Moon
ctx.beginPath();
ctx.arc(
200 - cameraX * 0.2,
200,
50,
0,
Math.PI * 2
);
ctx.fillStyle = '#d4af37';
ctx.fill();
}
// Draw platforms
ctx.fillStyle = '#654321';
for (const platform of platforms) {
ctx.fillRect(platform.x - cameraX, platform.y, platform.width, platform.height);
}
// Draw bonfire
ctx.fillStyle = bonfire.lit ? '#f80' : '#666';
ctx.fillRect(bonfire.x - cameraX, bonfire.y, bonfire.width, bonfire.height);
// Draw enemies
for (const enemy of enemies) {
if (enemy.health <= 0) continue;
// Enemy body
ctx.fillStyle = enemy.name.includes('Margit') ? '#0af' : '#864';
ctx.fillRect(enemy.x - cameraX, enemy.y, enemy.width, enemy.height);
// Enemy head
ctx.fillStyle = '#fff';
ctx.beginPath();
ctx.arc(
enemy.x - cameraX + enemy.width / 2,
enemy.y - 10,
15,
0,
Math.PI * 2
);
ctx.fill();
// Enemy weapon
ctx.fillStyle = '#555';
ctx.fillRect(
enemy.x - cameraX + (enemy.x < player.x ? enemy.width : -20),
enemy.y + enemy.height / 2,
30,
5
);
}
// Draw player
if (player.invulnerable > 0 && Math.floor(player.invulnerable / 5) % 2 === 0) {
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
} else {
ctx.fillStyle = player.isRolling ? '#369' : '#47a';
}
ctx.fillRect(player.x - cameraX, player.y, player.width, player.height);
// Player head
ctx.fillStyle = '#fff';
ctx.beginPath();
ctx.arc(
player.x - cameraX + player.width / 2,
player.y - 10,
20,
0,
Math.PI * 2
);
ctx.fill();
// Player weapon
ctx.fillStyle = '#d4af37';
if (player.isAttacking) {
ctx.fillRect(
player.x - cameraX + (player.direction === 1 ? player.width : -40),
player.y + player.height / 2,
40,
8
);
} else {
ctx.fillRect(
player.x - cameraX + (player.direction === 1 ? 10 : player.width - 30),
player.y + player.height / 2,
20,
4
);
}
// Draw erdtree in background
if (canvas.width >= 768) {
ctx.fillStyle = 'rgba(0, 180, 60, 0.3)';
ctx.beginPath();
ctx.moveTo(1800 - cameraX * 0.1, canvas.height);
ctx.lineTo(1850 - cameraX * 0.1, canvas.height - 150);
ctx.lineTo(1900 - cameraX * 0.1, canvas.height - 300);
ctx.lineTo(1950 - cameraX * 0.1, canvas.height - 450);
ctx.lineTo(2000 - cameraX * 0.1, canvas.height - 600);
ctx.lineTo(1950 - cameraX * 0.1, canvas.height - 450);
ctx.lineTo(1900 - cameraX * 0.1, canvas.height - 300);
ctx.lineTo(1850 - cameraX * 0.1, canvas.height - 150);
ctx.lineTo(1800 - cameraX * 0.1, canvas.height);
ctx.fill();
ctx.fillStyle = 'rgba(200, 180, 0, 0.6)';
ctx.beginPath();
ctx.arc(2000 - cameraX * 0.1, canvas.height - 650, 100, 0, Math.PI * 2);
ctx.fill();
}
}
</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 <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
</html>