Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
/*Dodgeball
 By: Jasper Hong
 DESCRIPTION: Help Billy overcome his crippling depression by winning a game of dodgeball.
 The program keeps track of the score the player has, and lists the high score, so users can challenge each other to see who can get the highest score.
 The game ends when the player is hit by a dodgeball, which will take them to the game over screen and ask them if they want to try again.
 CONTROLS: Move the mouse to control Billy.
 Press Q to temporarily shrink the dodgeballs.
 Press W to temporarily cower to try and avoid dodgeballs.
 Press E to temporarily slow down time with your Nerd-Senseâ„¢.*/

//OVERALL GAME STATS
int currentScore, highScore;
int quoteNumber, backgroundNumber;
boolean title, gameOver, quoted;
//BILLY STATS
int billySize, originalBillySize;
//COOLDOWN TIMERS
int qCooldownStart, wCooldownStart, eCooldownStart;
int qCooldownLength, wCooldownLength, eCooldownLength;
int qEffectLength, wEffectLength, eEffectLength;
int scoreUpdate, scoreTimer;
//DODGEBALL STATS
float dodgeballSpeed, originalDodgeballSpeed, dodgeballSize, originalDodgeballSize;
float dodgeball1Speed, dodgeball2Speed, dodgeball3Speed;
int dodgeball1PositionX, dodgeball1PositionY, dodgeball2PositionX, dodgeball2PositionY, dodgeball3PositionX, dodgeball3PositionY;
int dodgeball1MovementX, dodgeball1MovementY, dodgeball2MovementX, dodgeball2MovementY, dodgeball3MovementX, dodgeball3MovementY;
boolean dodgeball1Spawned, dodgeball2Spawned, dodgeball3Spawned;

void setup() {
  size(400, 400);
  frameRate(60);
  background(0, 255, 100);
  //Stop displaying the cursor
  noCursor();
  //Starts the game with the title screen
  title = true;
  gameOver = false;
  //COOLDOWN VALUES
  scoreTimer = 1000;
  qCooldownLength = 12000;
  wCooldownLength = 10000;
  eCooldownLength = 15000;
  qEffectLength = 3000;
  wEffectLength = 5000;
  eEffectLength = 1500;
  //Resets all stats to their default settings, more useful later
  resetStats();
}

void draw() {
  //Will start at the title screen, then transition to the actual product. Similar setup for game overs.
  if (title) {
    titleScreen();
  } else if (gameOver) {
    gameOverScreen();
  } else {
    //UPDATE STATE OF THE GAME
    increaseDifficulty();
    //DEAL WITH DODGEBALLS
    spawnDodgeball();
    updateDodgeballPosition();
    //RESOLVE CONFLICTS
    updateEffects();
    resolveCollisions();
    //DRAW
    drawBackground(backgroundNumber);
    drawBilly();
    drawDodgeball();
    drawUI();
    drawAbilities();
  }
}

void resetStats() {
  //Resets all values to their default setting
  quoted = true;
  backgroundNumber = int(random(0, 3));
  currentScore = 0;
  billySize = 35;
  originalBillySize = billySize;
  //Set to a low number so the player can use them immediately
  qCooldownStart = -100000;
  wCooldownStart = -100000;
  eCooldownStart = -100000;
  scoreUpdate = 0;
  //DODGEBALL VALUES
  dodgeballSpeed = 2.5;
  originalDodgeballSpeed = dodgeballSpeed;
  dodgeballSize = 35;
  originalDodgeballSize = dodgeballSize;
  //DODGEBALL SPAWN VALUES
  dodgeball1Spawned = false;
  dodgeball2Spawned = false;
  dodgeball3Spawned = false;
  dodgeball1Speed = 0;
  dodgeball2Speed = 0;
  dodgeball3Speed = 0;
  //Immediately destroys the dodgeballs due to them being off-screen
  dodgeball1PositionX = -1000;
  dodgeball1PositionY = -1000;
  dodgeball2PositionX = -1000;
  dodgeball2PositionY = -1000;
  dodgeball3PositionX = -1000;
  dodgeball3PositionY = -1000;
  dodgeball1MovementX = 0;
  dodgeball1MovementY = 0;
  dodgeball2MovementX = 0;
  dodgeball2MovementY = 0;
  dodgeball3MovementX = 0;
  dodgeball3MovementY = 0;
}

