How to remove array object when mouse pressed

Hello Dear Processors, thank you for your time. So I am trying to remove images from an array when mouseX and mouseY is directly in top of the image. how do i do that. So fare I have the code that detects when the mouse is in top of the image like so.

if (mouseX > x && mouseX < x + w * randomSize && mouseY > y 
        && mouseY < y + h { }

Are you familiar with classes? You can create a class that contain the following fields:

  • PosX
  • PosY
  • PImage
  • showFlag

The last item is used to show or hide the image in the sketch. More about objects here. After you define your class, you can use an ArrayList to manage all these objects.

Kf

Yes, I have my class defined. I just want to learn how to remove items from and array. I am looking into arrayList

If you intend to use method remove(), it’s important you iterate over the Collection backwards. :back:

like this for (int i = bottles.length-1; i>=0; i–) {} i am having another issue with the remove
my code is long but please be patient; look for void removebottle() inside the class

ArrayList<Trash> trash ;
//Trash[] trash = new Trash[5];
PImage[] bottles = new PImage[3];
float time = 0;
PImage img;
PImage fish;

void setup() {
  size(640, 640);
  fish = loadImage("fish.png");
  img = loadImage("aceituna.png");
  trash = new ArrayList<Trash>();
  for (int i = 0; i < bottles.length; i++) {
    bottles[i] = loadImage("water-bottle-"+i+".png");
  }
  for (int i = 0; i < 5; i++) {
    int index = (int(random(0, bottles.length))); 
    trash.add(new Trash(bottles[index], 120+i*100, 645, random (32, 72)));
  }
}

void draw() {
  background(30);

  noStroke();
  fill(0);
  rect(0, height/2, width, height/2);

  for (Trash part : trash) {
    part.fish();
    part.bouncingseagal();
    part.move();
    part.removebottle();
    part.display();
  }

  //waves
  float x = 0;
  stroke(30); 
  strokeWeight(10);
  while (x < width) {
    point(x, 285+50 *noise(x / 100, time));
    point(x, 295+50 *noise(x / 100, time));
    point(x, 310+50 *noise(x / 100, time));
    x = x + 1;
  }
  time = time + 0.02;
}
class Trash {
  float x;
  float y;
  float speedY = 0.5;
  float randomSize;
  float offSetThis = 10; 
  float scalarThis = 3; 
  float yay;
  float diamW = int(900/400), diamH = int(800/400);

  PImage bottle;
  float upDown = 0.0;
  float speedTrash =.04; 

  //seagal

  float xE = 0;
  float yE = 0;
  float ellipseXSpeed = 1;
  float ellipseYSpeed = 1.4;

  //fish variables

  float xLoc = -250;
  float yLoc = 400; 
  float angle = 0.0;
  float offset = 150; 
  float scalar = 50; 
  float speed =.04; 
  boolean gLeft, gRight;

  //rectangel
  int rectW = width;
  int rectH = height/2;
  int rectX = 0, rectY = height/2;

  Trash(PImage tempImg, float tempX, float tempY, float tempD) {
    x = tempX;
    y = tempY;
    randomSize = tempD;
    bottle = tempImg;
  }

  void fish() {
    randomSeed(0);
    int wW = int (320/3);
    int wH = int (215/3);
    int r = (int) random(-5, 5);
    float y1 = offset + sin(angle) * scalar;
    float y2 = offset + sin(angle + .4) * scalar;
    float y3 = offset + sin(angle + .8) * scalar;
    float y4 = offset + sin(angle + 1.2) * scalar;

    if (mouseX > xLoc+r && mouseX < xLoc+r + wW*r && mouseY > yLoc+y1
      && mouseY < yLoc+y1 + wH*r) {
      tint(255, 0, 0);
    } else {
      noTint();
    }

    image(fish, xLoc+r, yLoc+y1, wW*r, wH*r);
    image(fish, xLoc+r, yLoc+y2, wW, wH);
    image(fish, xLoc+150, yLoc+y3+50, wW*r, wH*r);
    image(fish, xLoc+50, yLoc+y4, wW, wH);

    angle += speed; 

    if (y + rectH >= height/2) {
      gRight = true;
      xLoc++;

      if (xLoc <= -100) {
        gRight = true;
        gLeft = false;
      } 
      if ( gRight == true) {
        xLoc = xLoc+2;
      }

      if (xLoc + wW >= width + wW * 2) {
        gLeft = true;
        xLoc = xLoc *-1;
      }

      if (xLoc > width + wW * 2) {
        gLeft = true;
        gRight = false;
      }

      if (gLeft == true) {
        xLoc--;
      }
    }
  }
  void bouncingseagal() {

    int w = int(370/3);
    int h = int(215/3);
    smooth();
    imageMode(CORNER);
    noTint();
    image(img, xE, yE, w, h);

    xE += ellipseXSpeed;
    yE += ellipseYSpeed;

    if (xE < 0 || xE + w/2 > width - w/2) {
      ellipseXSpeed *= -1;
    }
    if (yE < 0 || yE + h/2 > height/2 - h/2) {
      ellipseYSpeed *= -1;
    }
    //detect moving square
    //if (xE+s+ellipseXSpeed > x && xE + ellipseXSpeed < x+diamW
    //  && yE+s>y && yE < y + diamH) {
    //  ellipseXSpeed *= -1;
    //}
    //if ( xE + s > x && xE < x + diamW && yE + s + ellipseYSpeed > y
    //  &&yE + ellipseYSpeed < y + diamH) {
    //  ellipseYSpeed *= -1;
    //}
  }

  void move() { 
    if (y + diamH > height) {
      speedY *= 1;
    }
    y--;
    if (y + diamH < height/2 + 40) {
      y = y + y;
      speedY *= -1;
    }
  }

  void removebottle() {
    for (int i = bottles.length-1; i>=0; i--) {
      bottles[i] = bottles[i].get();
      if (mouseX > x && mouseX < x + diamW * randomSize && mouseY > y + yay
        && mouseY < y + yay + diamH * randomSize) { 
        trash.remove(i);
      }
    }
  }

  void display() {
    imageMode(CENTER);
    yay = offSetThis + sin(angle) * scalarThis;
    noTint();

    image(bottle, x, y+yay, diamW * randomSize, diamH * randomSize);
  }
}

As a general rule, load all of the assets your sketch is gonna use in setup(), before draw() begins, storing them in global variables. :bulb:

Classes should request already loaded assets rather than loading them on their own. :warning:

great , thanks. Made the change and it is now loading on setup.

this is the messy part , it shows a ConcurrentModificationException.

  void removebottle() {
    for (int i = bottles.length-1; i>=0; i--) {
      bottles[i] = bottles[i].get();
      if (mouseX > x && mouseX < x + diamW * randomSize && mouseY > y + yay
        && mouseY < y + yay + diamH * randomSize) { 
        trash.remove(i);
      }
    }
}

You loop over your bottles, but then call trash.remove(i).

Maybe try calling bottles.remove(i)?

the bottle (image) loop is made of 3 items, and the trash is made of 5. how can I make and arrayLIst

  for (int i = 0; i < 3; i++) {
    bottles[i] = loadImage("water-bottle-"+i+".png");
  }

As GoToLoop said, load your images in setup(). Once they are loaded and stored in PImage variables, DON’T DO ANYTHING WITH THEM except using them to draw that image.

If you want to make one of those images only appear some of the time - for example, when an object that uses that image is on the screen you want to draw the image and when that object is no longer on the screen then you want to stop drawing that image - then you need to use booleans or conditions to determine if an image should be drawn. You do NOT mess with the stored image at all! You simply stop drawing it.

PImage logo;

boolean draw_logo;

void setup() {
  size(300, 300);
  logo = loadImage("http://www.tfguy44.com/MyIcon1.PNG");
}

void draw() {
  background(196);
  if (draw_logo) {
    image(logo, 50, 50 );
  }
}

void mousePressed(){
  draw_logo = !draw_logo;
}

In this example, notice that the logo is loaded, but a boolean variable, draw_logo, tracks if it is actually used and drawn. There is no need to unload the image when I do not want to display it!

2 Likes

Hi

I went through your code and I think we need to do a bit of revamping. Unfortunately I do not know what your program does. However, I see that you have created a class and the class is not being used properly. Consider the following code:

PImage[] bottles = new PImage[3];

...  Other code not included

class Trash{

   ...  Other code not included

  void removebottle() {
    for (int i = bottles.length-1; i>=0; i--) {
      bottles[i] = bottles[i].get();
      if (mouseX > x && mouseX < x + diamW * randomSize && mouseY > y + yay
        && mouseY < y + yay + diamH * randomSize) { 
        trash.remove(i);
      }
    }

}

In the above code, you are accessing a variable that is not defined inside your class (This also applies to fish and the img object - used in the bouncingseagal() function). This breaks one of the basic concepts of OOP: encapsulation. In other words, this should not be done. The reason your code still works is because Processing provides a global environment (I won’t discuss the details here) which allows you to do this. However, because you can do it does not mean it is proper. :pensive:

My suggestion? Time to wear the designer’s hat and re-design your code. To do this, you need to take one step back :face_with_monocle: and start thinking about the different relationships between your components. I understand you have a trash. You put in the trash a fish, an aceituna (in the img object) and some bottles. So what I can see is that you have different trash objects and they all have different bottles but they have the same fish and the same img object. My first suggestion is to move the fish and img inside your trash can. Another suggestion is to move any method dealing with the fish and img objects outside the trash can. There is a third solution which is creating more classes. Which solution is the best? I cannot tell because I do not know the details of your design. If you share your thoughts about your code (why to have different trash objects with only different bottles) I will be able to provide a better direction.

Kf

2 Likes

Hello Kfrajer, Thank YOU! Ok so, I want to make a game where the bottles are the trash bouncing on the lower half of the screen. The whales (fish) are an obstacle because they block (make it hard) to click on the trash, I want them so that every time they are hovered over or clicked they are tinted in red. Also when the trash is clicked (depending on the amount of trash) the whales multiply. There is a crab (which i called sea gal) that i have bouncing around the upper middle part of the screen. Every time a bottle is picked a counter increases and coins appear according to the amount of points. the game ends when all the images of the coins appear.

Great, you have provided a brief description of your game. Can you write more details about it and also describe the interactions between each element? You know the game because you are the designer. If I were to play your game (actually for the matter, anybody that want to help you with your code), I do not have the minimum/essential details to work on the design. You need to separate the details for each element and describe their interactions. You have a crab, several fish and bottles and even coins. Let’s start with the bottles:

Bottles

  1. They are restricted to the lower half of the sketch
  2. One could click on them (What happen if you do?)
  3. Do they get tinted?
  4. How do they interact with:
    a. The fish
    b. The crab

Can you also describe the crab and the fish? How do they interact between each of them and also with the bottles. For instance: do they collide against each other? Also describe relevant mouse/key events associated to each element.

You also mentioned coins. Where do they come from? Are they clickable? What happen to them?

Also could we think about the name of your class Trash? Should it be called Trash or would Bottle be a better name?

At last, can you reflect on your current concept? Do you think a single class is good here or would you take a different approach based on the concept of encapsulation?

Kf

1 Like

The game is about catching trash. When you catch a bottle you get 10 points (some amount of points), but you also get bonuses if you catch them in less than 2 seconds(any amount of secs) as well as by speed. The obstacles for catching the bottles are the whales. Images of whales will simply block the mousePressed. Depending on the amount of points you get coin - images appear… and that’s where my design is left at… will think of it more, maybe. I have rewritten the code.

Game game;
Whale whale;
Crab crab;

float time = 0;

void setup() {
  size(640, 640);
  game = new Game();
  crab = new Crab();
  whale = new Whale();
  
  frameRate(60);
}

void draw() {
  background(30);
  noStroke();
  fill(0);
  rect(0, height/2, width, height/2);

  game.display();
  game.reward();

  whale.display();
  crab.display();
}

void mousePressed() {
  game.trash();
}

thank you for your time. Would you like to read any of the classes?

Hello I want to show you this class

class Crab {
  PImage img;
  float xE = 0;
  float yE = 0;
  int w = int(370/4);
  int h = int(215/4);
  float ellipseXSpeed = 1;
  float ellipseYSpeed = 1;

  float lastTimeChecked = millis();
  float counter = 40000.00;

  Crab() {
    img = loadImage("aceituna.png");
  }

  void crabWalk() {
    xE += ellipseXSpeed;
    yE += ellipseYSpeed;

    if (xE < 0 || xE + (w/2)  > (width) - w /2 ) {
      ellipseXSpeed *= -1;
    }
    if (yE < 0  || yE + (h/2)  > (height/2) - h / 2 ) {
      ellipseYSpeed *= -1;
    }

    if (millis()  > lastTimeChecked + counter) {     
      lastTimeChecked  = millis();     
      xE -= ellipseXSpeed;
    }
  }

  void display() {
    imageMode(CORNER);
    tint(255, 255);
    image(img, xE, yE, w, h);
  }
}

part where it says if (millis() > lastTimeChecked + counter) how come it does not work? I want to make the crab walk backwards every 4 seconds.

Hi tefa,

You counter variable is equal to 40000 so 40 seconds.
You want to set it to 4000.

1 Like

Hi @tefa

Thxs for sharing your classes. This is what I call “readable code”, which means it is easier to follow. Code like this is easier to debug and to maintain. Yes, you are right. From time to time it is good to rewrite your code, specially at this early stage when you are working with new concepts or you are introducing new features. I put your code above together and I got a running version.

I encourage you to see the following post: Random boxes and circles using array(s)

Just copy and paste it in a new sketch. You need to press the key up or down when the sketch is running to control the character there. Have a look at the Coin and Bomb classes and see if you can understand their connection and why they were put together that way. If you find it useful, and if you understand what is going on, you could implement it in your game. You don’t have to but more for you to see a different approach.

Kf

//Game game;
//Whale whale;
Crab crab;

float time = 0;

void setup() {
  size(640, 640);
  //game = new Game();
  crab = new Crab();
  //whale = new Whale();

  frameRate(60);
}

void draw() {
  background(30);
  noStroke();
  fill(0);
  rect(0, height/2, width, height/2);

  //game.display();
  //game.reward();

  //whale.display();
  crab.crabWalk();
  crab.display();
}

void mousePressed() {
  //game.trash();
}

class Crab {
  PImage img;
  float xE = 0;
  float yE = 0;
  int w = int(370/4);
  int h = int(215/4);
  float ellipseXSpeed = 1;
  float ellipseYSpeed = 1;

  float lastTimeChecked;
  float counter = 4000.00;

  Crab() {
    lastTimeChecked = millis();
    img = createAnImage(w, h, color(255, 0, 0), color(150, 150, 0)); //loadImage("aceituna.png");
  }

  void crabWalk() {
    xE += ellipseXSpeed;
    yE += ellipseYSpeed;

    boolean dirChange=false;
    if (xE < 0 || xE + (w/2)  > (width) - w /2 ) {
      ellipseXSpeed *= -1;
      xE %= width;
      dirChange=true;
    }
    if (yE < 0  || yE + (h/2)  > (height/2) - h / 2 ) {
      ellipseYSpeed *= -1;
      yE %= height;
      dirChange=true;
    }

    //Only perform next if the direction was not change recently. Avoids some glitches ocurring duringedge checking 
    if (!dirChange && millis()  > lastTimeChecked + counter) {     
      lastTimeChecked  = millis();     
      //xE -= ellipseXSpeed;
      ellipseXSpeed *= -1;
    }
  }

  void display() {
    imageMode(CORNER);
    tint(255, 255);
    image(img, xE, yE, w, h);
  }

  PImage createAnImage(int w, int h, color c1, color c2) {

    PImage imgx=createImage(w, h, ARGB);
    imgx.loadPixels();
    for (int i=0; i<w*h; i++) {
      imgx.pixels[i]=lerpColor(c1, c2, (i%w)/float(w));
    }
    imgx.updatePixels();

    return imgx;
  }
}

1 Like