Files
Kinderspiele/game-server/public/spiele/zielscheibe.html
T
2026-04-26 09:44:19 +02:00

272 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>Zielscheibe - KinderWelt</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }
body {
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
min-height: 100vh; display: flex; flex-direction: column; align-items: center;
font-family: 'Comic Sans MS', cursive, sans-serif; padding: 20px; overflow: hidden;
}
h1 { color: white; margin-bottom: 10px; font-size: 26px; }
.score-board {
display: flex; gap: 30px; margin-bottom: 15px; color: white; font-size: 18px;
}
.score-item { text-align: center; }
.score-value { font-size: 32px; font-weight: bold; color: #feca57; }
.game-container {
position: relative; width: 350px; height: 350px;
background: rgba(255,255,255,0.1); border-radius: 20px;
overflow: hidden; cursor: crosshair;
}
.target {
position: absolute; border-radius: 50%; cursor: pointer;
animation: appear 0.3s ease-out;
}
@keyframes appear {
from { transform: scale(0); }
to { transform: scale(1); }
}
.target.hit { animation: hit 0.3s ease-out forwards; }
@keyframes hit {
to { transform: scale(1.5); opacity: 0; }
}
/* Ringe der Zielscheibe */
.ring-1 { width: 60px; height: 60px; background: radial-gradient(circle, #ff6b6b 30%, transparent 30%); }
.ring-2 { width: 80px; height: 80px; background: radial-gradient(circle, #ff6b6b 23%, #feca57 23%, #feca57 38%, transparent 38%); }
.ring-3 { width: 100px; height: 100px; background: radial-gradient(circle, #ff6b6b 18%, #feca57 18%, #feca57 30%, #4ade80 30%, #4ade80 45%, transparent 45%); }
.ring-4 { width: 120px; height: 120px; background: radial-gradient(circle, #ff6b6b 15%, #feca57 15%, #feca57 25%, #4ade80 25%, #4ade80 38%, #3b82f6 38%, #3b82f6 50%, transparent 50%); }
.ring-5 { width: 140px; height: 140px; background: radial-gradient(circle, #ff6b6b 13%, #feca57 13%, #feca57 21%, #4ade80 21%, #4ade80 33%, #3b82f6 33%, #3b82f6 43%, #fff 43%, #fff 50%, transparent 50%); }
.hit-text {
position: absolute; font-weight: bold; font-size: 24px;
animation: floatUp 1s ease-out forwards; pointer-events: none;
}
@keyframes floatUp {
0% { transform: translateY(0) scale(1); opacity: 1; }
100% { transform: translateY(-50px) scale(1.5); opacity: 0; }
}
.hit-10 { color: #ff6b6b; }
.hit-8 { color: #feca57; }
.hit-6 { color: #4ade80; }
.hit-4 { color: #3b82f6; }
.hit-2 { color: #a0aec0; }
.timer { color: white; font-size: 48px; margin: 10px 0; font-weight: bold; }
.controls { display: flex; gap: 15px; margin-top: 15px; }
.btn {
background: white; border: none; border-radius: 10px; padding: 12px 25px;
font-size: 16px; cursor: pointer; font-family: inherit; font-weight: bold;
}
.btn-start { background: #4ade80; color: white; }
.btn-back { background: #ff6b6b; color: white; text-decoration: none; }
.game-over {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
background: white; padding: 30px; border-radius: 20px; text-align: center;
display: none; z-index: 100;
}
.game-over h2 { color: #333; margin-bottom: 15px; }
.final-score { font-size: 48px; color: #4ade80; font-weight: bold; }
</style>
</head>
<body>
<h1>🎯 Zielscheibe</h1>
<div class="score-board">
<div class="score-item">
<div>Punkte</div>
<div class="score-value" id="score">0</div>
</div>
<div class="score-item">
<div>Treffer</div>
<div class="score-value" id="hits">0</div>
</div>
</div>
<div class="timer" id="timer">30</div>
<div class="game-container" id="gameContainer">
<div class="game-over" id="gameOver">
<h2>🎉 Zeit abgelaufen!</h2>
<div class="final-score" id="finalScore">0</div>
<div style="margin-top: 15px; color: #666">Punkte</div>
<button class="btn btn-start" onclick="startGame()" style="margin-top: 20px">🔄 Nochmal</button>
</div>
</div>
<div class="controls">
<button class="btn btn-start" id="startBtn" onclick="startGame()">▶️ Start</button>
<a href="../index.html" class="btn btn-back">⬅️ Zurück</a>
</div>
<script>
let score = 0;
let hits = 0;
let timeLeft = 30;
let gameActive = false;
let timerInterval = null;
let targetInterval = null;
let highscore = localStorage.getItem('zielscheibe_highscore') || 0;
const container = document.getElementById('gameContainer');
const scoreEl = document.getElementById('score');
const hitsEl = document.getElementById('hits');
const timerEl = document.getElementById('timer');
const gameOverEl = document.getElementById('gameOver');
const finalScoreEl = document.getElementById('finalScore');
function startGame() {
score = 0;
hits = 0;
timeLeft = 30;
gameActive = true;
scoreEl.textContent = '0';
hitsEl.textContent = '0';
timerEl.textContent = '30';
gameOverEl.style.display = 'none';
document.getElementById('startBtn').style.display = 'none';
// Container leeren
container.innerHTML = '';
container.appendChild(gameOverEl);
// Erste Zielscheibe
spawnTarget();
// Timer
timerInterval = setInterval(() => {
timeLeft--;
timerEl.textContent = timeLeft;
if (timeLeft <= 10) {
timerEl.style.color = '#ff6b6b';
}
if (timeLeft <= 0) {
endGame();
}
}, 1000);
// Neue Zielscheiben automatisch
targetInterval = setInterval(() => {
if (gameActive && document.querySelectorAll('.target').length < 3) {
spawnTarget();
}
}, 1500);
}
function spawnTarget() {
const target = document.createElement('div');
const ringSize = Math.floor(Math.random() * 5) + 1;
target.className = 'target ring-' + ringSize;
// Zufällige Position (nicht zu nah am Rand)
const maxX = container.offsetWidth - 150;
const maxY = container.offsetHeight - 150;
const x = 20 + Math.random() * maxX;
const y = 20 + Math.random() * maxY;
target.style.left = x + 'px';
target.style.top = y + 'px';
// Punkte basierend auf Ring
const points = ringSize === 1 ? 10 : ringSize === 2 ? 8 : ringSize === 3 ? 6 : ringSize === 4 ? 4 : 2;
target.onclick = function(e) {
e.stopPropagation();
if (!gameActive) return;
hitTarget(target, points, e.clientX, e.clientY);
};
// Automatisch entfernen nach 3 Sekunden
setTimeout(() => {
if (target.parentNode) {
target.remove();
}
}, 3000);
container.appendChild(target);
}
function hitTarget(target, points, x, y) {
score += points;
hits++;
scoreEl.textContent = score;
hitsEl.textContent = hits;
// Hit-Text anzeigen
const hitText = document.createElement('div');
hitText.className = 'hit-text hit-' + points;
hitText.textContent = '+' + points;
hitText.style.left = (target.offsetLeft + target.offsetWidth/2 - 20) + 'px';
hitText.style.top = target.offsetTop + 'px';
container.appendChild(hitText);
setTimeout(() => hitText.remove(), 1000);
// Animation
target.classList.add('hit');
// Sound via TTS
if ('speechSynthesis' in window && points >= 8) {
const utterance = new SpeechSynthesisUtterance(points + ' Punkte');
utterance.lang = 'de-DE';
utterance.rate = 1.2;
speechSynthesis.speak(utterance);
}
setTimeout(() => {
target.remove();
// Neue Zielscheibe sofort
if (gameActive) spawnTarget();
}, 300);
}
function endGame() {
gameActive = false;
clearInterval(timerInterval);
clearInterval(targetInterval);
finalScoreEl.textContent = score;
gameOverEl.style.display = 'block';
timerEl.style.color = 'white';
// Highscore
if (score > highscore) {
highscore = score;
localStorage.setItem('zielscheibe_highscore', highscore);
finalScoreEl.innerHTML = score + '<br><small style="font-size:20px">🏆 Neuer Rekord!</small>';
}
if ('speechSynthesis' in window) {
const utterance = new SpeechSynthesisUtterance('Spiel vorbei. Du hast ' + score + ' Punkte erreicht.');
utterance.lang = 'de-DE';
speechSynthesis.speak(utterance);
}
}
// Verfehlte Klicks = -1 Punkt
container.addEventListener('click', (e) => {
if (!gameActive || e.target.classList.contains('target')) return;
score = Math.max(0, score - 1);
scoreEl.textContent = score;
// Visuelles Feedback
const missText = document.createElement('div');
missText.className = 'hit-text';
missText.style.color = '#ff6b6b';
missText.textContent = '-1';
missText.style.left = (e.offsetX - 10) + 'px';
missText.style.top = (e.offsetY - 20) + 'px';
container.appendChild(missText);
setTimeout(() => missText.remove(), 800);
});
</script>
</body>
</html>