void titleScreen() {
  //This function exists to inform the user of how to interact with the program.
  drawBackground(backgroundNumber);
  //Demos the game
  spawnDodgeball();
  updateDodgeballPosition();
  drawDodgeball();
  drawUI();
  strokeWeight(5);
  textSize(50);
  //Changes rectangle and font colour for easier visibility
  if (backgroundNumber == 0) {
    fill(255);
    stroke(0);
    rect(25, 75, 375, 140);
    rect(10, 160, 390, 325);
    fill(0);
  } else if (backgroundNumber == 1) {
    fill(0);
    stroke(255);
    rect(25, 75, 375, 140);
    rect(10, 160, 390, 325);
    fill(255);
  } else {
    fill(0);
    stroke(255);
    rect(25, 75, 375, 140);
    rect(10, 160, 390, 325);
    fill(255);
  }
  text("DODGEBALL", 50, 125);
  textSize(25);
  rectMode(CORNERS);
  text("Help Billy avoid dodgeballs!", 35, 200);
  text("Use special abilities to survive!", 15, 250);
  text("Press any key to get started!", 25, 300);
  //Ends the titlescreen upon the press of a mouse / button / key
  if (mousePressed || keyPressed) {
    resetStats();
    title = false;
  }
}

void gameOverScreen() {
  //This function displays the user their scores, and allows them to play again, resetting their progress
  background(0);
  if (currentScore > highScore) {
    highScore = currentScore;
  }
  textSize(50);
  fill(255);
  text("GAME OVER", 50, 125);
  textSize(25);
  //The boolean exists to flag whether the quote has been generated or not
  if (quoted) {
    quoteNumber = int(random(0, 4));
    quoted = false;
  }
  if (quoteNumber == 0) {
    text("Billy's out!", 140, 200);
  } else if (quoteNumber == 1) {
    text("Billy, hit the showers!", 75, 200);
  } else if (quoteNumber == 2) {
    text("Drop and give me twenty!", 50, 200);
  } else {
    text("Nice try, Billy. Maybe next time.", 10, 200);
  }
  text("Press any key to continue!", 50, 300);
  textSize(25);
  fill(255);
  text("Score: " + currentScore, 25, 385);
  text("High Score: " + highScore, 180, 385);
  //Resets the game
  if (mousePressed || keyPressed) {
    resetStats();
    gameOver = false;
  }
}

void increaseDifficulty() {
  //Gradually increase the difficulty of the game by increasing the size and speed of dodgeballs
  //Also updates the score once every interval
  if (dodgeballSpeed < 5 && eCooldownStart + eEffectLength <= millis()) {
    dodgeballSpeed = dodgeballSpeed + 0.001;
  }
  if (dodgeballSize < 100 && qCooldownStart + qEffectLength <= millis()) {
    dodgeballSize = dodgeballSize + 0.01;
  }
  if (scoreUpdate + scoreTimer <= millis()) {
    currentScore += 10;
    scoreUpdate = millis();
  }
}

