var debugmode = false; var states = Object.freeze({ SplashScreen: 0, GameScreen: 1, ScoreScreen: 2 }); var currentstate; var gravity = 0.25; var velocity = 0; var position = 180; var rotation = 0; var jump = -4.6; var flyArea = $("#flyarea").height(); var score = 0; var highscore = 0; var pipeheight = 90; var pipewidth = 52; var pipes = new Array(); var replayclickable = false; //sounds var volume = 30; var soundJump = new buzz.sound("assets/sounds/sfx_wing.ogg"); var soundScore = new buzz.sound("assets/sounds/sfx_point.ogg"); var soundHit = new buzz.sound("assets/sounds/sfx_hit.ogg"); var soundDie = new buzz.sound("assets/sounds/sfx_die.ogg"); var soundSwoosh = new buzz.sound("assets/sounds/sfx_swooshing.ogg"); buzz.all().setVolume(volume); //loops var loopGameloop; var loopPipeloop; $(document).ready(function() { if(window.location.search == "?debug") debugmode = true; if(window.location.search == "?easy") pipeheight = 200; //get the highscore var savedscore = getCookie("highscore"); if(savedscore != "") highscore = parseInt(savedscore); //start with the splash screen showSplash(); }); function getCookie(cname) { var name = cname + "="; var ca = document.cookie.split(';'); for(var i=0; i= $("#land").offset().top) { playerDead(); return; } //have they tried to escape through the ceiling? :o var ceiling = $("#ceiling"); if(boxtop <= (ceiling.offset().top + ceiling.height())) position = 0; //we can't go any further without a pipe if(pipes[0] == null) return; //determine the bounding box of the next pipes inner area var nextpipe = pipes[0]; var nextpipeupper = nextpipe.children(".pipe_upper"); var pipetop = nextpipeupper.offset().top + nextpipeupper.height(); var pipeleft = nextpipeupper.offset().left - 2; // for some reason it starts at the inner pipes offset, not the outer pipes. var piperight = pipeleft + pipewidth; var pipebottom = pipetop + pipeheight; if(debugmode) { var boundingbox = $("#pipebox"); boundingbox.css('left', pipeleft); boundingbox.css('top', pipetop); boundingbox.css('height', pipeheight); boundingbox.css('width', pipewidth); } //have we gotten inside the pipe yet? if(boxright > pipeleft) { //we're within the pipe, have we passed between upper and lower pipes? if(boxtop > pipetop && boxbottom < pipebottom) { //yeah! we're within bounds } else { //no! we touched the pipe playerDead(); return; } } //have we passed the imminent danger? if(boxleft > piperight) { //yes, remove it pipes.splice(0, 1); //and score a point playerScore(); } } //Handle space bar $(document).keydown(function(e){ //space bar! if(e.keyCode == 32) { //in ScoreScreen, hitting space should click the "replay" button. else it's just a regular spacebar hit if(currentstate == states.ScoreScreen) $("#replay").click(); else screenClick(); } }); //Handle mouse down OR touch start if("ontouchstart" in window) $(document).on("touchstart", screenClick); else $(document).on("mousedown", screenClick); function screenClick() { if(currentstate == states.GameScreen) { playerJump(); } else if(currentstate == states.SplashScreen) { startGame(); } } function playerJump() { velocity = jump; //play jump sound soundJump.stop(); soundJump.play(); } function setBigScore(erase) { var elemscore = $("#bigscore"); elemscore.empty(); if(erase) return; var digits = score.toString().split(''); for(var i = 0; i < digits.length; i++) elemscore.append("" + digits[i] + ""); } function setSmallScore() { var elemscore = $("#currentscore"); elemscore.empty(); var digits = score.toString().split(''); for(var i = 0; i < digits.length; i++) elemscore.append("" + digits[i] + ""); } function setHighScore() { var elemscore = $("#highscore"); elemscore.empty(); var digits = highscore.toString().split(''); for(var i = 0; i < digits.length; i++) elemscore.append("" + digits[i] + ""); } function setMedal() { var elemmedal = $("#medal"); elemmedal.empty(); if(score < 10) //signal that no medal has been won return false; if(score >= 10) medal = "bronze"; if(score >= 20) medal = "silver"; if(score >= 30) medal = "gold"; if(score >= 40) medal = "platinum"; elemmedal.append('' + medal +''); //signal that a medal has been won return true; } function playerDead() { //stop animating everything! $(".animated").css('animation-play-state', 'paused'); $(".animated").css('-webkit-animation-play-state', 'paused'); //drop the bird to the floor var playerbottom = $("#player").position().top + $("#player").width(); //we use width because he'll be rotated 90 deg var floor = flyArea; var movey = Math.max(0, floor - playerbottom); $("#player").transition({ y: movey + 'px', rotate: 90}, 1000, 'easeInOutCubic'); //it's time to change states. as of now we're considered ScoreScreen to disable left click/flying currentstate = states.ScoreScreen; //destroy our gameloops clearInterval(loopGameloop); clearInterval(loopPipeloop); loopGameloop = null; loopPipeloop = null; //mobile browsers don't support buzz bindOnce event if(isIncompatible.any()) { //skip right to showing score showScore(); } else { //play the hit sound (then the dead sound) and then show score soundHit.play().bindOnce("ended", function() { soundDie.play().bindOnce("ended", function() { showScore(); }); }); } } function showScore() { //unhide us $("#scoreboard").css("display", "block"); //remove the big score setBigScore(true); //have they beaten their high score? if(score > highscore) { //yeah! highscore = score; //save it! setCookie("highscore", highscore, 999); } //update the scoreboard setSmallScore(); setHighScore(); var wonmedal = setMedal(); //SWOOSH! soundSwoosh.stop(); soundSwoosh.play(); //show the scoreboard $("#scoreboard").css({ y: '40px', opacity: 0 }); //move it down so we can slide it up $("#replay").css({ y: '40px', opacity: 0 }); $("#scoreboard").transition({ y: '0px', opacity: 1}, 600, 'ease', function() { //When the animation is done, animate in the replay button and SWOOSH! soundSwoosh.stop(); soundSwoosh.play(); $("#replay").transition({ y: '0px', opacity: 1}, 600, 'ease'); //also animate in the MEDAL! WOO! if(wonmedal) { $("#medal").css({ scale: 2, opacity: 0 }); $("#medal").transition({ opacity: 1, scale: 1 }, 1200, 'ease'); } }); //make the replay button clickable replayclickable = true; } $("#replay").click(function() { //make sure we can only click once if(!replayclickable) return; else replayclickable = false; //SWOOSH! soundSwoosh.stop(); soundSwoosh.play(); //fade out the scoreboard $("#scoreboard").transition({ y: '-40px', opacity: 0}, 1000, 'ease', function() { //when that's done, display us back to nothing $("#scoreboard").css("display", "none"); //start the game over! showSplash(); }); }); function playerScore() { score += 1; //play score sound soundScore.stop(); soundScore.play(); setBigScore(); } function updatePipes() { //Do any pipes need removal? $(".pipe").filter(function() { return $(this).position().left <= -100; }).remove() //add a new pipe (top height + bottom height + pipeheight == flyArea) and put it in our tracker var padding = 80; var constraint = flyArea - pipeheight - (padding * 2); //double padding (for top and bottom) var topheight = Math.floor((Math.random()*constraint) + padding); //add lower padding var bottomheight = (flyArea - pipeheight) - topheight; var newpipe = $('
'); $("#flyarea").append(newpipe); pipes.push(newpipe); } var isIncompatible = { Android: function() { return navigator.userAgent.match(/Android/i); }, BlackBerry: function() { return navigator.userAgent.match(/BlackBerry/i); }, iOS: function() { return navigator.userAgent.match(/iPhone|iPad|iPod/i); }, Opera: function() { return navigator.userAgent.match(/Opera Mini/i); }, Safari: function() { return (navigator.userAgent.match(/OS X.*Safari/) && ! navigator.userAgent.match(/Chrome/)); }, Windows: function() { return navigator.userAgent.match(/IEMobile/i); }, any: function() { return (isIncompatible.Android() || isIncompatible.BlackBerry() || isIncompatible.iOS() || isIncompatible.Opera() || isIncompatible.Safari() || isIncompatible.Windows()); } };