272 lines
11 KiB
HTML
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> |