void spawnDodgeball() {
  //Checks if the appropriate number of dodgeballs have been spawned.
  //Spawns a certain amount of dodgeballs, each with slightly different stats.
  //Attaches those stats to global variables.
  //Random is used to add variety to each dodgeball.
  int updownleftright;
  //updownleftright -> 0 = starts up, 1 = starts down, 2 = starts left, 3 = starts right
  if (dodgeball1Spawned == false) {
    dodgeball1Speed = int(random(dodgeballSpeed*0.9, dodgeballSpeed*1.1));
    updownleftright = int(random(0, 4));
    if (updownleftright == 0) {
      //Position refers to the current position of each dodgeball, and Movement means how much it will move and in what direction, based on its starting point
      dodgeball1PositionX = int(random(50, 350));
      dodgeball1PositionY = 50;
      dodgeball1MovementX = int(random(-2*dodgeball1Speed, 2*dodgeball1Speed));
      dodgeball1MovementY = int(random(1*dodgeball1Speed, 2*dodgeball1Speed));
    } else if (updownleftright == 1) {
      dodgeball1PositionX = int(random(50, 350));
      dodgeball1PositionY = 350;
      dodgeball1MovementX = int(random(-2*dodgeball1Speed, 2*dodgeball1Speed));
      dodgeball1MovementY = int(random(-1*dodgeball1Speed, -2*dodgeball1Speed));
    } else if (updownleftright == 2) {
      dodgeball1PositionX = 0;
      dodgeball1PositionY = int(random(100, 250));
      dodgeball1MovementX = int(random(1*dodgeball1Speed, 2*dodgeball1Speed));
      dodgeball1MovementY = int(random(-2*dodgeball1Speed, 2*dodgeball1Speed));
    } else {
      dodgeball1PositionX = 400;
      dodgeball1PositionY = int(random(100, 250));
      dodgeball1MovementX = int(random(-1*dodgeball1Speed, -2*dodgeball1Speed));
      dodgeball1MovementY = int(random(-2*dodgeball1Speed, 2*dodgeball1Speed));
    }
    //Sets the flag to prevent the program from creating it again while it is still active.
    dodgeball1Spawned = true;
  }
  if (dodgeball2Spawned==false) {
    dodgeball2Speed = int(random(dodgeballSpeed*0.8, dodgeballSpeed*1.3));
    updownleftright = int(random(0, 4));
    if (updownleftright == 0) {
      dodgeball2PositionX = int(random(50, 350));
      dodgeball2PositionY = 50;
      dodgeball2MovementX = int(random(-2*dodgeball2Speed, 2*dodgeball2Speed));
      dodgeball2MovementY = int(random(1*dodgeball2Speed, 2*dodgeball2Speed));
    } else if (updownleftright == 1) {
      dodgeball2PositionX = int(random(50, 350));
      dodgeball2PositionY = 350;
      dodgeball2MovementX = int(random(-2*dodgeball2Speed, 2*dodgeball2Speed));
      dodgeball2MovementY = int(random(-1*dodgeball2Speed, -2*dodgeball2Speed));
    } else if (updownleftright == 2) {
      dodgeball2PositionX = 0;
      dodgeball2PositionY = int(random(100, 250));
      dodgeball2MovementX = int(random(1*dodgeball2Speed, 2*dodgeball2Speed));
      dodgeball2MovementY = int(random(-2*dodgeball2Speed, 2*dodgeball2Speed));
    } else {
      dodgeball2PositionX = 400;
      dodgeball2PositionY = int(random(100, 250));
      dodgeball2MovementX = int(random(-1*dodgeball2Speed, -2*dodgeball2Speed));
      dodgeball2MovementY = int(random(-2*dodgeball2Speed, 2*dodgeball2Speed));
    }
    dodgeball2Spawned = true;
  }
  if (dodgeball3Spawned==false) {
    dodgeball3Speed = int(random(dodgeballSpeed, dodgeballSpeed*1.5));
    updownleftright = int(random(0, 4));
    if (updownleftright == 0) {
      dodgeball3PositionX = int(random(50, 350));
      dodgeball3PositionY = 50;
      dodgeball3MovementX = int(random(-2*dodgeball3Speed, 2*dodgeball3Speed));
      dodgeball3MovementY = int(random(1*dodgeball3Speed, 2*dodgeball3Speed));
    } else if (updownleftright == 1) {
      dodgeball3PositionX = int(random(50, 350));
      dodgeball3PositionY = 350;
      dodgeball3MovementX = int(random(-2*dodgeball3Speed, 2*dodgeball3Speed));
      dodgeball3MovementY = int(random(-1*dodgeball3Speed, -2*dodgeball3Speed));
    } else if (updownleftright == 2) {
      dodgeball3PositionX = 0;
      dodgeball3PositionY = int(random(100, 250));
      dodgeball3MovementX = int(random(1*dodgeball3Speed, 2*dodgeball3Speed));
      dodgeball3MovementY = int(random(-2*dodgeball3Speed, 2*dodgeball3Speed));
    } else {
      dodgeball3PositionX = 400;
      dodgeball3PositionY = int(random(100, 250));
      dodgeball3MovementX = int(random(-1*dodgeball3Speed, -2*dodgeball3Speed));
      dodgeball3MovementY = int(random(-2*dodgeball3Speed, 2*dodgeball3Speed));
    }
    dodgeball3Spawned = true;
  }
}

