Files
testprojekt/snake.html

276 lines
7.0 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Snake</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #1a1a2e;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
font-family: 'Courier New', monospace;
color: #e0e0e0;
}
h1 {
font-size: 2rem;
margin-bottom: 12px;
color: #4ecca3;
letter-spacing: 4px;
}
#hud {
display: flex;
gap: 40px;
margin-bottom: 12px;
font-size: 1rem;
color: #a0a0c0;
}
#hud span { color: #4ecca3; font-weight: bold; }
canvas {
border: 2px solid #4ecca3;
box-shadow: 0 0 20px rgba(78, 204, 163, 0.3);
display: block;
}
#overlay {
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
}
#overlay h2 {
font-size: 2.5rem;
color: #ff6b6b;
}
#overlay p {
font-size: 1rem;
color: #a0a0c0;
}
#overlay.hidden { display: none; }
button {
margin-top: 8px;
padding: 10px 28px;
font-size: 1rem;
font-family: inherit;
background: #4ecca3;
color: #1a1a2e;
border: none;
cursor: pointer;
letter-spacing: 2px;
font-weight: bold;
}
button:hover { background: #38b28a; }
#controls {
margin-top: 12px;
font-size: 0.75rem;
color: #606080;
}
</style>
</head>
<body>
<h1>SNAKE</h1>
<div id="hud">
Score: <span id="score">0</span> &nbsp;&nbsp; Highscore: <span id="highscore">0</span>
</div>
<div style="position:relative;">
<canvas id="canvas" width="400" height="400"></canvas>
<div id="overlay">
<h2 id="overlay-title">SNAKE</h2>
<p id="overlay-msg">Steuere die Schlange mit den Pfeiltasten oder WASD</p>
<button id="btn">STARTEN</button>
</div>
</div>
<div id="controls">Pfeiltasten / WASD &nbsp;|&nbsp; P = Pause</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const overlay = document.getElementById('overlay');
const overlayTitle = document.getElementById('overlay-title');
const overlayMsg = document.getElementById('overlay-msg');
const btn = document.getElementById('btn');
const scoreEl = document.getElementById('score');
const highscoreEl = document.getElementById('highscore');
const COLS = 20, ROWS = 20;
const CELL = canvas.width / COLS;
let snake, dir, nextDir, food, score, highscore, running, paused, animId;
highscore = parseInt(localStorage.getItem('snake_hs') || '0');
highscoreEl.textContent = highscore;
function init() {
snake = [
{ x: 10, y: 10 },
{ x: 9, y: 10 },
{ x: 8, y: 10 },
];
dir = { x: 1, y: 0 };
nextDir = { x: 1, y: 0 };
score = 0;
scoreEl.textContent = 0;
spawnFood();
}
function spawnFood() {
let pos;
do {
pos = { x: Math.floor(Math.random() * COLS), y: Math.floor(Math.random() * ROWS) };
} while (snake.some(s => s.x === pos.x && s.y === pos.y));
food = pos;
}
function step() {
dir = nextDir;
const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
// Wall collision
if (head.x < 0 || head.x >= COLS || head.y < 0 || head.y >= ROWS) return gameOver();
// Self collision
if (snake.some(s => s.x === head.x && s.y === head.y)) return gameOver();
snake.unshift(head);
if (head.x === food.x && head.y === food.y) {
score++;
scoreEl.textContent = score;
if (score > highscore) {
highscore = score;
highscoreEl.textContent = highscore;
localStorage.setItem('snake_hs', highscore);
}
spawnFood();
} else {
snake.pop();
}
}
function draw() {
// Background
ctx.fillStyle = '#0f0f1a';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Grid (subtle)
ctx.strokeStyle = 'rgba(255,255,255,0.03)';
ctx.lineWidth = 0.5;
for (let x = 0; x <= COLS; x++) {
ctx.beginPath(); ctx.moveTo(x * CELL, 0); ctx.lineTo(x * CELL, canvas.height); ctx.stroke();
}
for (let y = 0; y <= ROWS; y++) {
ctx.beginPath(); ctx.moveTo(0, y * CELL); ctx.lineTo(canvas.width, y * CELL); ctx.stroke();
}
// Food
const fx = food.x * CELL, fy = food.y * CELL;
ctx.fillStyle = '#ff6b6b';
ctx.beginPath();
ctx.arc(fx + CELL / 2, fy + CELL / 2, CELL / 2 - 2, 0, Math.PI * 2);
ctx.fill();
// Snake
snake.forEach((seg, i) => {
const t = i / snake.length;
const r = Math.round(78 + (30 - 78) * t);
const g = Math.round(204 + (150 - 204) * t);
const b = Math.round(163 + (80 - 163) * t);
ctx.fillStyle = `rgb(${r},${g},${b})`;
const pad = i === 0 ? 1 : 2;
ctx.fillRect(seg.x * CELL + pad, seg.y * CELL + pad, CELL - pad * 2, CELL - pad * 2);
// Eyes on head
if (i === 0) {
ctx.fillStyle = '#1a1a2e';
const ex = dir.y !== 0 ? [CELL * 0.3, CELL * 0.7] : [CELL * 0.6, CELL * 0.6];
const ey = dir.x !== 0 ? [CELL * 0.3, CELL * 0.7] : [CELL * 0.6, CELL * 0.6];
const ox = dir.x === -1 ? CELL * 0.2 : 0;
const oy = dir.y === -1 ? CELL * 0.2 : 0;
ctx.beginPath();
ctx.arc(seg.x * CELL + ex[0] + ox, seg.y * CELL + ey[0] + oy, 2, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(seg.x * CELL + ex[1] + ox, seg.y * CELL + ey[1] + oy, 2, 0, Math.PI * 2);
ctx.fill();
}
});
}
let lastTime = 0;
const SPEED = 120; // ms per step
function loop(ts) {
if (!running || paused) return;
if (ts - lastTime >= SPEED) {
step();
lastTime = ts;
}
if (running) draw();
animId = requestAnimationFrame(loop);
}
function startGame() {
init();
running = true;
paused = false;
overlay.classList.add('hidden');
lastTime = 0;
animId = requestAnimationFrame(loop);
}
function gameOver() {
running = false;
cancelAnimationFrame(animId);
overlayTitle.textContent = 'GAME OVER';
overlayTitle.style.color = '#ff6b6b';
overlayMsg.textContent = `Punkte: ${score}`;
btn.textContent = 'NEU STARTEN';
overlay.classList.remove('hidden');
}
btn.addEventListener('click', startGame);
document.addEventListener('keydown', e => {
const keys = {
ArrowUp: { x: 0, y: -1 }, w: { x: 0, y: -1 }, W: { x: 0, y: -1 },
ArrowDown: { x: 0, y: 1 }, s: { x: 0, y: 1 }, S: { x: 0, y: 1 },
ArrowLeft: { x: -1, y: 0 }, a: { x: -1, y: 0 }, A: { x: -1, y: 0 },
ArrowRight: { x: 1, y: 0 }, d: { x: 1, y: 0 }, D: { x: 1, y: 0 },
};
if (keys[e.key]) {
const d = keys[e.key];
// Prevent 180 turn
if (d.x !== -dir.x || d.y !== -dir.y) nextDir = d;
e.preventDefault();
}
if (e.key === 'p' || e.key === 'P') {
if (!running) return;
paused = !paused;
if (!paused) animId = requestAnimationFrame(loop);
}
});
// Initial draw
init();
draw();
</script>
</body>
</html>