Search code examples
processing

Fly Swatter in Processing - Almost works


The task is create a fly swatting game in Processing where a fly appears at a random location on the screen, once the fly is swatted it is replaced with the image of a swatted fly, and another fly appears on the screen in a random location. Currently, when the mouse is pressed to swat the fly, multiple flies appear in the window as well (instead of just one). The extra flies that appear in the window also increment the score by 1 for each fly randomly spawned.

I suspect this is has something to do with my arrays, but I'm struggling to find a solution.

I would greatly appreciate some clarity in my errors.

Some screenshots for greater clarity:

Initial screen when starting the game: score: 0 text on top left, black on white background, a black outline illustration of a fly swatter and a single (unswatted) fly to the right.

Swatting one fly. If swatter is within the collision detection of a fly & the fly is being swatted, many fly's then appear on the screen: in addition to the above image there is one swatted fly sprite, however many more unswatted flies (instead of 1)

For as long as a fly has been swatted and the mouse button is being pressed, more fly's keep appearing on the screen, along with the score incrementing with each fly added (but not swatted): similar to the above image, except there are 2 swatted flies and a lot more unswatted flies

PImage fly, flybye, swatter, swatted;
float[] fX, fY; // Declaring fX & fY locaiton arrays
int[] swat;
int score = 0;

void setup() {
  size(800, 400);
  // Images
  fly = loadImage("fly.png");
  fly.resize(50,0);
  flybye = loadImage("flybye.png");
  flybye.resize(50,0);
  swatter = loadImage("swatter.png");  
  swatted = loadImage("swatted.png");
  
  fX = new float[0];
  fY = new float[0];
  swat = new int[0];
  
  fX = append(fX, random(width));
  fY = append(fY, random(height));
  swat = append(swat, 0);
}

void draw() {
  background(255);
  populate(); // Displays flys to the screen
  fill(0);
  textSize(30);
  text("Score: " + score, 20, 50); // Displays the score in the top left corner 
  noCursor(); // Removes the cursor from the screen
  mousePressed(); 
}

void populate() {
  for (int i = 0; i < fX.length; i++) {
    if (swat[i] == 1) { // if swatted
      image(flybye, fX[i], fY[i]);
    } else {
      image(fly, fX[i], fY[i]);
    }
  }
}

void collisionDetect() {
  for (int i = 0; i < swat.length; i++) {
    if (mouseX > fX[i] && mouseX < fX[i] + fly.width &&
        mouseY > fY[i] && mouseY < fY[i] + fly.height) {
          swat[i] = 1;
          fX = append(fX, random(width));
          fY = append(fY, random(height));
          swat = append(swat, 0);
          score++;
          }
  } 
}

void mousePressed() {
  if (mousePressed) {
    collisionDetect();
    image(swatted, mouseX-35, mouseY-25);
  } else {
    image(swatter, mouseX-35, mouseY-25);
  }
}

