Files
2026-04-26 09:44:19 +02:00

302 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Snake - KinderWelt</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; touch-action: manipulation; }
body {
background: linear-gradient(135deg, #1a472a 0%, #2d5016 100%);
min-height: 100vh; display: flex; flex-direction: column; align-items: center;
font-family: 'Comic Sans MS', cursive, sans-serif; padding: 5px;
}
h1 { color: #4ade80; margin: 5px 0; font-size: 22px; }
.score-board { color: white; font-size: 16px; margin-bottom: 10px; text-align: center; }
#gameCanvas {
background: #0f291e; border: 3px solid #4ade80; border-radius: 8px;
box-shadow: 0 0 15px rgba(74, 222, 128, 0.3); display: block; margin: 0 auto;
}
.main-area { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.controls {
display: flex; gap: 10px; margin: 10px 0; flex-wrap: wrap; justify-content: center;
}
.btn {
background: linear-gradient(135deg, #4ade80, #22c55e); border: none; border-radius: 8px;
padding: 12px 20px; font-size: 16px; cursor: pointer; font-family: inherit; font-weight: bold;
color: white; box-shadow: 0 3px 8px rgba(0,0,0,0.3);
}
.btn:active { transform: scale(0.95); }
.btn-back { background: #ff6b6b; text-decoration: none; }
/* Big Touch Controls */
.touch-controls-area {
display: flex; flex-direction: column; align-items: center;
gap: 5px; margin-top: 10px;
}
.d-pad {
display: grid;
grid-template-columns: 80px 80px 80px;
gap: 8px;
}
.d-btn {
width: 80px; height: 80px;
background: rgba(255,255,255,0.15);
border: 3px solid #4ade80;
border-radius: 15px;
font-size: 36px;
color: #4ade80;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
touch-action: manipulation;
}
.d-btn:active {
background: rgba(74, 222, 128, 0.4);
transform: scale(0.95);
}
.d-btn.center {
background: rgba(74, 222, 128, 0.25);
font-size: 24px;
}
@media (min-width: 700px) {
.main-area { flex-direction: row; align-items: flex-start; }
}
</style>
</head>
<body>
<h1>🐍 Snake</h1>
<div class="score-board">Punkte: <span id="score">0</span> | Highscore: <span id="highscore">0</span></div>
<div class="main-area">
<canvas id="gameCanvas" width="360" height="360"></canvas>
<div class="controls-panel">
<div class="controls">
<button class="btn" id="startBtn" onclick="startGame()">▶️ Start</button>
<a href="../index.html" class="btn btn-back">⬅️ Zurück</a>
</div>
<!-- Touch Controls -->
<div class="touch-controls-area">
<div class="d-pad">
<div></div>
<button class="d-btn" ontouchstart="changeDirection('up'); return false;" onclick="changeDirection('up')"></button>
<div></div>
<button class="d-btn" ontouchstart="changeDirection('left'); return false;" onclick="changeDirection('left')"></button>
<button class="d-btn center" onclick="startGame()"></button>
<button class="d-btn" ontouchstart="changeDirection('right'); return false;" onclick="changeDirection('right')"></button>
<div></div>
<button class="d-btn" ontouchstart="changeDirection('down'); return false;" onclick="changeDirection('down')"></button>
<div></div>
</div>
</div>
</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// Game variables
const gridSize = 18;
const tileCount = canvas.width / gridSize;
let snake = [];
let food = {};
let direction = 'right';
let nextDirection = 'right';
let score = 0;
let highscore = localStorage.getItem('snake_highscore') || 0;
let gameRunning = false;
let gameLoopId;
document.getElementById('highscore').textContent = highscore;
function initGame() {
snake = [
{x: 5, y: 10},
{x: 4, y: 10},
{x: 3, y: 10}
];
direction = 'right';
nextDirection = 'right';
score = 0;
document.getElementById('score').textContent = score;
spawnFood();
}
function spawnFood() {
food = {
x: Math.floor(Math.random() * tileCount),
y: Math.floor(Math.random() * tileCount)
};
for (let segment of snake) {
if (segment.x === food.x && segment.y === food.y) {
spawnFood();
return;
}
}
}
function changeDirection(newDir) {
if (!gameRunning) {
startGame();
return;
}
const opposites = {up: 'down', down: 'up', left: 'right', right: 'left'};
if (opposites[newDir] !== direction) {
nextDirection = newDir;
}
}
function update() {
if (!gameRunning) return;
direction = nextDirection;
const head = {...snake[0]};
switch(direction) {
case 'up': head.y--; break;
case 'down': head.y++; break;
case 'left': head.x--; break;
case 'right': head.x++; break;
}
// Wall collision
if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
gameOver();
return;
}
// Self collision
for (let segment of snake) {
if (head.x === segment.x && head.y === segment.y) {
gameOver();
return;
}
}
snake.unshift(head);
// Check food
if (head.x === food.x && head.y === food.y) {
score += 10;
document.getElementById('score').textContent = score;
spawnFood();
} else {
snake.pop();
}
}
function draw() {
// Background
ctx.fillStyle = '#0f291e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Food
ctx.fillStyle = '#ff6b6b';
ctx.beginPath();
ctx.arc(
food.x * gridSize + gridSize/2,
food.y * gridSize + gridSize/2,
gridSize/2 - 2,
0, Math.PI * 2
);
ctx.fill();
// Snake
snake.forEach((segment, index) => {
ctx.fillStyle = index === 0 ? '#4ade80' : '#22c55e';
ctx.fillRect(
segment.x * gridSize + 1,
segment.y * gridSize + 1,
gridSize - 2,
gridSize - 2
);
// Eyes for head
if (index === 0) {
ctx.fillStyle = '#0f291e';
let eyeX1 = segment.x * gridSize + 4;
let eyeY1 = segment.y * gridSize + 5;
let eyeX2 = segment.x * gridSize + 11;
let eyeY2 = segment.y * gridSize + 5;
if (direction === 'up') { eyeY1 -= 2; eyeY2 -= 2; }
if (direction === 'down') { eyeY1 += 2; eyeY2 += 2; }
if (direction === 'left') { eyeX1 -= 2; eyeX2 -= 2; }
if (direction === 'right') { eyeX1 += 2; eyeX2 += 2; }
ctx.fillRect(eyeX1, eyeY1, 3, 3);
ctx.fillRect(eyeX2, eyeY2, 3, 3);
}
});
}
function gameLoop() {
update();
draw();
gameLoopId = setTimeout(gameLoop, 100);
}
function startGame() {
if (gameRunning) {
// Neustart
clearTimeout(gameLoopId);
}
initGame();
gameRunning = true;
document.getElementById('startBtn').textContent = '🔄 Neustart';
gameLoop();
}
function gameOver() {
gameRunning = false;
clearTimeout(gameLoopId);
if (score > highscore) {
highscore = score;
localStorage.setItem('snake_highscore', highscore);
document.getElementById('highscore').textContent = highscore;
}
// Draw Game Over
ctx.fillStyle = 'rgba(0,0,0,0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = 'bold 30px Comic Sans MS';
ctx.textAlign = 'center';
ctx.fillText('Game Over!', canvas.width/2, canvas.height/2 - 20);
ctx.font = '20px Comic Sans MS';
ctx.fillText('Punkte: ' + score, canvas.width/2, canvas.height/2 + 20);
document.getElementById('startBtn').textContent = '▶️ Nochmal';
}
// Keyboard controls
document.addEventListener('keydown', (e) => {
if (!gameRunning) return;
switch(e.key) {
case 'ArrowUp': case 'w': e.preventDefault(); changeDirection('up'); break;
case 'ArrowDown': case 's': e.preventDefault(); changeDirection('down'); break;
case 'ArrowLeft': case 'a': e.preventDefault(); changeDirection('left'); break;
case 'ArrowRight': case 'd': e.preventDefault(); changeDirection('right'); break;
}
});
// Initial draw
initGame();
draw();
</script>
</body>
</html>