1
0
2025-03-06 16:23:51 +01:00

645 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</title>
<!-- Open Graph Tags -->
<meta property="og:title" content="Banana Runner - Das lustige Endlos-Runner Spiel">
<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-runner">
<meta property="og:type" content="website">
<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 {
position: fixed;
bottom: 0;
left: 0;
margin-top: 0;
padding: 15px;
text-align: center;
background-color: var(--bg-color);
color: var(--text-color);
border-top: 2px solid var(--text-color);
transition: background-color 0.3s, color 0.3s;
width: 100%;
box-sizing: border-box;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
z-index: 100;
}
footer a {
color: var(--text-color);
text-decoration: none;
border-bottom: 1px dotted var(--text-color);
}
footer a:hover {
border-bottom-style: solid;
}
.footer-content {
max-width: 800px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
@media (max-width: 600px) {
.footer-content {
flex-direction: column;
text-align: center;
}
}
</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>
<footer>
<div class="footer-content">
<div>Created by Akamaru</div>
<div>Powered by Claude AI 🤖</div>
<div><a href="https://tools.ponywave.de">Mehr Tools & Spiele</a> 🛠️</div>
</div>
</footer>
<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>
</body>
</html>