Using Example 10-10 as a model, add new features to the raindrop game. (Note I have revised the wording of this exercise a bit to make it more clear.)
- Implement a lives / scoring system for the game.
- Start the player off with 10 lives. For every raindrop that reaches the bottom, decrease the user’s lives by 1.
- For every raindrop caught, increase the player’s score by 1.
- If all raindrops fall without the score getting to zero, a new level begins and the raindrops appear faster.
- If the player loses all their lives during any level, the game is over.
- Show the score onscreen as a rectangle that decreases in size.
Do not try to implement all of these features at once. Do them one step at a time!
I’ve revised a few things about the solution to this exercise to make it more clear.
// Learning Processing
// Daniel Shiffman
// http://www.learningprocessing.com
// Exercise 10-4: The raindrop catching game
Catcher catcher; // One catcher object
Timer timer; // One timer object
Drop[] drops; // An array of drop objects
int totalDrops = 0; // totalDrops
// A boolean to let us know if the game is over
boolean gameOver = false;
// Variables to keep track of score, level, lives left
int score = 0; // User's score
int level = 1; // What level are we on
int lives = 10; // 10 lives per level (10 raindrops can hit the bottom)
int levelCounter = 0;
PFont f;
void setup() {
size(400,400);
smooth();
catcher = new Catcher(32); // Create the catcher with a radius of 32
drops = new Drop[50]; // Create 50 spots in the array (each level now just has 25 drops)
timer = new Timer(300); // Create a timer that goes off every 2 seconds
timer.start(); // Starting the timer
f = createFont("Arial",12,true); // A font to write text on the screen
}
void draw() {
background(255);
// If the game is over
if (gameOver) {
textFont(f,48);
textAlign(CENTER);
fill(0);
text("GAME OVER",width/2,height/2);
}
else {
// Set catcher location
catcher.setLocation(mouseX,mouseY);
// Display the catcher
catcher.display();
// Check the timer
if (timer.isFinished()) {
// Deal with raindrops
// Initialize one drop
if (totalDrops < drops.length) {
drops[totalDrops] = new Drop();
// Increment totalDrops
totalDrops++;
}
timer.start();
}
// Move and display all drops
for (int i = 0; i < totalDrops; i++ ) {
if (!drops[i].finished) {
drops[i].move();
drops[i].display();
if (drops[i].reachedBottom()) {
levelCounter++;
drops[i].finished();
// If the drop reaches the bottom a live is lost
lives--;
// If lives reach 0 the game is over
if (lives <= 0) {
gameOver = true;
}
}
// Everytime you catch a drop, the score goes up
if (catcher.intersect(drops[i])) {
drops[i].finished();
levelCounter++;
score++;
}
}
}
// If all the drops are done, that leve is over!
if (levelCounter >= drops.length) {
// Go up a level
level++;
// Reset all game elements
levelCounter = 0;
lives = 10;
timer.setTime(constrain(300-level*25,0,300));
totalDrops = 0;
}
// Display number of lives left
textFont(f,14);
fill(0);
text("Lives left: " + lives,10,20);
rect(10,24,lives*10,10);
text("Level: " + level,300,20);
text("Score: " + score,300,40);
}
}
// Learning Processing
// Daniel Shiffman
// http://www.learningprocessing.com
// Exercise 10-4: The raindrop catching game
class Catcher {
float r; // radius
color col; // color
float x,y; // location
Catcher(float tempR) {
r = tempR;
col = color(50,10,10,150);
x = 0;
y = 0;
}
void setLocation(float tempX, float tempY) {
x = tempX;
y = tempY;
}
void display() {
stroke(0);
fill(col);
ellipse(x,y,r*2,r*2);
}
// A function that returns true or false based on
// if the catcher intersects a raindrop
boolean intersect(Drop d) {
// Calculate distance
float distance = dist(x,y,d.x,d.y);
// Compare distance to sum of radii
if (distance < r + d.r) {
return true;
} else {
return false;
}
}
}
// Learning Processing
// Daniel Shiffman
// http://www.learningprocessing.com
// Exercise 10-4: The raindrop catching game
class Drop {
float x,y; // Variables for location of raindrop
float speed; // Speed of raindrop
color c;
float r; // Radius of raindrop
// New variable to keep track of whether drop is still being used
boolean finished = false;
Drop() {
r = 8; // All raindrops are the same size
x = random(width); // Start with a random x location
y = -r*4; // Start a little above the window
speed = random(2,5); // Pick a random speed
c = color(50,100,150); // Color
}
// Move the raindrop down
void move() {
// Increment by speed
y += speed;
}
// Check if it hits the bottom
boolean reachedBottom() {
// If we go a little beyond the bottom
if (y > height + r*4) {
return true;
}
else {
return false;
}
}
// Display the raindrop
void display() {
// Display the drop
fill(c);
noStroke();
for (int i = 2; i < r; i++ ) {
ellipse(x,y + i*4,i*2,i*2);
}
}
// If the drop is caught
void finished() {
finished = true;
}
}
// Learning Processing
// Daniel Shiffman
// http://www.learningprocessing.com
// Exercise 10-4: The raindrop catching game
class Timer {
int savedTime; // When Timer started
int totalTime; // How long Timer should last
Timer(int tempTotalTime) {
totalTime = tempTotalTime;
}
void setTime(int t) {
totalTime = t;
}
// Starting the timer
void start() {
// When the timer starts it stores the current time in milliseconds.
savedTime = millis();
}
// The function isFinished() returns true if 5,000 ms have passed.
// The work of the timer is farmed out to this method.
boolean isFinished() {
// Check how much time has passed
int passedTime = millis()- savedTime;
if (passedTime > totalTime) {
return true;
} else {
return false;
}
}
}








