diff --git a/index.html b/index.html new file mode 100644 index 0000000000000000000000000000000000000000..a87ca0a77a52ca7e78f422d60070549cc9bf0caf --- /dev/null +++ b/index.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html lang="de"> +<head> + <!-- Deklariere den Typ des Dokuments und die verwendete Zeichenkodierung --> + <meta charset="UTF-8"> + <!-- Legt den Standardmodus für die Darstellung der Webseite im Internet Explorer fest --> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <!-- Legt die Breite des Viewports fest, um die Website auf verschiedenen Geräten korrekt darzustellen --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <!-- Fügt ein FavIcon zur Webseite hinzu --> + <link rel="icon" type="image/png" href="images/favicon.ico"> + <!-- Titel der Webseite --> + <title>Flappy Bird Game</title> + <!-- Verknüpfung mit dem externen Stylesheet --> + <link rel="stylesheet" href="style.css"> + <!-- Einbinden des externen JavaScript-Codes, der verzögert geladen wird --> + <script src="script.js" defer></script> + +</head> +<body> + <!-- Obere Leiste --> + <div class="topBar"> + <div class="gameTitle">Flappy Birds</div> + <div class="menuOptions"> + <div class="menuItem">Game</div> + <div class="menuItem" id="scoresButton">Scores</div> + </div> + </div> + + <!-- Hintergrundbild des Spiels --> + <div class="background" id="background"></div> + + + <!-- Bild des Vogels --> + <img src="images/Bird.png" alt="bird-img" class="bird" id="bird-1"> + <!-- Bild des Mascots --> + <div class="mascot" id="mascot"> + <img src="images/Tiger-Laecheln.png" alt="Tiger" id="Tiger-Laecheln" class="mascot"> + </div> + + <div class="GameOverMessage"> + <p id="gameOverText"></p> + </div> + + <!-- Anzeige des aktuellen Punktestands --> + <div class="score"> + <span class="score_title"></span> + <span class="score_val"></span> + </div> + <!-- Schwierigkeitsgrad-Auswahl im difficultyContainer --> + <div id="difficultyContainer" class="difficultyContainer"> + <label for="difficulty">Wähle den Schwierigkeitsgrad:</label> + <select id="difficulty"> + <option value="langsam">Langsam</option> + <option value="normal">Normal</option> + <option value="schnell">Schnell</option> + </select> + </div> + <div class="start-container"> + <button class="start-button" id="start-button">Start</button> + <!-- Eingabefeld für den Spielernamen --> + <input type="text" id="playerNameInput" placeholder="Enter your name" class="inputField"> + </div> + +</body> +</html> diff --git a/script.js b/script.js new file mode 100644 index 0000000000000000000000000000000000000000..252c112cbc7cd31a13107896210d066ad7c2b11f --- /dev/null +++ b/script.js @@ -0,0 +1,229 @@ +// Wähle das Vogel-Element und das Bild aus +let bird = document.querySelector('.bird'); +let img = document.getElementById('bird-1'); + +// Hole die Eigenschaften des Vogel-Elements und des Hintergrund-Elements +let bird_props = bird.getBoundingClientRect(); +let background = document.querySelector('.background').getBoundingClientRect(); + +// Wähle die Elemente für den Punktestand, Nachricht und Titel aus +let score_val = document.querySelector('.score_val'); +let message = document.querySelector('.GameOverMessage'); +let score_title = document.querySelector('.score_title'); + +// Setze den Spielzustand auf "Start" und verstecke das Vogelbild +let game_state = 'Start'; +img.style.display = 'none'; +message.classList.add('messageStyle'); + +// Führe den folgenden Code aus, sobald das DOM geladen ist +document.addEventListener('DOMContentLoaded', () => { + const mascot = document.getElementById('mascot'); + const mascotImage = document.getElementById('Tiger-Laecheln'); + + const messages = [ + "Willkommen zum Flappy Birds Spiel! Drücke Enter, um zu starten.", + "Weiche den Hindernissen aus, um Punkte zu sammeln.", + "Viel Glück und hab Spaß!" + ]; + + const images = [ + "images/Tiger-Laecheln.png", + "images/Mund-Geschlossen.png", + "images/Mund-Offen.png" + ]; + + let messageIndex = 0; + let imageIndex = 0; + + // Funktion, um eine Nachricht auszusprechen + function speakMessage(message) { + const utterance = new SpeechSynthesisUtterance(message); + utterance.lang = 'de-DE'; + window.speechSynthesis.speak(utterance); + } + + // Funktion, um die Nachricht zu aktualisieren + function updateMessage() { + const messageText = messages[messageIndex]; + speakMessage(messageText); + messageIndex = (messageIndex + 1) % messages.length; + } + + // Funktion, um das Bild zu aktualisieren + function updateImage() { + mascotImage.src = images[imageIndex]; + imageIndex = (imageIndex + 1) % images.length; + } + + // Zeige die nächste Nachricht alle 3 Sekunden an + const messageInterval = setInterval(updateMessage, 3000); + // Wechsle das Bild alle 0.5 Sekunden, um die Mundbewegung zu simulieren + const imageInterval = setInterval(updateImage, 500); + const playerNameInput = document.getElementById('playerNameInput'); + const scoresButton = document.getElementById('scoresButton'); + const scoreBoard = document.getElementById('scoreBoard'); + const scoreList = document.getElementById('scoreList'); + let scores = JSON.parse(localStorage.getItem('scores')) || []; + + // Event-Listener für den Mausklick auf den Start-Button + + const startButton = document.getElementById('start-button'); + startButton.addEventListener('click', () => { + if (game_state !== 'Play') { + // Entferne alle Rohre, zeige das Vogelbild, setze die Startposition des Vogels und starte das Spiel + document.querySelectorAll('.pipe_sprite').forEach((e) => { + e.remove(); + }); + // Stoppe die Nachrichten- und Bildaktualisierungsintervalle + clearInterval(messageInterval); + clearInterval(imageInterval); + window.speechSynthesis.cancel(); + img.style.display = 'block'; + bird.style.top = '40vh'; + game_state = 'Play'; + message.innerHTML = ''; + score_title.innerHTML = 'Score : '; + score_val.innerHTML = '0'; + message.classList.remove('messageStyle'); + startButton.style.display = 'none'; + mascot.style.display ='none'; + difficultyContainer.style.display ='none'; + play(); // Starte das Spiel + } + } +)}); + + +// Hauptspiellogik +function play() { + // Funktion für die Bewegung des Vogels + function move() { + if (game_state != 'Play') return; + + // Überprüfe Kollisionen mit den Rohren und Spielende + let pipe_sprite = document.querySelectorAll('.pipe_sprite'); + pipe_sprite.forEach((element) => { + let pipe_sprite_props = element.getBoundingClientRect(); + bird_props = bird.getBoundingClientRect(); + + // Kollisionserkennung + if (pipe_sprite_props.right <= 0) { + element.remove(); + } else { + if (bird_props.left < pipe_sprite_props.left + pipe_sprite_props.width && + bird_props.left + bird_props.width > pipe_sprite_props.left && + bird_props.top < pipe_sprite_props.top + pipe_sprite_props.height && + bird_props.top + bird_props.height > pipe_sprite_props.top) { + game_state = 'End'; + document.querySelector('.GameOverMessage').innerHTML = 'Game Over'.fontcolor('red'); + message.classList.add('GameOverMessageStyle'); + img.style.display = 'none'; + return; + } else { + if (pipe_sprite_props.right < bird_props.left && + pipe_sprite_props.right + move_speed >= bird_props.left && + element.increase_score == '1') { + score_val.innerHTML = +score_val.innerHTML + 1; + } + element.style.left = pipe_sprite_props.left - move_speed + 'px'; + } + } + }); + requestAnimationFrame(move); + } + requestAnimationFrame(move); + + // Funktion für die Anwendung der Gravitation auf den Vogel + let bird_dy = 0; + function apply_gravity() { + if (game_state != 'Play') return; + bird_dy += gravity; + + // Steuere den Vogelsprung durch Tastendruck + document.addEventListener('keydown', (e) => { + if (e.key == 'ArrowUp' || e.key == ' ') { + img.src = 'images/Bird-2.png'; + bird_dy = -10.6; + } + }); + + document.addEventListener('keyup', (e) => { + if (e.key == 'ArrowUp' || e.key == ' ') { + img.src = 'images/Bird.png'; + } + }); + + // Überprüfe, ob der Vogel den Bildschirmrand berührt und das Spiel beendet + if (bird_props.top <= 0 || bird_props.bottom >= background.bottom) { + game_state = 'End'; + message.style.left = '28vw'; + window.location.reload(); + message.classList.remove('GameOverMessageStyle'); + return; + } + // Aktualisiere die Vogelposition basierend auf der Gravitation + bird.style.top = `${parseFloat(bird.style.top) + bird_dy}px`; + bird_props = bird.getBoundingClientRect(); + requestAnimationFrame(apply_gravity); + } + requestAnimationFrame(apply_gravity); + + // Funktion zum Erstellen und Bewegen der Rohre + let pipe_separation = 0; + let pipe_gap = 35; + let difficulty = 'normal'; + + function create_pipe() { + // Überprüfe, ob das Spiel läuft + if (game_state != 'Play') return; + + // Erzeuge neue Rohre, wenn der Abstand groß genug ist + if (pipe_separation > 115) { + pipe_separation = 0; + // Zufällige Position für das obere Rohr berechnen + let pipe_posi = Math.floor(Math.random() * 43) + 8; + //Erzeuge das obere Rohr + let pipe_sprite_inv = document.createElement('div'); + pipe_sprite_inv.className = 'pipe_sprite'; + pipe_sprite_inv.style.top = pipe_posi - 70 + 'vh';//Position des oberen Rohrs + pipe_sprite_inv.style.left = '100vw';// Beginne außerhalb des sichtabaren Bereichs + + //Füge das obere Rohr dem Dokumet hinzu + document.body.appendChild(pipe_sprite_inv); + + //Erzeuge das untere Rohr + let pipe_sprite = document.createElement('div'); + pipe_sprite.className = 'pipe_sprite'; + pipe_sprite.style.top = pipe_posi + pipe_gap + 'vh'; // Position des unteren Rohrs + pipe_sprite.style.left = '100vw'; // Beginne außerhalb des Sichtbaren Bereichs + pipe_sprite.increase_score = '1'; // Markiere das Rohr zur Punktzählung + + // Füge das untere Rohr dem Dokument hinzu + document.body.appendChild(pipe_sprite); + } + // Inkrementiere den Abstandzähler + pipe_separation++; + + //Wiederhole die Funktion, um kontinuierlich neue Rohre zu erstellen + requestAnimationFrame(create_pipe); + } + + //Starte die Rohrerstellung basierend auf dem Schwierigkeitsgrad + if (difficulty === 'langsam' || difficulty === 'normal' || difficulty === 'schnell') { + requestAnimationFrame(create_pipe); + //Passe die Bewegungsgeschwindigkeit basierend auf dem Schwierigkeitsgrad an + if (difficulty === 'langsam') { + move_speed = 2; + gravity = 0.2; + } + else if (difficulty === 'normal') { + move_speed = 3; + gravity = 0.3; + } + else if (difficulty === 'schnell') { + move_speed = 5; + gravity = 0.6; + } + } +} diff --git a/style.css b/style.css new file mode 100644 index 0000000000000000000000000000000000000000..cdc496f87b1280701e49fbcee4a5241ebbf14b57 --- /dev/null +++ b/style.css @@ -0,0 +1,205 @@ +/* Setze den Standard-Margin und Padding auf 0, nutze das border-box Box-Modell, und wähle eine Standardschriftart */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: Arial, Helvetica, sans-serif; +} +/* Stil für das Eingabefeld */ +.inputField { + position: fixed; + top: 20vh; + left: 50%; + transform: translateX(-50%); + padding: 10px; + font-size: 16px; + border-radius: 5px; + border: 1px solid #ccc; +} + +.start-container { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; /* Höhe des Containers auf die volle Höhe des Viewports setzen */ +} + +.start-button { + background-color: #3498db; + color: #fff; + padding: 10px 20px; + font-size: 16px; + border: none; + cursor: pointer; + border-radius: 5px; + z-index: 1000; + margin-top: 10px; +} + +.start-button:hover { + background-color: #2980b9; +} +/* Stil für die obere Leiste */ +.topBar { + background-color: #02917b; /* Hintergrundfarbe */ + color: white; /* Textfarbe */ + padding: 10px; /* Innenabstand */ + display: flex; /* Flexbox-Layout verwenden */ + justify-content: space-between; /* Elemente gleichmäßig verteilen */ + align-items: center; /* Elemente zentrieren */ +} + +/* Stil für den Spieltitel */ +.gameTitle { + font-size: 24px; + font-weight: bold; + +} + +/* Stil für die Menüoptionen */ +.menuOptions { + display: flex; /* Flexbox-Layout verwenden */ +} + +.menuItem { + margin-left: 10px; /* Abstand zwischen den Menüoptionen */ + cursor: pointer; /* Zeiger-Cursor */ +} + +/* Stil für hover über Menüoptionen */ +.menuItem:hover { + text-decoration: underline; /* Unterstrich bei Hover */ +} + + + +/* Stil für den Hintergrund */ +.background { + height: 100vh; + width: 100vw; + background: url('images/background.png') no-repeat center center fixed; + background-size: cover; + position: fixed; + +} + +/* Stil für den Difficulty Container */ +.difficultyContainer { + position: fixed; + top:10; + left: 0; + padding: 10px; + background-color: rgba(255, 255, 255, 0.5); +} + + +/* Stil für den Vogel */ +.bird { + height: 70px; + width: 100px; + position: fixed; + top: 40vh; + left: 30vw; + z-index: 100; +} + +/* Stil für das Maskottchen */ +.mascot { + width: 450px; + height: 500px; + cursor: pointer; + position: fixed; + top: 40vh; + left: -5vw; + z-index: 100; + background-image: url('Tiger-Laecheln.png'); /* Standard-Hintergrundbild */ + background-repeat: no-repeat; + background-size: contain; +} + +.Mund-Offen { + background-image: url('Mund-Offen.png'); /* Hintergrundbild für offenen Mund */ +} + +.Mund-Geschlossen { + background-image: url('Mund-Geschlossen.png'); /* Hintergrundbild für geschlossenen Mund */ +} + +.mascot-text { + visibility: hidden; +} + + +/* Stil für die Rohre */ +.pipe_sprite { + position: fixed; + top: 40vh; + left: 100vw; + height: 70vh; + width: 6vw; + background: radial-gradient(rgb(96, 98, 2) 50%, rgb(138, 118, 1)); + border: 5px solid black; +} + +/* Stil für Nachrichten */ +.GameOverMessage { + position: absolute; + z-index: 10; + color: black; + top: 30%; + left: 50%; + font-size: 4em; + transform: translate(-50%, -50%); + text-align: center; +} + +/* Zusätzlicher Stil für Nachrichten im Spielstil */ +.GameOverMessageStyle { + background: rgb(156, 130, 3); + padding: 30px; + box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; + border-radius: 5%; +} + + + +/* Stil für den Punktestand */ +.score { + position: fixed; + z-index: 10; + height: 10vh; + font-size: 10vh; + font-weight: 100; + color: white; + -webkit-text-stroke-width: 2px; + -webkit-text-stroke-color: black; + top: 10; + left: 0; + margin: 10px; + font-family: Arial, Helvetica, sans-serif; +} + +/* Stil für den Punktestand-Wert */ +.score_val { + color: gold; + font-weight: bold; +} + +/* Media Query für kleinere Bildschirme */ +@media only screen and (max-width: 1080px) { + .message { + font-size: 50px; + top: 50%; + white-space: nowrap; + } + .score { + font-size: 8vh; + } + .bird { + width: 120px; + height: 90px; + } + .pipe_sprite { + width: 14vw; + } +}