-
Notifications
You must be signed in to change notification settings - Fork 0
/
script.js
373 lines (326 loc) · 11.1 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
// Declaration of global variables for game elements and state
let birdEl,
instructionTextEl,
gameDisplayEl,
groundEl,
skyEl,
currentScore,
highestScore;
let score = 0;
let highScore;
let birdLeft = 220;
let birdBottom = 100;
let isInvincible = false;
let gravity = 1;
let isGameOver = false;
let gap = 475;
let lives = 3;
let allowInitGame = true;
let obstacleTimers = []; // Array to store timer IDs
// Arrays containing CSS classes for obstacle elements
let classNamesTop = [
"topObstacleFork",
"topObstacleKnife",
"topObstaclePipe",
"topObstacleSalmon",
];
let classNamesBottom = [
"obstacleFork",
"obstacleKnife",
"obstaclePipe",
"obstacleCoffee",
"obstacleKhadija",
"obstacleSalmon",
"obstacleEskilCool",
"obstacleEskilBreak",
"obstacleSmoke",
];
// Event listener to initialize the game when the DOM is fully loaded
document.addEventListener("DOMContentLoaded", () => {
// Assign DOM elements to variables
birdEl = document.querySelector("#bird");
instructionTextEl = document.querySelector("#instructionText");
gameDisplayEl = document.querySelector("#gameDisplay");
groundEl = document.querySelector("#movingGround");
skyEl = document.querySelector("#movingSky");
currentScore = document.querySelector("#currentScore");
highestScore = document.querySelector("#highestScore");
// Initialize game elements and set up event listeners
initializeGameElements(
gameDisplayEl,
groundEl,
skyEl,
currentScore,
highestScore
);
setupEventListeners();
});
// Function to update the player's score
function updateScore() {
score++;
// Check if the current score surpasses the highest score
if (score > highScore) {
// Update local storage with the new highest score
localStorage.setItem(
"flappyBirdData",
JSON.stringify({ score, highestScore: score })
);
// Update the displayed highest score
setHighscore({
score: score,
});
highestScore.textContent = `Highest Score: ${score}`;
}
// Update the displayed current score
currentScore.textContent = `Current Score: ${score}`;
}
// Function to set and update the highest score in local storage
function setHighscore(highscore) {
// Use the same key "flappyBirdData" consistently
localStorage.setItem(
"flappyBirdData",
JSON.stringify({ score: highscore.score, highestScore: highscore.score })
);
}
// Function to retrieve the highest score from local storage
function getHighscore() {
// Use the same key "flappyBirdData" consistently
const storedData = JSON.parse(localStorage.getItem("flappyBirdData")) || {
score: 0,
highestScore: 0,
};
return storedData.highestScore;
}
// Function to initialize game elements and set initial scores
function initializeGameElements() {
// Retrieve the highest score from local storage
highScore = getHighscore();
// Initialize the displayed scores
currentScore.textContent = `Current Score: ${score}`;
highestScore.textContent = `Highest Score: ${highScore}`;
}
// Function to get a random class for the top obstacle
function getRandomTopObstacleClass(classNames) {
let randomIndexTop = Math.floor(Math.random() * classNamesTop.length);
return classNamesTop[randomIndexTop];
}
// Function to get a random class for the bottom obstacle
function getRandomBottomObstacleClass(classNames) {
let randomIndexBottom = Math.floor(Math.random() * classNamesBottom.length);
return classNamesBottom[randomIndexBottom];
}
function updateLivesDisplay() {
document.getElementById("lives").innerText = "LIVES: " + lives;
}
// Function to display the game over popup
function displayGameOverPopup() {
let popupEl = document.querySelector("#gameOverPopup");
popupEl.style.display = "block";
document.addEventListener("keydown", (e) => {
// console.log(e);
if (e.key === "Enter") {
restartGame();
}
});
}
// Define startGame function
function startGame() {
// Move the bird up if it's above the ground, else keep it at the ground level
if (birdBottom > 15) {
birdBottom -= gravity;
birdEl.style.bottom = birdBottom + "px";
birdEl.style.left = birdLeft + "px";
} else {
// Stop the bird from going below the ground level
birdBottom = 15;
birdEl.style.bottom = birdBottom + "px";
}
}
// Function to initiate the game and set up initial configurations
function initiateGame() {
birdBottom = 100;
birdEl.style.bottom = birdBottom + "px";
isGameOver = false;
// Start the game loop and obstacle generation
gameTimerId = setInterval(startGame, 20);
generateObstacle();
// Initialize and play sounds
let collisionSound = document.querySelector("#collisionSound");
let spacebarSound = document.querySelector("#spacebarSound");
let okeyLetsGo = document.querySelector("#okeyLetsGo");
collisionSound.pause(); // Pause the collision sound initially
spacebarSound.pause(); // Pause the spacebar sound initially
okeyLetsGo.play(); // Play the start game sound
}
// Function to handle the "S" key press and call initiateGame function
function handleKeyPress(e) {
if ((allowInitGame && e.key === "s") || e.key === "S") {
initiateGame(); // Call the initiateGame function when the "S" key is pressed
allowInitGame = false; // Disable further "S" key presses
instructionTextEl.style.opacity = 0;
okeyLetsGo.play();
}
}
// Function to change the avatar by pressing numbers 1 to 3
function changeBird(e) {
if (e.key === "1") {
bird.classList.remove("pikachu", "nyan");
bird.classList.add("bird");
birdSound.play();
}
}
function changeBirdPikachu(e) {
if (e.key === "2") {
bird.classList.remove("bird", "nyan");
bird.classList.add("pikachu");
pikachuSound.play();
}
}
function changeBirdNyan(e) {
if (e.key === "3") {
bird.classList.remove("bird", "pikachu");
bird.classList.add("nyan");
nyanSound.play();
}
}
// Function to execute a jump when the spacebar is pressed
function executeJump() {
// Increase the bird's bottom position to simulate a jump
if (birdBottom < 500) birdBottom += 50;
birdEl.style.bottom = birdBottom + "px";
// console.log(birdBottom);
}
// Function to handle user control (spacebar press for jump)
function handleUserControl(e) {
if (e.key === " ") {
executeJump();
spacebarSound.play();
}
}
// Function to decrease the count of remaining lives
function decreaseLiveCount() {
if (lives > 0) {
lives--;
updateLivesDisplay();
// Play the collision sound only if lives are greater than 0
collisionSound.play();
}
}
// Function to check if the player has remaining lives
function checkRemainingLives() {
if (lives <= 0) {
// If no lives left, show game over popup and end the game
displayGameOverPopup();
gameOver();
// Pause the collision sound when the game is over
collisionSound.pause();
}
}
// Function to generate new obstacles at intervals
function generateObstacle() {
let obstacleLeft = 1200;
// Generate a random height for the obstacle
let randomHeight = Math.random() * 150;
let obstacleBottom = randomHeight;
// Create HTML elements for the obstacle and its top counterpart
let obstacle = document.createElement("div");
let topObstacle = document.createElement("div");
// Get random obstacle classes for styling
let randomClassTop = getRandomTopObstacleClass(classNamesTop);
let randomClassBottom = getRandomBottomObstacleClass(classNamesBottom);
// Add obstacle classes if the game is not over
if (!isGameOver) {
obstacle.classList.add(randomClassBottom);
topObstacle.classList.add(randomClassTop);
}
// Append obstacles to the game display
gameDisplayEl.appendChild(obstacle);
gameDisplayEl.appendChild(topObstacle);
// Set initial positions for the obstacles
obstacle.style.left = obstacleLeft + "px";
topObstacle.style.left = obstacleLeft + "px";
obstacle.style.bottom = obstacleBottom + "px";
topObstacle.style.bottom = obstacleBottom + gap + "px";
// Set up a timer to move the obstacles
let timerId = setInterval(moveObstacle, 20);
// Push the timerId into the array for later cleanup
obstacleTimers.push(timerId);
// Function to move the obstacles
function moveObstacle() {
// Move the obstacles to the left
obstacleLeft -= 2;
obstacle.style.left = obstacleLeft + "px";
topObstacle.style.left = obstacleLeft + "px";
// Check for collision with the bird or reaching top/bottom
if (
(obstacleLeft > 200 &&
obstacleLeft < 280 &&
birdLeft === 220 &&
(birdBottom < obstacleBottom + 153 ||
birdBottom > obstacleBottom + gap - 200)) ||
birdBottom === 18
) {
// Handle collision events
if (!isInvincible) {
// console.log("collision", birdBottom);
decreaseLiveCount();
checkRemainingLives();
collisionSound.play();
// Make the bird temporarily invincible after a collision
isInvincible = true;
birdEl.classList.add("invincible");
// Remove invincibility after a delay
setTimeout(function () {
isInvincible = false;
birdEl.classList.remove("invincible");
}, 2000);
}
}
// Check if the obstacle is at the same position as the bird
if (obstacleLeft === 220) {
updateScore();
}
// Check if the obstacle has moved off the screen
if (obstacleLeft === -200) {
// Remove obstacles and clear the timer
clearInterval(timerId);
gameDisplayEl.removeChild(obstacle);
gameDisplayEl.removeChild(topObstacle);
}
}
// Schedule the next obstacle generation if the game is not over
if (!isGameOver) setTimeout(generateObstacle, 3000);
}
// Function to handle game over conditions
function gameOver() {
// Clear all obstacle timers
obstacleTimers.forEach((timerId) => {
clearInterval(timerId);
});
// Clear the game loop timer
clearInterval(gameTimerId);
// console.log("Game over");
isGameOver = true;
// Remove key event listener for user control
document.removeEventListener("keyup", handleUserControl);
// Update CSS classes for ground and sky to indicate the game over state
groundEl.classList.add("ground");
groundEl.classList.remove("ground-moving");
skyEl.classList.add("sky");
skyEl.classList.remove("sky-moving");
}
// Function to restart the game by reloading the page
function restartGame() {
location.reload();
allowInitGame = true;
}
// Function to set up event listeners for user input
function setupEventListeners() {
// Add event listener for key release
document.addEventListener("keyup", handleUserControl);
// Add event listener for key press
document.addEventListener("keydown", handleKeyPress);
document.addEventListener("keydown", changeBird);
document.addEventListener("keydown", changeBirdPikachu);
document.addEventListener("keydown", changeBirdNyan);
}