638 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			638 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html lang="de">
 | |
| <head>
 | |
|     <meta charset="UTF-8">
 | |
|     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | |
|     <title>Banana Runner | PonyWave Tools</title>
 | |
|     <link rel="icon" href="https://tools.ponywave.de/banana_run/icon.jpg">
 | |
| 
 | |
|     <!-- Open Graph Tags -->
 | |
|     <meta property="og:title" content="Banana Runner | PonyWave Tools">
 | |
|     <meta property="og:description" content="Hilf der Banane über Hindernisse zu springen und erreiche einen neuen Highscore!">
 | |
|     <meta property="og:url" content="https://tools.ponywave.de/banana_run">
 | |
|     <meta property="og:type" content="website">
 | |
|     <meta property="og:image" content="https://tools.ponywave.de/banana_run/icon.jpg">
 | |
|     <meta name="theme-color" content="#87CEEB">
 | |
| 
 | |
|     <!-- Umami Stats -->
 | |
|     <script defer src="https://stats.ponywave.de/script" data-website-id="9ef713d2-adb9-4906-9df5-708d8a8b9131" data-tag="banana_run"></script>
 | |
| 
 | |
|     <style>
 | |
|         :root {
 | |
|             --bg-color: #ffffff;
 | |
|             --text-color: #000000;
 | |
|             --ground-color: #333333;
 | |
|             --obstacle-color: #4a4a4a;
 | |
|             --mountain-color: #a0a0a0;
 | |
|             --cloud-color: #ffffff;
 | |
|             --sky-color: #87CEEB;
 | |
|         }
 | |
| 
 | |
|         [data-theme="dark"] {
 | |
|             --bg-color: #1a1a1a;
 | |
|             --text-color: #ffffff;
 | |
|             --ground-color: #666666;
 | |
|             --obstacle-color: #888888;
 | |
|             --mountain-color: #4a4a4a;
 | |
|             --cloud-color: #cccccc;
 | |
|             --sky-color: #1a1a3a;
 | |
|         }
 | |
| 
 | |
|         body {
 | |
|             margin: 0;
 | |
|             display: flex;
 | |
|             flex-direction: column;
 | |
|             align-items: center;
 | |
|             min-height: 100vh;
 | |
|             background-color: var(--bg-color);
 | |
|             color: var(--text-color);
 | |
|             font-family: Arial, sans-serif;
 | |
|             transition: background-color 0.3s, color 0.3s;
 | |
|             padding-bottom: 60px; /* Platz für den Footer */
 | |
|             position: relative;
 | |
|         }
 | |
| 
 | |
|         #game-container {
 | |
|             position: relative;
 | |
|             width: 800px;
 | |
|             height: 300px;
 | |
|             border: 2px solid var(--text-color);
 | |
|             overflow: hidden;
 | |
|             margin-top: 20px;
 | |
|             background-color: var(--sky-color);
 | |
|             transition: background-color 0.3s;
 | |
|         }
 | |
| 
 | |
|         .mountain {
 | |
|             position: absolute;
 | |
|             bottom: 0;
 | |
|             width: 0;
 | |
|             height: 0;
 | |
|             border-left: 50px solid transparent;
 | |
|             border-right: 50px solid transparent;
 | |
|             border-bottom: 100px solid var(--mountain-color);
 | |
|             transition: border-bottom-color 0.3s;
 | |
|         }
 | |
| 
 | |
|         .mountain1 { left: 50px; }
 | |
|         .mountain2 { left: 200px; transform: scale(1.5); z-index: 1; }
 | |
|         .mountain3 { left: 400px; transform: scale(0.8); bottom: 0; transform-origin: bottom; }
 | |
|         .mountain4 { left: 600px; transform: scale(1.2); z-index: 1; }
 | |
| 
 | |
|         .mountains-container {
 | |
|             position: absolute;
 | |
|             bottom: 0;
 | |
|             width: 1600px;
 | |
|             height: 100px;
 | |
|             animation: moveMountains linear infinite 20s;
 | |
|             animation-play-state: paused;
 | |
|         }
 | |
| 
 | |
|         .mountain-set-2 {
 | |
|             position: absolute;
 | |
|             left: 800px;
 | |
|             bottom: 0;
 | |
|             width: 800px;
 | |
|             height: 100%;
 | |
|         }
 | |
| 
 | |
