645 lines
22 KiB
HTML
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> |