Solution

  • You're very close, however parts of your code need a closer look as there are a few mistakes:

    • mousePressed() a function you can override in any Processing sketch:
    • calling it from draw() is unecessary (this is why one reason you see the duplicate flies)
    • if (mousePressed) { is redundant inside mousePressed() since the function should only be called once per click. (Try out the reference example in a separate sketch to get the hang of it)
    • One more source of duplicate flies is the bounding box condition inside collisionDetect()
    if (mouseX > fX[i] && mouseX < fX[i] + fly.width &&
            mouseY > fY[i] && mouseY < fY[i] + fly.height)...
    

    only checks if a fly (any fly, even already swatted) is inside the box. You might want to constrain that further by filtering un-swatted flies only before incrementing score and adding a new fly.

    e.g.

    void collisionDetect() {
      for (int i = 0; i < swat.length; i++) {
        if (mouseX > fX[i] && mouseX < fX[i] + fly.width &&
            mouseY > fY[i] && mouseY < fY[i] + fly.height &&
            // also check this fly has not been swatted (yet)
            swat[i] == 0) {
              swat[i] = 1;
              fX = append(fX, random(width));
              fY = append(fY, random(height));
              swat = append(swat, 0);
              score++;
              }
      } 
    }
    

    This is your code with the above mentions added:

    PImage fly, flybye, swatter, swatted;
    float[] fX, fY; // Declaring fX & fY location arrays
    int[] swat;
    int score = 0;
    
    void setup() {
      size(800, 400);
      // Images
      fly = loadImage("fly.png");
      fly.resize(50,0);
      flybye = loadImage("flybye.png");
      flybye.resize(50,0);
      swatter = loadImage("swatter.png");  
      swatted = loadImage("swatted.png");
      
      fX = new float[0];
      fY = new float[0];
      swat = new int[0];
      
      fX = append(fX, random(width));
      fY = append(fY, random(height));
      swat = append(swat, 0);
    }
    
    void draw() {
      background(255);
      populate(); // Displays flys to the screen
      fill(0);
      textSize(30);
      text("Score: " + score, 20, 50); // Displays the score in the top left corner 
      noCursor(); // Removes the cursor from the screen
    }
    
    void populate() {
      for (int i = 0; i < fX.length; i++) {
        if (swat[i] == 1) { // if swatted
          image(flybye, fX[i], fY[i]);
        } else {
          image(fly, fX[i], fY[i]);
        }
      }
    }
    
    void collisionDetect() {
      for (int i = 0; i < swat.length; i++) {
        if (mouseX > fX[i] && mouseX < fX[i] + fly.width &&
            mouseY > fY[i] && mouseY < fY[i] + fly.height &&
            // also check this fly has not been swatted (yet)
            swat[i] == 0) {
              swat[i] = 1;
              fX = append(fX, random(width));
              fY = append(fY, random(height));
              swat = append(swat, 0);
              score++;
              }
      } 
    }
    
    void mousePressed() {
      collisionDetect();
    }
    

    The other things that could be improved:

    • formatting: you can use Ctrl+T / CMD+T to tidy up code. This makes it easier to read and it's a good habbit to have. On the long run you'll spend more time reading/understanding code than writing code. Even revisiting your own code in 2 weeks or more will be easier if you format/comment/etc. and make the life of your future self easier
    • you can avoid copy/pasted code by encapsulating reusable blocks of code. In this case adding a fly (once in setup, on collision), but also the conditional for checking a collision could be encapsulated in a function you can re-use in any other sketch easily.

    e.g.

    PImage fly, flybye, swatter, swatted;
    float[] fX, fY; // Declaring fX & fY location arrays
    int[] swat;
    int score = 0;
    
    void setup() {
      size(800, 400);
      noCursor(); // Removes the cursor from the screen
      // Images
      fly = loadImage("fly.png");
      fly.resize(50, 0);
      flybye = loadImage("flybye.png");
      flybye.resize(50, 0);
      swatter = loadImage("swatter.png");
      swatted = loadImage("swatted.png");
      
      fX = new float[0];
      fY = new float[0];
      swat = new int[0];
    
      addFly();
    }
    
    void draw() {
      background(255);
      populate(); // Displays flys to the screen
      fill(0);
      textSize(30);
      text("Score: " + score, 20, 50); // Displays the score in the top left corner
    }
    
    void populate() {
      for (int i = 0; i < swat.length; i++) {
        if (swat[i] == 1) { // if swatted
          image(flybye, fX[i], fY[i]);
        } else {
          image(fly, fX[i], fY[i]);
        }
      }
    }
    
    void collisionDetect() {
      for (int i = 0; i < swat.length; i++) {
        if (isPointInRect(mouseX, mouseY, fX[i], fY[i], fly.width, fly.height) &&
          // also check this fly has not been swatted (yet)
          swat[i] == 0) {
          // mark this index as swatted
          swat[i] = 1;
          // increment score
          score++;
          // add new fly
          addFly();
        }
      }
    }
    
    void addFly() {
      fX = append(fX, random(width));
      fY = append(fY, random(height));
      swat = append(swat, 0);
    }
    
    boolean isPointInRect(int mx, int my, float rx, float ry, float rw, float rh) {
      return (mx >= rx && mx <= rx + rw) &&
             (my >= ry && my <= ry + rh);
    }
    
    void mousePressed() {
      collisionDetect();
    }
    

    Take it one step at a time. Sometimes, with code, slowing down/re-checking assumptions will get you over the line faster than rushing. Have fun !