void updateDodgeballPosition() {
  //Goes through each dodgeball
  //Move each dodgeball based on certain values
  //Delete them if they fly off-screen
  if (dodgeball1Spawned) {
    dodgeball1PositionX = dodgeball1PositionX + dodgeball1MovementX;
    dodgeball1PositionY = dodgeball1PositionY + dodgeball1MovementY;
    if (dodgeball1PositionX < 0 || dodgeball1PositionX > 400 || dodgeball1PositionY < 50 || dodgeball1PositionY > 350) {
      dodgeball1Spawned = false;
    }
  }
  if (dodgeball2Spawned) {
    dodgeball2PositionX = dodgeball2PositionX + dodgeball2MovementX;
    dodgeball2PositionY = dodgeball2PositionY + dodgeball2MovementY;
    if (dodgeball2PositionX < 0 || dodgeball2PositionX > 400 || dodgeball2PositionY < 50 || dodgeball2PositionY > 350) {
      dodgeball2Spawned = false;
    }
  }
  if (dodgeball3Spawned) {
    dodgeball3PositionX = dodgeball3PositionX + dodgeball3MovementX;
    dodgeball3PositionY = dodgeball3PositionY + dodgeball3MovementY;
    if (dodgeball3PositionX < 0 || dodgeball3PositionX > 400 || dodgeball3PositionY < 50 || dodgeball3PositionY > 350) {
      dodgeball3Spawned = false;
    }
  }
}

void updateEffects() {
  //Check if the effects have expired.
  //If they have, then end the effect(s).
  //Set a specific time, then compare said time to the millis() function, which tracks how long the program has been running
  //Checks for size and speed to prevent the program to stop increasing in difficulty.
  if (qCooldownStart + qEffectLength <= millis() && dodgeballSize < originalDodgeballSize) {
    dodgeballSize = originalDodgeballSize;
  }
  if (wCooldownStart + wEffectLength <= millis()) {
    billySize = originalBillySize;
  }
  if (eCooldownStart + eEffectLength <= millis() && dodgeballSpeed < originalDodgeballSpeed) {
    dodgeballSpeed = originalDodgeballSpeed;
  }
}

void activateQ() {
  //Checks if Q is off cooldown. If so, decrease dodgeball size.
  if (qCooldownStart + qCooldownLength <= millis()) {
    originalDodgeballSize = dodgeballSize;
    dodgeballSize = dodgeballSize/2;
    qCooldownStart = millis();
  }
}

void activateW() {
  //Checks if W is off cooldown. If so, decrease hitbox.
  if (wCooldownStart + wCooldownLength <= millis()) {
    billySize = 25;
    wCooldownStart = millis();
  }
}

void activateE() {
  //Checks if E is off cooldown. If so, slows down the dodgeballs.
  if (eCooldownStart + eCooldownLength <= millis()) { 
    originalDodgeballSpeed = dodgeballSpeed;
    dodgeballSpeed = dodgeballSpeed/2;
    eCooldownStart = millis();
  }
}

void resolveCollisions() {
  //Restrict the mouse to the screen
  //Check if the user has been hit by a dodgeball
  //If so, end the game.
  mouseX = constrain(mouseX, 50, 350);
  mouseY = constrain(mouseY, 100, 300);
  if (mouseX+billySize/2 >= dodgeball1PositionX - dodgeballSize/2 && mouseX -billySize/2 <= dodgeball1PositionX + dodgeballSize/2 && mouseY+billySize/2 >= dodgeball1PositionY - dodgeballSize/2 && mouseY-billySize/2 <= dodgeball1PositionY+dodgeballSize/2) {
    gameOver=true;
  }
  if (mouseX+billySize/2 >= dodgeball2PositionX - dodgeballSize/2 && mouseX -billySize/2 <= dodgeball2PositionX + dodgeballSize/2 && mouseY+billySize/2 >= dodgeball2PositionY - dodgeballSize/2 && mouseY-billySize/2 <= dodgeball2PositionY+dodgeballSize/2) {
    gameOver=true;
  }
  if (mouseX+billySize/2 >= dodgeball3PositionX - dodgeballSize/2 && mouseX -billySize/2 <= dodgeball3PositionX + dodgeballSize/2 && mouseY+billySize/2 >= dodgeball3PositionY - dodgeballSize/2 && mouseY-billySize/2 <= dodgeball3PositionY+dodgeballSize/2) {
    gameOver=true;
  }
}

