xxxxxxxxxx
224
// A flappy bird game controlled by the microphone or SPACE BAR
//
// For other flappy bird versions, see:
// - Basic flappy bird: https://editor.p5js.org/jonfroehlich/sketches/sFOMDuDaw
// - Similar to this version but no audio input: https://editor.p5js.org/jonfroehlich/sketches/shtF6XFeY
//
// By Jon Froehlich
// http://makeabilitylab.io/
//
// Based on Daniel Shiffman's 'Flappy Bird'
// - https://thecodingtrain.com/CodingChallenges/031-flappybird.html
// - Video: https://www.youtube.com/watch?v=cXgA1d_E-jY
// and 'Clappy Bird' (LOL!):
// - https://youtu.be/aKiyCeIuwn4
//
// As well as other 'Flappy Bird' derivatives:
// - https://mdbrim.github.io/flappy/index.html
//
// Ideas for extensions:
// - bird flaps proportional to arms in PoseNet
// - [done] bird flaps proportional to sound input (ha, just saw that Shiffman
// has something similar: https://www.youtube.com/watch?v=aKiyCeIuwn4)
let bird;
let barriers;
let landscape;
let isGameOver = false;
let hasGameBegun = false;
let score = 0;
let hiScore = -1;
let lastHiScore = -1;
let stage = 1;
let startingSpeed = 4;
let arcadeFont;
let isInvincible = false; // change this to be true to become invincible
let minDistanceBetweenPipes;
let nextSpawnDistance;
// audio input related variables
let acceptKeyPressForFlap = false; // change to true to also enable SPACE BAR for flap
let mic;
let audioFlapTimestamp = 0; // timestamp for last audio-input based flap
let minAudioFlapTimeDelta = 100; // min time between audio-input based flaps
function preload() {
arcadeFont = loadFont('assets/arcadefont.ttf');
}
function setup() {
createCanvas(600, 400);
minDistanceBetweenPipes = width / 2;
textFont(arcadeFont);
mic = new p5.AudioIn(); // see https://p5js.org/reference/#/p5.AudioIn
mic.start();
resetGame();
// stop game loop until space bar hit to begin
noLoop();
}
function createBarrier(){
return new Barrier(startingSpeed + stage * 0.5, stage - 0.5);
}
function resetGame(){
score = 0;
isGameOver = false;
landscape = new Background();
bird = new Bird(64, height / 2);
barriers = [createBarrier()];
nextSpawnDistance = random(minDistanceBetweenPipes, width - width/4);
//nextSpawnDistance = random(width, width * 2);
loop();
}
function draw() {
background(220);
landscape.update();
landscape.draw();
if(barriers.length <= 0 || width - barriers[barriers.length - 1].x >= nextSpawnDistance){
barriers.push(createBarrier());
nextSpawnDistance = random(minDistanceBetweenPipes, width * 1.2);
}
// loop through all the barriers and update them
for(let i = barriers.length - 1; i >= 0; i--){
barriers[i].update();
barriers[i].draw();
//if we hit the barrier, end game
if(barriers[i].checkIfHitsBird(bird) && isInvincible == false){
isGameOver = true;
lastHiScore = hiScore;
if(hiScore < score){
hiScore = score;
}
noLoop(); // game is over, stop game loop
}
// if we successfully pass the barrier, increase the score
if(barriers[i].pastBird === false && barriers[i].checkIfPastBird(bird)){
score++;
if(score % 10 == 0){
stage++;
}
}
// remove barriers that have gone off the screen
if(barriers[i].getRight() < 0){
barriers.splice(i, 1);
}
}
bird.update();
bird.draw();
drawScore();
// draw mic level stuff
let micLevel = mic.getLevel();
let timeSinceLastFlap = millis() - audioFlapTimestamp;
if(micLevel > 0.1 && timeSinceLastFlap > minAudioFlapTimeDelta){
//bird.flap();
let flapStrength = map(micLevel, 0, 1, 0, height / 4)
bird.velocity += -flapStrength;
audioFlapTimestamp = millis();
//print(micLevel, flapStrength, timeSinceLastFlap);
}
var yMicLevel = map(micLevel, 0, 1, height, 0);
let volumeBarWidth = 5;
push();
fill(255, 0, 0, 128);
noStroke();
rect(0, yMicLevel, volumeBarWidth, height - yMicLevel);
pop();
}
function drawScore() {
fill(0);
textAlign(LEFT);
textSize(15);
text('Score:' + score, 10, 20);
let stageStr = 'Stage:' + stage;
text(stageStr, width - textWidth(stageStr) - 5, 20);
if(hiScore > 0){
let hiScoreStr = 'Hi-Score:' + hiScore;
text(hiScoreStr, width/2 - textWidth(hiScoreStr)/2, 20);
}
if (isGameOver) {
// dark overlay
fill(0, 0, 0, 100);
rect(0, 0, width, height);
// draw gameover text
textAlign(CENTER);
textSize(35);
fill(255);
text('GAME OVER!', width / 2, height / 3);
textSize(12);
let yText = height / 2;
if(hiScore > lastHiScore && hiScore > 0){
text('New Hi-Score of ' + hiScore + '!', width / 2, yText);
yText += 30;
}
text('Press UP ARROW to play again.', width / 2, yText);
}else if(hasGameBegun == false){
// if we're here, then the game has yet to begin for the first time
// dark overlay
fill(0, 0, 0, 100);
rect(0, 0, width, height);
// draw game over text
textAlign(CENTER);
textSize(14);
fill(255);
text('Make LOUD sounds to control flappy bird', width / 2, height / 3);
text('Press SPACE BAR to start!', width / 2, height / 2);
textSize(10);
text('Hint: clapping works well', width / 2, height - 40);
}
}
function keyPressed(){
if (key == ' ' && acceptKeyPressForFlap == true){ // spacebar
bird.flap();
}
// check for special states (game over or if game hasn't begun)
if (isGameOver == true && keyIsDown(UP_ARROW)) {
resetGame();
}else if(hasGameBegun == false && key == ' '){
hasGameBegun = true;
loop();
}
}