Going through the Learn Processing Book - I'm not sure why this isn't working (raindrops)

edited January 2015 in Questions about Code

I could Google the answer, but then I'll just be working through that instead of this...

What I'm currently trying to do is implement a score counter, that's based on one of the 'raindrops' getting to / exceeding the height of the window.

Score counter starts at 10 -> Each drop that hits / exceeds height is -1 from score -> game over at 0

So what I immediately thought was that I could subtract 1 from the score counter each time a drop went off the screen. But they just keep counting, rather than the behaviour I'm expecting which is for them to be replaced each time.

Error that's happening :

When a droplet goes off the screen the score continues to decrease. It keeps decreasing indefinitely, so if only one droplet goes off screen the game is automatically lost.

I don't understand why this is, and have included what I believe to be the related code beneath. From line 6 of that code I'm checking the current drop element of the iteration to see whether it's above the value of height.

If it is above the height value, the score is decreased. This is one action on this one array element, on the next iteration the condition of line 6 will be referencing a different drop, so why is it that the previous droplet continues to reduce the score? I'm not really following that.

Here's the part of the code relating to this :

  // Move and display all drops
  for (int i = 0; i < totalDrops; i++ ) {
    drops[i].move();
    drops[i].display();
    if (drops[i].y > height) {
      score -= 1;
      println(score);
      if (score< 1) {
        println("lost lost lost lost");
      }
      background(0);
    }
    if (catcher.intersect(drops[i])) {
      drops[i].caught();
    }
  }

Here's the rest of the code, sorry it's a bit long winded :

// Example 10-10: 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

int score = 10;


void setup() {
  size(400, 400);
  frameRate(60);
  smooth();
  catcher = new Catcher(32); // Create the catcher with a radius of 32
  drops = new Drop[10];    // Create 1000 spots in the array
  timer = new Timer(3000);   // Create a timer that goes off every 2 seconds
  timer.start();             // Starting the timer
}

void draw() {
  background(255);

  // Set catcher location
  catcher.setLocation(mouseX, mouseY); 
  // Display the catcher
  catcher.display(); 

  // Check the timer
  if (timer.isFinished()) {
    // Deal with raindrops
    // Initialize one drop
    drops[totalDrops] = new Drop();
    // Increment totalDrops
    totalDrops ++ ;
    // If we hit the end of the array
    if (totalDrops >= drops.length) {
      totalDrops = 0; // Start over
    }
    timer.start();
  }

  // Move and display all drops
  for (int i = 0; i < totalDrops; i++ ) {
    drops[i].move();
    drops[i].display();
    if (drops[i].y > height) {
      score -= 1;
      println(score);
    }
    if (score< 1) {
      println("lost lost lost lost");
    }
    if (catcher.intersect(drops[i])) {
      drops[i].caught();
    }
  }
}

// Example 10-10: 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;
    }
  }
}

// Example 10-10: 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

  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(1,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 caught() {
    // Stop it from moving by setting speed equal to zero
    speed = 0; 
    // Set the location to somewhere way off-screen
    y = - 1000;
  }
}

// http://www.learningprocessing.com

class Timer {

  int savedTime; // When Timer started
  int totalTime; // How long Timer should last

  Timer(int tempTotalTime) {
    totalTime = tempTotalTime;
  }

  // Starting the timer
  void start() {
    // When the timer starts it stores the current time in milliseconds.
    savedTime = millis(); 
  }

  // The function isFinished() returns true if "totalTime" has 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;
    }
  }
}

Answers

  • edited January 2015 Answer ✓

    Try this:

    ...

      // Move and display all drops
      for (int i = 0; i < totalDrops; i++ ) {
        drops[i].move();
        drops[i].display();
        if (drops[i].y > height-2 && drops[i].y < height+2) {
          score -= 1;
          if (score == 0) {
            //score = 0;
            println("score is zero");
            println("lost lost lost lost");
            noLoop();
          }
        } else if (catcher.intersect(drops[i])) {
          drops[i].caught();
        }
        println(score);
      }
    

    ...

    By just using if(drops[i].y > height) you run into trouble: the condition continues to remain true, which is why the counter still keeps counting down, even though the drop has disappeared.

    My solution here is slightly buggy in that you may need to play around with the tolerance level (height+-3 or 4 etc). I have had similar issues in the past where objects seem to jump the condition boundaries - not quite sure why this happens - possibly related to frame rate issues. Rather use a range than a definitive statement in this case to ensure that you catch the condition.

Sign In or Register to comment.