Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
///////////////////////////////////////////////////////////////////////////
// Author: Justin Vrieling
// Made for Media Computation at Sheridan College
// October 2018
//
// - Click the duck to spook it and make it fly! Move your mouse over it in
//   flight to change its direction!
// - Make jeremy the duck hit a UFO to make it crash! The ufo speeds up
//   whenever you hit it, and slows down if you miss.
//
///////////////////////////////////////////////////////////////////////////

//declare variables for use later
float waterOffset;
float starAlpha = 100;
//A couple of variables to handle the duck (HMM, IF ONLY I COULD USE ARRAYS OR CLASSES)
int duckCount = 5;
float duckSpeed = 2;
float ducksX = random(0, 400);
float ducksY = random(240, 390);
float ducksDirection = 0;
float ducksRise = 0;
float duckLanding = 400;
int dirCooldown = 0;
float wingOffset = 0;
//Variables for the UFOs
float ufoX = -100;
float ufoY = 100;
float ufoSpeed = 1;
int ufoCooldown = 10;
int score = 0;
//Coordinates for the stars
float star1X = random(0, 400);
float star1Y = random(0, 240);
float star2X = random(0, 400);
float star2Y = random(0, 240);
float star3X = random(0, 400);
float star3Y = random(0, 240);
float star4X = random(0, 400);
float star4Y = random(0, 240);
float star5X = random(0, 400);
float star5Y = random(0, 240);

void setup() {
  size(400, 400);
  noStroke();
}

void draw() {
  frameRate(60);
  background(0);
  //Modify the variables that need to change with each frame
  starAlpha += random(-30, 30);
  waterOffset = 0+(sin(frameCount*0.05)*3);
  moveDucks();
  moveUfo();
  if (dirCooldown > 0) {
    dirCooldown--;
  }
  if (ufoCooldown > 0) {
    ufoCooldown--;
  }
  //draw all the things
  drawLake();
  drawStars();
  drawUfo();
  drawShimmer();
  drawDucks();
}
/////////////////////
// UFO FUNCTIONS
///////////////////////
void moveUfo() {
  //Move the ufo
  if (ufoCooldown <= 0) {
    ufoX+=ufoSpeed;
  }
  //if it goes off screen reset it
  if (ufoX > width+100) {
    resetUfo();
  }
  //if it hits the duck, make it go boom and add score and speed it up
  if (ducksX >= ufoX-20 && ducksX <= ufoX+20 && ducksY <= ufoY+20 && ducksY >= ufoY-20) {
    score++;
    ufoSpeed = (ufoSpeed + 0.1) * 1.2;
    fill(255, 0, 0);
    ellipse(ufoX, ufoY, 70, 70);
    frameRate(2);
    print("BOOM! Score: " + score + "\n");
    resetUfo();
  }
}
void resetUfo() {
  //Reset the ufo to the left side, and set the cooldown so it doesn't come right away
  ufoCooldown = 80;
  ufoX = -50;
  ufoY = random(70, 150);
  ufoSpeed *= 0.9;
}
void drawUfo() {
  //Draw the ufo
  //Blue orb thing
  fill(0, 200, 200);
  ellipse(ufoX, ufoY-10, 25, 25);
  //Red body. Shift the colour based on score
  fill(255-(score*20), 0+(score*20), 0+(score*20));
  ellipse(ufoX, ufoY, 50, 20);
}