|         @keyframes moveMountains {
 | |
|             from {
 | |
|                 transform: translateX(0);
 | |
|             }
 | |
|             to {
 | |
|                 transform: translateX(-800px);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         .cloud {
 | |
|             position: absolute;
 | |
|             background-color: var(--cloud-color);
 | |
|             border-radius: 20px;
 | |
|             transition: background-color 0.3s;
 | |
|             opacity: 0.8;
 | |
|             animation: moveCloud linear infinite;
 | |
|             animation-play-state: paused;
 | |
|         }
 | |
| 
 | |
|         .cloud::before,
 | |
|         .cloud::after {
 | |
|             content: '';
 | |
|             position: absolute;
 | |
|             background-color: inherit;
 | |
|             border-radius: 50%;
 | |
|         }
 | |
| 
 | |
|         .cloud1 {
 | |
|             width: 100px;
 | |
|             height: 30px;
 | |
|             top: 40px;
 | |
|             animation-duration: 30s;
 | |
|             animation-delay: 0s;
 | |
|         }
 | |
| 
 | |
|         .cloud2 {
 | |
|             width: 60px;
 | |
|             height: 20px;
 | |
|             top: 80px;
 | |
|             animation-duration: 20s;
 | |
|             animation-delay: -15s;
 | |
|         }
 | |
| 
 | |
|         .cloud3 {
 | |
|             width: 80px;
 | |
|             height: 25px;
 | |
|             top: 120px;
 | |
|             animation-duration: 25s;
 | |
|             animation-delay: -7s;
 | |
|         }
 | |
| 
 | |
|         .cloud1::before { width: 35px; height: 35px; top: -20px; left: 15px; }
 | |
|         .cloud1::after { width: 30px; height: 30px; top: -15px; left: 45px; }
 | |
|         .cloud2::before { width: 25px; height: 25px; top: -15px; left: 10px; }
 | |
|         .cloud2::after { width: 20px; height: 20px; top: -10px; left: 30px; }
 | |
|         .cloud3::before { width: 30px; height: 30px; top: -18px; left: 12px; }
 | |
|         .cloud3::after { width: 25px; height: 25px; top: -12px; left: 35px; }
 | |
| 
 | |
|         @keyframes moveCloud {
 | |
|             from {
 | |
|                 left: -150px;
 | |
|             }
 | |
|             to {
 | |
|                 left: 800px;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #banana {
 | |
|             position: absolute;
 | |
|             width: 30px;
 | |
|             height: 30px;
 | |
|             bottom: 0;
 | |
|             left: 50px;
 | |
|             transform: rotate(-45deg);
 | |
|             transition: transform 0.2s;
 | |
|             display: flex;
 | |
|             align-items: center;
 | |
|             justify-content: center;
 | |
|             font-size: 24px;
 | |
|             animation: run 0.4s infinite;
 | |
|             animation-play-state: paused;
 | |
|         }
 | |
| 
 | |
|         @keyframes run {
 | |
|             0%, 100% {
 | |
|                 transform: rotate(-45deg) translateY(0);
 | |
|             }
 | |
|             50% {
 | |
|                 transform: rotate(-45deg) translateY(-3px);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         .obstacle {
 | |
|             position: absolute;
 | |
|             width: 20px;
 | |
|             height: 40px;
 | |
|             bottom: 0;
 | |
|             background-color: var(--obstacle-color);
 | |
|             border-radius: 4px;
 | |
|         }
 | |
| 
 | |
|         #ground {
 | |
|             position: absolute;
 | |
|             bottom: 0;
 | |
|             width: 100%;
 | |
|             height: 2px;
 | |
|             background-color: var(--ground-color);
 | |
|         }
 | |
| 
 | |
|         #score {
 | |
|             position: absolute;
 | |
|             top: 20px;
 | |
|             right: 20px;
 | |
|             font-size: 20px;
 | |
|         }
 | |
| 
 | |
|         #highscore {
 | |
|             position: absolute;
 | |
|             top: 50px;
 | |
|             right: 20px;
 | |
|             font-size: 16px;
 | |
|         }
 | |
| 
 | |
|         #theme-toggle {
 | |
|             position: absolute;
 | |
|             top: 20px;
 | |
|             left: 20px;
 | |
|             font-size: 24px;
 | |
|             background: none;
 | |
|             border: none;
 | |
|             cursor: pointer;
 | |
|             padding: 5px;
 | |
|         }
 | |
| 
 | |
|         .game-over {
 | |
|             position: absolute;
 | |
|             top: 50%;
 | |
|             left: 50%;
 | |
|             transform: translate(-50%, -50%);
 | |
|             font-size: 24px;
 | |
|             display: none;
 | |
|         }
 | |
| 
 | |
|         .start-screen {
 | |
|             position: absolute;
 | |
|             top: 50%;
 | |
|             left: 50%;
 | |
|             transform: translate(-50%, -50%);
 | |
|             font-size: 24px;
 | |
|             text-align: center;
 | |
|             background-color: rgba(0, 0, 0, 0.7);
 | |
|             color: white;
 | |
|             padding: 20px;
 | |
|             border-radius: 10px;
 | |
|             z-index: 10;
 | |
|         }
 | |
| 
 | |
|         .game-instructions {
 | |
|             max-width: 800px;
 | |
|             margin: 20px auto;
 | |
|             padding: 20px;
 | |
|             background-color: var(--bg-color);
 | |
|             border: 2px solid var(--text-color);
 | |
|             border-radius: 10px;
 | |
|             transition: background-color 0.3s, color 0.3s, border-color 0.3s;
 | |
|         }
 | |
| 
 | |
|         .game-instructions h2 {
 | |
|             color: var(--text-color);
 | |
|             margin-top: 0;
 | |
|         }
 | |
| 
 | |
|         .game-instructions ul {
 | |
|             list-style-type: none;
 | |
|             padding: 0;
 | |
|         }
 | |
| 
 | |
|         .game-instructions li {
 | |
|             margin: 10px 0;
 | |
|             padding-left: 25px;
 | |
|             position: relative;
 | |
|         }
 | |
| 
 | |
|         .game-instructions li::before {
 | |
|             content: '🎮';
 | |
|             position: absolute;
 | |
|             left: 0;
 | |
|             top: 50%;
 | |
|             transform: translateY(-50%);
 | |
|         }
 | |
| 
 | |
|         .keyboard-key {
 | |
|             display: inline-block;
 | |
|             padding: 3px 8px;
 | |
|             background-color: var(--text-color);
 | |
|             color: var(--bg-color);
 | |
|             border-radius: 4px;
 | |
|             font-family: monospace;
 | |
|             margin: 0 3px;
 | |
|         }
 | |
| 
 | |
|         footer {
 | |
|             margin-top: 2rem;
 | |
|             padding: 1rem 0;
 | |
|             color: var(--text-color);
 | |
|             font-size: 0.9rem;
 | |
|             text-align: center;
 | |
|             border-top: 1px solid #ddd;
 | |
|             width: 100%;
 | |
|         }
 | |
| 
 | |
|         footer a {
 | |
|             color: var(--accent-color, #7F006E);
 | |
|             text-decoration: none;
 | |
|             transition: color 0.3s;
 | |
|         }
 | |
| 
 | |
|         footer a:hover {
 | |
|             color: var(--accent-color, #FF7FED);
 | |
|             text-decoration: underline;
 | |
|         }
 | |
|         
 | |
|         .heart {
 | |
|             color: #e74c3c;
 | |
|             animation: heartbeat 1.5s infinite;
 | |
|         }
 | |
|         
 | |
|         @keyframes heartbeat {
 | |
|             0% { transform: scale(1); }
 | |
|             50% { transform: scale(1.2); }
 | |
|             100% { transform: scale(1); }
 | |
|         }
 | |
|     </style>
 | |
| </head>
 | |
| <body>
 | |
|     <h1>Banana Runner 🍌</h1>
 | |
|     <div id="game-container">
 | |
|         <div class="mountains-container">
 | |
|             <div class="mountain-set-1">
 | |
|                 <div class="mountain mountain1"></div>
 | |
|                 <div class="mountain mountain2"></div>
 | |
|                 <div class="mountain mountain3"></div>
 | |
|                 <div class="mountain mountain4"></div>
 | |
|             </div>
 | |
|             <div class="mountain-set-2">
 | |
|                 <div class="mountain mountain1"></div>
 | |
|                 <div class="mountain mountain2"></div>
 | |
|                 <div class="mountain mountain3"></div>
 | |
|                 <div class="mountain mountain4"></div>
 | |
|             </div>
 | |
|         </div>
 | |
|         <div class="cloud cloud1"></div>
 | |
|         <div class="cloud cloud2"></div>
 | |
|         <div class="cloud cloud3"></div>
 | |
|         <div id="score">0</div>
 | |
|         <div id="highscore">Highscore: 0</div>
 | |
|         <button id="theme-toggle">🌞</button>
 | |
|         <div id="ground"></div>
 | |
|         <div id="banana">🍌</div>
 | |
|         <div class="game-over">Game Over! Drücke Leertaste zum Neustarten</div>
 | |
|         <div class="start-screen">Drücke Leertaste zum Starten</div>
 | |
|     </div>
 | |
| 
 | |
|     <div class="game-instructions">
 | |
|         <h2>🎮 Spielanleitung</h2>
 | |
|         <ul>
 | |
|             <li>Drücke <span class="keyboard-key">Leertaste</span> oder tippe auf den Bildschirm um das Spiel zu starten</li>
 | |
|             <li>Springe mit der <span class="keyboard-key">Leertaste</span> oder durch Tippen über die Hindernisse</li>
 | |
|             <li>Sammle Punkte indem du möglichst lange überlebst</li>
 | |
|             <li>Das Spiel wird mit der Zeit schneller</li>
 | |
|             <li>Wechsle mit <span class="keyboard-key">🌞/🌚</span> zwischen Hell- und Dunkel-Modus</li>
 | |
|             <li>Dein Highscore wird automatisch gespeichert</li>
 | |
|             <li>Nach "Game Over" drücke <span class="keyboard-key">Leertaste</span> oder tippe zum Neustart</li>
 | |
|             <li>Funktioniert auf allen Geräten - PC, Tablet und Smartphone</li>
 | |
|         </ul>
 | |
|     </div>
 | |
| 
 | |
|     <script>
 | |
|         const banana = document.getElementById('banana');
 | |
|         const gameContainer = document.getElementById('game-container');
 | |
|         const scoreElement = document.getElementById('score');
 | |
|         const highscoreElement = document.getElementById('highscore');
 | |
|         const themeToggle = document.getElementById('theme-toggle');
 | |
|         const gameOverElement = document.querySelector('.game-over');
 | |
|         const startScreen = document.querySelector('.start-screen');
 | |
|         const mountainsContainer = document.querySelector('.mountains-container');
 | |
|         const clouds = document.querySelectorAll('.cloud');
 | |
| 
 | |
|         let isJumping = false;
 | |
|         let score = 0;
 | |
|         let gameSpeed = 5;
 | |
|         let isGameOver = false;
 | |
|         let gameStarted = false;
 | |
|         let highscore = localStorage.getItem('bananaRunHighscore') || 0;
 | |
|         highscoreElement.textContent = `Highscore: ${highscore}`;
 | |
| 
 | |
|         function startGame() {
 | |
|             if (!gameStarted) {
 | |
|                 gameStarted = true;
 | |
|                 startScreen.style.display = 'none';
 | |
|                 // Starte die Animationen
 | |
|                 mountainsContainer.style.animationPlayState = 'running';
 | |
|                 clouds.forEach(cloud => cloud.style.animationPlayState = 'running');
 | |
|                 banana.style.animationPlayState = 'running';
 | |
|                 // Setze Startgeschwindigkeit
 | |
|                 gameSpeed = 5;
 | |
|                 // Starte das Spawnen von Hindernissen
 | |
|                 startObstacleSpawning();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         function startObstacleSpawning() {
 | |
|             setInterval(() => {
 | |
|                 if (!isGameOver && Math.random() < 0.03) {
 | |
|                     createObstacle();
 | |
|                 }
 | |
|             }, 100);
 | |
|         }
 | |
| 
 | |
|         // Theme handling
 | |
|         function setTheme(isDark) {
 | |
|             document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
 | |
|             themeToggle.textContent = isDark ? '🌞' : '🌚';
 | |
|             localStorage.setItem('bananaRunTheme', isDark ? 'dark' : 'light');
 | |
|         }
 | |
| 
 | |
|         // Check system preference and stored preference
 | |
|         const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
 | |
|         const storedTheme = localStorage.getItem('bananaRunTheme');
 | |
|         if (storedTheme) {
 | |
|             setTheme(storedTheme === 'dark');
 | |
|         } else {
 | |
|             setTheme(prefersDark);
 | |
|         }
 | |
| 
 | |
|         themeToggle.addEventListener('click', () => {
 | |
|             const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
 | |
|             setTheme(!isDark);
 | |
|         });
 | |
| 
 | |
|         function jump() {
 | |
|             if (!isJumping && !isGameOver) {
 | |
|                 isJumping = true;
 | |
|                 let position = 0;
 | |
|                 let jumpHeight = 150;
 | |
|                 let jumpCount = 0;
 | |
|                 
 | |
|                 // Pause die Laufanimation während des Sprungs
 | |
|                 banana.style.animationPlayState = 'paused';
 | |
|                 
 | |
|                 const jumpInterval = setInterval(() => {
 | |
|                     if (jumpCount < 15) {
 | |
|                         position += jumpHeight / 15;
 | |
|                     } else if (jumpCount < 30) {
 | |
|                         position -= jumpHeight / 15;
 | |
|                     }
 | |
|                     
 | |
|                     banana.style.bottom = position + 'px';
 | |
|                     banana.style.transform = `rotate(${-45 + (position/2)}deg)`;
 | |
|                     
 | |
|                     jumpCount++;
 | |
|                     
 | |
|                     if (jumpCount >= 30) {
 | |
|                         clearInterval(jumpInterval);
 | |
|                         isJumping = false;
 | |
|                         banana.style.bottom = '0px';
 | |
|                         banana.style.transform = 'rotate(-45deg)';
 | |
|                         // Starte die Laufanimation wieder
 | |
|                         banana.style.animationPlayState = 'running';
 | |
|                     }
 | |
|                 }, 20);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         function createObstacle() {
 | |
|             if (!isGameOver) {
 | |
|                 const obstacle = document.createElement('div');
 | |
|                 obstacle.classList.add('obstacle');
 | |
|                 
 | |
|                 // Zufällige Höhe zwischen 30 und 60 Pixeln
 | |
|                 const height = Math.floor(Math.random() * 31) + 30;
 | |
|                 // Zufällige Breite zwischen 15 und 25 Pixeln
 | |
|                 const width = Math.floor(Math.random() * 11) + 15;
 | |
|                 
 | |
|                 obstacle.style.height = `${height}px`;
 | |
|                 obstacle.style.width = `${width}px`;
 | |
|                 
 | |
|                 gameContainer.appendChild(obstacle);
 | |
|                 
 | |
|                 let position = 800;
 | |
|                 
 | |
|                 const moveObstacle = setInterval(() => {
 | |
|                     if (position < -20) {
 | |
|                         clearInterval(moveObstacle);
 | |
|                         gameContainer.removeChild(obstacle);
 | |
|                     } else if (isGameOver) {
 | |
|                         clearInterval(moveObstacle);
 | |
|                     } else {
 | |
|                         position -= gameSpeed;
 | |
|                         obstacle.style.left = position + 'px';
 | |
|                         
 | |
|                         // Verbesserte Kollisionserkennung
 | |
|                         const bananaRect = banana.getBoundingClientRect();
 | |
|                         const obstacleRect = obstacle.getBoundingClientRect();
 | |
|                         
 | |
|                         // Kollisionstoleranz hinzufügen
 | |
|                         const collisionTolerance = 10;
 | |
|                         
 | |
|                         if (
 | |
|                             bananaRect.right - collisionTolerance > obstacleRect.left &&
 | |
|                             bananaRect.left + collisionTolerance < obstacleRect.right &&
 | |
|                             bananaRect.bottom - collisionTolerance > obstacleRect.top
 | |
|                         ) {
 | |
|                             gameOver();
 | |
|                         }
 | |
|                     }
 | |
|                 }, 20);
 | |
|                 
 | |
|                 // Increase score
 | |
|                 score++;
 | |
|                 scoreElement.textContent = score;
 | |
|                 
 | |
|                 // Increase game speed more significantly
 | |
|                 if (score % 50 === 0) {
 | |
|                     gameSpeed += 1;
 | |
|                     // Passe die Berge- und Wolkengeschwindigkeit an
 | |
|                     mountainsContainer.style.animationDuration = `${20 - (gameSpeed - 5)}s`;
 | |
|                     clouds.forEach(cloud => {
 | |
|                         const baseSpeed = parseInt(cloud.style.animationDuration) || 25;
 | |
|                         cloud.style.animationDuration = `${baseSpeed - (gameSpeed - 5)}s`;
 | |
|                     });
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         function resetGame() {
 | |
|             isGameOver = false;
 | |
|             score = 0;
 | |
|             gameSpeed = 5;
 | |
|             scoreElement.textContent = '0';
 | |
|             gameOverElement.style.display = 'none';
 | |
|             
 | |
|             // Remove all obstacles
 | |
|             const obstacles = document.querySelectorAll('.obstacle');
 | |
|             obstacles.forEach(obstacle => gameContainer.removeChild(obstacle));
 | |
| 
 | |
|             // Reset animation speeds
 | |
|             mountainsContainer.style.animationDuration = '20s';
 | |
|             clouds.forEach(cloud => {
 | |
|                 if (cloud.classList.contains('cloud1')) cloud.style.animationDuration = '30s';
 | |
|                 if (cloud.classList.contains('cloud2')) cloud.style.animationDuration = '20s';
 | |
|                 if (cloud.classList.contains('cloud3')) cloud.style.animationDuration = '25s';
 | |
|             });
 | |
| 
 | |
|             // Starte die Animationen wieder
 | |
|             mountainsContainer.style.animationPlayState = 'running';
 | |
|             clouds.forEach(cloud => cloud.style.animationPlayState = 'running');
 | |
|             banana.style.animationPlayState = 'running';
 | |
|         }
 | |
| 
 | |
|         function gameOver() {
 | |
|             isGameOver = true;
 | |
|             gameOverElement.style.display = 'block';
 | |
|             
 | |
|             // Stoppe die Animationen
 | |
|             mountainsContainer.style.animationPlayState = 'paused';
 | |
|             clouds.forEach(cloud => cloud.style.animationPlayState = 'paused');
 | |
|             banana.style.animationPlayState = 'paused';
 | |
|             
 | |
|             if (score > highscore) {
 | |
|                 highscore = score;
 | |
|                 localStorage.setItem('bananaRunHighscore', highscore);
 | |
|                 highscoreElement.textContent = `Highscore: ${highscore}`;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Controls
 | |
|         document.addEventListener('keydown', (event) => {
 | |
|             if (event.code === 'Space') {
 | |
|                 event.preventDefault();
 | |
|                 if (!gameStarted) {
 | |
|                     startGame();
 | |
|                 } else if (isGameOver) {
 | |
|                     resetGame();
 | |
|                 } else {
 | |
|                     jump();
 | |
|                 }
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         // Touch Controls
 | |
|         document.addEventListener('touchstart', (event) => {
 | |
|             event.preventDefault(); // Verhindere Zoom und Scroll auf Mobilgeräten
 | |
|             
 | |
|             // Prüfe, ob der Touch im Spielbereich ist
 | |
|             const touch = event.touches[0];
 | |
|             const gameRect = gameContainer.getBoundingClientRect();
 | |
|             
 | |
|             if (touch.clientX >= gameRect.left && 
 | |
|                 touch.clientX <= gameRect.right && 
 | |
|                 touch.clientY >= gameRect.top && 
 | |
|                 touch.clientY <= gameRect.bottom) {
 | |
|                 
 | |
|                 if (!gameStarted) {
 | |
|                     startGame();
 | |
|                 } else if (isGameOver) {
 | |
|                     resetGame();
 | |
|                 } else {
 | |
|                     jump();
 | |
|                 }
 | |
|             }
 | |
|         }, { passive: false });
 | |
| 
 | |
|         // Theme Toggle auch per Touch
 | |
|         themeToggle.addEventListener('touchend', (event) => {
 | |
|             event.preventDefault();
 | |
|             const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
 | |
|             setTheme(!isDark);
 | |
|         });
 | |
| 
 | |
|         // Verhindern von ungewolltem Zoomen auf Mobilgeräten
 | |
|         document.addEventListener('touchmove', (event) => {
 | |
|             if (event.touches.length > 1) {
 | |
|                 event.preventDefault();
 | |
|             }
 | |
|         }, { passive: false });
 | |
|     </script>
 | |
|     
 | |
|     <footer>
 | |
|         <p>
 | |
|             <a href="https://tools.ponywave.de/">Zurück zur Startseite</a> | 
 | |
|             © <span id="current-year"></span> Akamaru | Made with <span class="heart">❤️</span> by Claude
 | |
|         </p>
 | |
|     </footer>
 | |
| 
 | |
|     <script>
 | |
|         document.getElementById('current-year').textContent = new Date().getFullYear();
 | |
|     </script>
 | |
| </body>
 | |
| </html>  |