void drawBackground(int number) {
  //Takes in a random number, then draws a different background depending on what the number is.
  if (number == 0) {
    //PLAYGROUND
    //Nested For Loop automates the process of drawing the grass, two different grass lines per strand of grass.
    background(0, 255, 100);
    strokeWeight(3);
    stroke(50, 200, 50);
    for (int h = 75; h < 350; h+= 75) {
      for (int i = 0; i < 400; i+= 20) {
        line(i, h+25, i+10, h);
      }
      for (int i = 10; i < 400; i+= 20) {
        line(i, h, i+10, h+25);
      }
    }
  } else if (number == 1) {
    //GYM
    //For loop is replicate school gyms.
    background(255, 165, 0);
    stroke(255, 200, 0);
    strokeWeight(2);
    for (int i = 40; i < 400; i += 40) {
      line(i, 0, i, 400);
    }
    ellipseMode(CENTER);
    noFill();
    ellipse(200, 200, 70, 70);
  } else {
    //STREET
    //For loops to draw cracks on the sidewalk and the dividing line in the middle of the road.
    background(150);
    strokeWeight(8);
    stroke(0);
    rectMode(CORNERS);
    fill(200);
    rect(0, 0, 75, 400);
    rect(325, 0, 400, 400);
    strokeWeight(1);
    stroke(0);
    for (int i = 0; i < 400; i += 80) {
      line(0, i, 75, i);
    }
    for (int j = 0; j < 400; j += 80) {
      line(325, j, 400, j);
    }
    stroke(255, 255, 0);
    strokeWeight(12);
    for (int k = 0; k < 400; k += 100) {
      line(200, k, 200, k+60);
    }
  }
}

void drawBilly() {
  //Draws Billy based on the user's mouse position
  ellipseMode(CENTER);
  strokeWeight(2);
  stroke(225);
  fill(0, 0, 255);
  ellipse(mouseX, mouseY, billySize, billySize);
}

void drawDodgeball() {
  //Checks each dodgeball to see if it is on the screen. If so, it draws it.
  stroke(0);
  strokeWeight(2);
  fill(255, 0, 0);
  ellipseMode(CENTER);
  if (dodgeball1Spawned) {
    ellipse(dodgeball1PositionX, dodgeball1PositionY, dodgeballSize, dodgeballSize);
  }
  if (dodgeball2Spawned) {
    ellipse(dodgeball2PositionX, dodgeball2PositionY, dodgeballSize, dodgeballSize);
  }
  if (dodgeball3Spawned) {
    ellipse(dodgeball3PositionX, dodgeball3PositionY, dodgeballSize, dodgeballSize);
  }
}

void drawUI() {
  //Draws the UI and lists the score
  rectMode(CORNERS);
  noStroke();
  fill(0);
  rect(0, 0, 400, 50);
  rect(0, 350, 400, 400);
  textSize(25);
  fill(255);
  text("Score: " + currentScore, 25, 385);
  text("High Score: " + highScore, 180, 385);
}

void drawAbilities() {
  //Check each ability if they are used, then draws an appropriate indicator based on the result.
  //Indicators will be dim when the ability is ready, bright when the ability is active, and dark when the ability is on cooldown.
  rectMode(CORNERS);
  stroke(255);
  strokeWeight(5);
  textSize(30);
  if (qCooldownStart + qEffectLength >= millis()) {
    fill(255, 0, 0);
    rect(25, 5, 125, 45);
    fill(255);
    text("Q", 65, 35);
  } else if (qCooldownStart + qCooldownLength >= millis()) {
    fill(50);
    rect(25, 5, 125, 45);
  } else {
    fill(150, 0, 0);
    rect(25, 5, 125, 45);
    fill(200);
    text("Q", 65, 35);
  }
  if (wCooldownStart + wEffectLength >= millis()) {
    fill(0, 0, 255);
    rect(150, 5, 250, 45);
    fill(255);
    text("W", 190, 37);
  } else if (wCooldownStart + wCooldownLength >= millis()) {
    fill(50);
    rect(150, 5, 250, 45);
  } else {
    fill(0, 0, 150);
    rect(150, 5, 250, 45);
    fill(200);
    text("W", 190, 37);
  }
  if (eCooldownStart + eEffectLength >= millis()) {
    fill(0, 255, 0);
    rect(275, 5, 375, 45);
    fill(255);
    text("E", 315, 37);
  } else if (eCooldownStart + eCooldownLength >= millis()) {
    fill(50);
    rect(275, 5, 375, 45);
  } else {
    fill(0, 150, 0);
    rect(275, 5, 375, 45);
    fill(200);
    text("E", 315, 37);
  }
}

//Used https://processing.org/reference/keyPressed_.html, and https://processing.org/reference/keyCode.html
void keyPressed() {
  //Activates skills upon pressing certain buttons.
  if (key=='q') {
    activateQ();
  }
  if (key=='w') {
    activateW();
  }
  if (key=='e') {
    activateE();
  }
}