//////////////////////
// DUCK FUNCTIONS
//////////////////////
void drawDucks() {
  //Draw a duck relative to the coordinates from the lists.
  //The conditional makes the duck face where it's going
  if (ducksDirection >= 0) {
    //body
    fill(#4E504A);
    ellipse(ducksX, ducksY+waterOffset, 40, 20);
    //wing
    fill(#41423D);
    triangle(ducksX-15, ducksY+waterOffset+wingOffset, ducksX+5, ducksY-6+waterOffset, ducksX+5, ducksY+7+waterOffset);
    //head
    fill(#1B6C3D);
    ellipse(ducksX+15, (ducksY+waterOffset)-10, 15, 15);
    //beak
    fill(#FFDD95);
    triangle(ducksX+21, (ducksY+waterOffset)-7, ducksX+26, (ducksY+waterOffset)-9, ducksX+21, (ducksY+waterOffset)-12);
    //eye
    fill(0);
    ellipse(ducksX+17, (ducksY+waterOffset)-12, 3, 3);
  } else {
    //body
    fill(#4E504A);
    ellipse(ducksX, ducksY+waterOffset, 40, 20);
    //wing
    fill(#41423D);
    triangle(ducksX+15, ducksY+waterOffset+wingOffset, ducksX-5, ducksY-6+waterOffset, ducksX-5, ducksY+7+waterOffset);
    //head
    fill(#1B6C3D);
    ellipse(ducksX-15, (ducksY+waterOffset)-10, 15, 15);
    //beak
    fill(#FFDD95);
    triangle(ducksX-21, (ducksY+waterOffset)-7, ducksX-26, (ducksY+waterOffset)-9, ducksX-21, (ducksY+waterOffset)-12);
    //eye
    fill(0);
    ellipse(ducksX-17, (ducksY+waterOffset)-12, 3, 3);
  }
}

void mouseClicked() {
  //When mouse is clicked, Check if it was on the duck
  if (mouseX <= ducksX+20 && mouseX >= ducksX-20 && mouseY <= ducksY+20 && mouseY >= ducksY-20) {
    scareDucks();
  }
}

////////////////////////////////////////////////////////////////////////////////////////
// A function to handle movement of the ducks. Handles exiting the play space as well
void moveDucks() {

  //If mouse is over the duck, make it change direction
  if (dirCooldown == 0 && mouseX <= ducksX+20 && mouseX >= ducksX-20 && mouseY <= ducksY+20 && mouseY >= ducksY-20) {
    ducksDirection *= -1;
    dirCooldown = 40;
  }
  //If the duckDirection isn't zero, it's in flight
  if (ducksDirection != 0) {
    wingOffset = (sin(frameCount*0.3)*15);
    //The variables will always be appropriate so these equations will make them rise or fall.
    ducksY -= (duckSpeed*ducksRise);
    ducksX += duckSpeed*ducksDirection;

    //make sure the ducks don't go off screen
    if (ducksX <= 0 || ducksX >= 400) { 
      ducksDirection *= -1;
    }
    //make sure they don't go off the top either
    if (ducksY < 50) {
      ducksRise *= -1;
    }
    //When the duck is in the air decide on the landing Y coordinate
    if (duckLanding == 400 && ducksY <= 200) {
      duckLanding = random(240, 380);
    }
    //When the duck hits the Y landing, make it stop flying and reset stuff.
    if (ducksY >= duckLanding) {
      ducksDirection = 0;
      duckLanding = 400;
      wingOffset = 0;
    }
  }
}

void scareDucks() {
  //Don't let the direction be zero.
  while (ducksDirection == 0) { 
    ducksDirection = round(random(-1, 1));
    ducksRise = 1;
  }
}

//////////////////////
// LAKE FUNCTIONS
//////////////////////
void drawShimmer() {
  //Draw the shimmering reflection of the moon on the lake
  fill(255, 100);
  ellipse(210+(sin(frameCount*0.1)*4), 245+waterOffset, 30, 5);
  ellipse(190+(sin(frameCount*0.11)*5), 245+waterOffset, 40, 6);
  ellipse(210+(sin(frameCount*0.12)*5), 250+waterOffset, 35, 4);
  ellipse(230+(sin(frameCount*0.1)*6), 246+waterOffset, 20, 4);
  ellipse(240+(sin(frameCount*0.16)*4), 243+waterOffset, 10, 3);
  ellipse(180+(sin(frameCount*0.08)*7), 242+waterOffset, 45, 4);
  ellipse(220+(sin(frameCount*0.1)*10), 242+waterOffset, 15, 4);
}
void drawStars() {
  //Draw the stars
  fill(255, random(90, 150));
  ellipse(star1X, star1Y, 3, 3);
  ellipse(star2X, star2Y, 3, 3);
  ellipse(star3X, star3Y, 3, 3);
  ellipse(star4X, star4Y, 3, 3);
  ellipse(star5X, star5Y, 3, 3);
  fill(255, 70);
  //Draw the shimmer around the stars.
  //Using sin() and random to make them glimmer real cool
  ellipse(star1X, star1Y, 4+(sin(frameCount*random(0.01, 0.05))*3), 4+(sin(frameCount*random(0.01, 0.05))*3));
  ellipse(star2X, star2Y, 4+(sin(frameCount*random(0.01, 0.05))*3), 4+(sin(frameCount*random(0.01, 0.05))*3));
  ellipse(star3X, star3Y, 4+(sin(frameCount*random(0.01, 0.05))*3), 4+(sin(frameCount*random(0.01, 0.05))*3));
  ellipse(star4X, star4Y, 4+(sin(frameCount*random(0.01, 0.05))*3), 4+(sin(frameCount*random(0.01, 0.05))*3));
  ellipse(star5X, star5Y, 4+(sin(frameCount*random(0.01, 0.05))*3), 4+(sin(frameCount*random(0.01, 0.05))*3));

  //Draw the moon//
  fill(255);
  ellipse(200, 70, 40, 40);
  fill(#FFEAD0);
  //craters
  ellipse(210, 60, 7, 7);
  ellipse(195, 70, 9, 9);
  ellipse(190, 65, 5, 5);
  ellipse(200, 65, 5, 5);
  ellipse(205, 80, 5, 5);
  ellipse(185, 80, 4, 4);
}

void drawLake() {
  //Draw the lake, use a loop for the gradient
  rectMode(CORNER);
  for (int i = 0; i < 200; i += 20) {
    //Set the colour based on how low on the screen
    fill(33-(i/5), 42-(i/5), 66-(i/5));
    //Draw a rectangle, using water offSet to make it wave
    rect(0, ((240+i)+waterOffset), 400, 30);
  }
}