Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
AroriaNetwork
GitHub Repository: AroriaNetwork/3kho-backup
Path: blob/main/projects/flappy-bird/js/main.js
1834 views
1
var debugmode = false;
2
3
var states = Object.freeze({
4
SplashScreen: 0,
5
GameScreen: 1,
6
ScoreScreen: 2
7
});
8
9
var currentstate;
10
11
var gravity = 0.25;
12
var velocity = 0;
13
var position = 180;
14
var rotation = 0;
15
var jump = -4.6;
16
var flyArea = $("#flyarea").height();
17
18
var score = 0;
19
var highscore = 0;
20
21
var pipeheight = 90;
22
var pipewidth = 52;
23
var pipes = new Array();
24
25
var replayclickable = false;
26
27
//sounds
28
var volume = 30;
29
var soundJump = new buzz.sound("assets/sounds/sfx_wing.ogg");
30
var soundScore = new buzz.sound("assets/sounds/sfx_point.ogg");
31
var soundHit = new buzz.sound("assets/sounds/sfx_hit.ogg");
32
var soundDie = new buzz.sound("assets/sounds/sfx_die.ogg");
33
var soundSwoosh = new buzz.sound("assets/sounds/sfx_swooshing.ogg");
34
buzz.all().setVolume(volume);
35
36
//loops
37
var loopGameloop;
38
var loopPipeloop;
39
40
$(document).ready(function() {
41
if(window.location.search == "?debug")
42
debugmode = true;
43
if(window.location.search == "?easy")
44
pipeheight = 200;
45
46
//get the highscore
47
var savedscore = getCookie("highscore");
48
if(savedscore != "")
49
highscore = parseInt(savedscore);
50
51
//start with the splash screen
52
showSplash();
53
});
54
55
function getCookie(cname)
56
{
57
var name = cname + "=";
58
var ca = document.cookie.split(';');
59
for(var i=0; i<ca.length; i++)
60
{
61
var c = ca[i].trim();
62
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
63
}
64
return "";
65
}
66
67
function setCookie(cname,cvalue,exdays)
68
{
69
var d = new Date();
70
d.setTime(d.getTime()+(exdays*24*60*60*1000));
71
var expires = "expires="+d.toGMTString();
72
document.cookie = cname + "=" + cvalue + "; " + expires;
73
}
74
75
function showSplash()
76
{
77
currentstate = states.SplashScreen;
78
79
//set the defaults (again)
80
velocity = 0;
81
position = 180;
82
rotation = 0;
83
score = 0;
84
85
//update the player in preparation for the next game
86
$("#player").css({ y: 0, x: 0 });
87
updatePlayer($("#player"));
88
89
soundSwoosh.stop();
90
soundSwoosh.play();
91
92
//clear out all the pipes if there are any
93
$(".pipe").remove();
94
pipes = new Array();
95
96
//make everything animated again
97
$(".animated").css('animation-play-state', 'running');
98
$(".animated").css('-webkit-animation-play-state', 'running');
99
100
//fade in the splash
101
$("#splash").transition({ opacity: 1 }, 2000, 'ease');
102
}
103
104
function startGame()
105
{
106
currentstate = states.GameScreen;
107
108
//fade out the splash
109
$("#splash").stop();
110
$("#splash").transition({ opacity: 0 }, 500, 'ease');
111
112
//update the big score
113
setBigScore();
114
115
//debug mode?
116
if(debugmode)
117
{
118
//show the bounding boxes
119
$(".boundingbox").show();
120
}
121
122
//start up our loops
123
var updaterate = 1000.0 / 60.0 ; //60 times a second
124
loopGameloop = setInterval(gameloop, updaterate);
125
loopPipeloop = setInterval(updatePipes, 1400);
126
127
//jump from the start!
128
playerJump();
129
}
130
131
function updatePlayer(player)
132
{
133
//rotation
134
rotation = Math.min((velocity / 10) * 90, 90);
135
136
//apply rotation and position
137
$(player).css({ rotate: rotation, top: position });
138
}
139
140
function gameloop() {
141
var player = $("#player");
142
143
//update the player speed/position
144
velocity += gravity;
145
position += velocity;
146
147
//update the player
148
updatePlayer(player);
149
150
//create the bounding box
151
var box = document.getElementById('player').getBoundingClientRect();
152
var origwidth = 34.0;
153
var origheight = 24.0;
154
155
var boxwidth = origwidth - (Math.sin(Math.abs(rotation) / 90) * 8);
156
var boxheight = (origheight + box.height) / 2;
157
var boxleft = ((box.width - boxwidth) / 2) + box.left;
158
var boxtop = ((box.height - boxheight) / 2) + box.top;
159
var boxright = boxleft + boxwidth;
160
var boxbottom = boxtop + boxheight;
161
162
//if we're in debug mode, draw the bounding box
163
if(debugmode)
164
{
165
var boundingbox = $("#playerbox");
166
boundingbox.css('left', boxleft);
167
boundingbox.css('top', boxtop);
168
boundingbox.css('height', boxheight);
169
boundingbox.css('width', boxwidth);
170
}
171
172
//did we hit the ground?
173
if(box.bottom >= $("#land").offset().top)
174
{
175
playerDead();
176
return;
177
}
178
179
//have they tried to escape through the ceiling? :o
180
var ceiling = $("#ceiling");
181
if(boxtop <= (ceiling.offset().top + ceiling.height()))
182
position = 0;
183
184
//we can't go any further without a pipe
185
if(pipes[0] == null)
186
return;
187
188
//determine the bounding box of the next pipes inner area
189
var nextpipe = pipes[0];
190
var nextpipeupper = nextpipe.children(".pipe_upper");
191
192
var pipetop = nextpipeupper.offset().top + nextpipeupper.height();
193
var pipeleft = nextpipeupper.offset().left - 2; // for some reason it starts at the inner pipes offset, not the outer pipes.
194
var piperight = pipeleft + pipewidth;
195
var pipebottom = pipetop + pipeheight;
196
197
if(debugmode)
198
{
199
var boundingbox = $("#pipebox");
200
boundingbox.css('left', pipeleft);
201
boundingbox.css('top', pipetop);
202
boundingbox.css('height', pipeheight);
203
boundingbox.css('width', pipewidth);
204
}
205
206
//have we gotten inside the pipe yet?
207
if(boxright > pipeleft)
208
{
209
//we're within the pipe, have we passed between upper and lower pipes?
210
if(boxtop > pipetop && boxbottom < pipebottom)
211
{
212
//yeah! we're within bounds
213
214
}
215
else
216
{
217
//no! we touched the pipe
218
playerDead();
219
return;
220
}
221
}
222
223
224
//have we passed the imminent danger?
225
if(boxleft > piperight)
226
{
227
//yes, remove it
228
pipes.splice(0, 1);
229
230
//and score a point
231
playerScore();
232
}
233
}
234
235
//Handle space bar
236
$(document).keydown(function(e){
237
//space bar!
238
if(e.keyCode == 32)
239
{
240
//in ScoreScreen, hitting space should click the "replay" button. else it's just a regular spacebar hit
241
if(currentstate == states.ScoreScreen)
242
$("#replay").click();
243
else
244
screenClick();
245
}
246
});
247
248
//Handle mouse down OR touch start
249
if("ontouchstart" in window)
250
$(document).on("touchstart", screenClick);
251
else
252
$(document).on("mousedown", screenClick);
253
254
function screenClick()
255
{
256
if(currentstate == states.GameScreen)
257
{
258
playerJump();
259
}
260
else if(currentstate == states.SplashScreen)
261
{
262
startGame();
263
}
264
}
265
266
function playerJump()
267
{
268
velocity = jump;
269
//play jump sound
270
soundJump.stop();
271
soundJump.play();
272
}
273
274
function setBigScore(erase)
275
{
276
var elemscore = $("#bigscore");
277
elemscore.empty();
278
279
if(erase)
280
return;
281
282
var digits = score.toString().split('');
283
for(var i = 0; i < digits.length; i++)
284
elemscore.append("<img src='assets/font_big_" + digits[i] + ".png' alt='" + digits[i] + "'>");
285
}
286
287
function setSmallScore()
288
{
289
var elemscore = $("#currentscore");
290
elemscore.empty();
291
292
var digits = score.toString().split('');
293
for(var i = 0; i < digits.length; i++)
294
elemscore.append("<img src='assets/font_small_" + digits[i] + ".png' alt='" + digits[i] + "'>");
295
}
296
297
function setHighScore()
298
{
299
var elemscore = $("#highscore");
300
elemscore.empty();
301
302
var digits = highscore.toString().split('');
303
for(var i = 0; i < digits.length; i++)
304
elemscore.append("<img src='assets/font_small_" + digits[i] + ".png' alt='" + digits[i] + "'>");
305
}
306
307
function setMedal()
308
{
309
var elemmedal = $("#medal");
310
elemmedal.empty();
311
312
if(score < 10)
313
//signal that no medal has been won
314
return false;
315
316
if(score >= 10)
317
medal = "bronze";
318
if(score >= 20)
319
medal = "silver";
320
if(score >= 30)
321
medal = "gold";
322
if(score >= 40)
323
medal = "platinum";
324
325
elemmedal.append('<img src="assets/medal_' + medal +'.png" alt="' + medal +'">');
326
327
//signal that a medal has been won
328
return true;
329
}
330
331
function playerDead()
332
{
333
//stop animating everything!
334
$(".animated").css('animation-play-state', 'paused');
335
$(".animated").css('-webkit-animation-play-state', 'paused');
336
337
//drop the bird to the floor
338
var playerbottom = $("#player").position().top + $("#player").width(); //we use width because he'll be rotated 90 deg
339
var floor = flyArea;
340
var movey = Math.max(0, floor - playerbottom);
341
$("#player").transition({ y: movey + 'px', rotate: 90}, 1000, 'easeInOutCubic');
342
343
//it's time to change states. as of now we're considered ScoreScreen to disable left click/flying
344
currentstate = states.ScoreScreen;
345
346
//destroy our gameloops
347
clearInterval(loopGameloop);
348
clearInterval(loopPipeloop);
349
loopGameloop = null;
350
loopPipeloop = null;
351
352
//mobile browsers don't support buzz bindOnce event
353
if(isIncompatible.any())
354
{
355
//skip right to showing score
356
showScore();
357
}
358
else
359
{
360
//play the hit sound (then the dead sound) and then show score
361
soundHit.play().bindOnce("ended", function() {
362
soundDie.play().bindOnce("ended", function() {
363
showScore();
364
});
365
});
366
}
367
}
368
369
function showScore()
370
{
371
//unhide us
372
$("#scoreboard").css("display", "block");
373
374
//remove the big score
375
setBigScore(true);
376
377
//have they beaten their high score?
378
if(score > highscore)
379
{
380
//yeah!
381
highscore = score;
382
//save it!
383
setCookie("highscore", highscore, 999);
384
}
385
386
//update the scoreboard
387
setSmallScore();
388
setHighScore();
389
var wonmedal = setMedal();
390
391
//SWOOSH!
392
soundSwoosh.stop();
393
soundSwoosh.play();
394
395
//show the scoreboard
396
$("#scoreboard").css({ y: '40px', opacity: 0 }); //move it down so we can slide it up
397
$("#replay").css({ y: '40px', opacity: 0 });
398
$("#scoreboard").transition({ y: '0px', opacity: 1}, 600, 'ease', function() {
399
//When the animation is done, animate in the replay button and SWOOSH!
400
soundSwoosh.stop();
401
soundSwoosh.play();
402
$("#replay").transition({ y: '0px', opacity: 1}, 600, 'ease');
403
404
//also animate in the MEDAL! WOO!
405
if(wonmedal)
406
{
407
$("#medal").css({ scale: 2, opacity: 0 });
408
$("#medal").transition({ opacity: 1, scale: 1 }, 1200, 'ease');
409
}
410
});
411
412
//make the replay button clickable
413
replayclickable = true;
414
}
415
416
$("#replay").click(function() {
417
//make sure we can only click once
418
if(!replayclickable)
419
return;
420
else
421
replayclickable = false;
422
//SWOOSH!
423
soundSwoosh.stop();
424
soundSwoosh.play();
425
426
//fade out the scoreboard
427
$("#scoreboard").transition({ y: '-40px', opacity: 0}, 1000, 'ease', function() {
428
//when that's done, display us back to nothing
429
$("#scoreboard").css("display", "none");
430
431
//start the game over!
432
showSplash();
433
});
434
});
435
436
function playerScore()
437
{
438
score += 1;
439
//play score sound
440
soundScore.stop();
441
soundScore.play();
442
setBigScore();
443
}
444
445
function updatePipes()
446
{
447
//Do any pipes need removal?
448
$(".pipe").filter(function() { return $(this).position().left <= -100; }).remove()
449
450
//add a new pipe (top height + bottom height + pipeheight == flyArea) and put it in our tracker
451
var padding = 80;
452
var constraint = flyArea - pipeheight - (padding * 2); //double padding (for top and bottom)
453
var topheight = Math.floor((Math.random()*constraint) + padding); //add lower padding
454
var bottomheight = (flyArea - pipeheight) - topheight;
455
var newpipe = $('<div class="pipe animated"><div class="pipe_upper" style="height: ' + topheight + 'px;"></div><div class="pipe_lower" style="height: ' + bottomheight + 'px;"></div></div>');
456
$("#flyarea").append(newpipe);
457
pipes.push(newpipe);
458
}
459
460
var isIncompatible = {
461
Android: function() {
462
return navigator.userAgent.match(/Android/i);
463
},
464
BlackBerry: function() {
465
return navigator.userAgent.match(/BlackBerry/i);
466
},
467
iOS: function() {
468
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
469
},
470
Opera: function() {
471
return navigator.userAgent.match(/Opera Mini/i);
472
},
473
Safari: function() {
474
return (navigator.userAgent.match(/OS X.*Safari/) && ! navigator.userAgent.match(/Chrome/));
475
},
476
Windows: function() {
477
return navigator.userAgent.match(/IEMobile/i);
478
},
479
any: function() {
480
return (isIncompatible.Android() || isIncompatible.BlackBerry() || isIncompatible.iOS() || isIncompatible.Opera() || isIncompatible.Safari() || isIncompatible.Windows());
481
}
482
};
483