Initial commit - Kinderspiele
This commit is contained in:
@@ -0,0 +1,302 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user