Looking for more resources about ArrayLists

here is a non-running part from a much bigger Sketch that shows

  • how to show bullets (it’s from a player who shoots) and
  • how to remove the bullets (in a backward for-loop) that are dead (because they left the screen or hit something, then the variable dead in the class Explosion is set to true). The core idea is to set a variable dead and don’t display the bullet when dead is true. Then in the backward for-loop we remove the dead ones finally from the ArrayList.

Chrisir

void ExplosionManager() {

  // this is a new for loop.
  // Actually for the Shrapnels.
  for (Explosion m : missiles) {
    m.decreaseLife(); // call the decrease life (for explosion)
    m.fly();             // call the "fly" method of the missile
    m.display();      // call the "display" method of the missile
  }
  //
  // remove dead ones (you need to have a conventional for-loop here, backwards)
  for (int i=missiles.size()-1; i>=0; i--) {
    Explosion m = (Explosion) missiles.get(i);
    if (m.dead) {
      missiles.remove(i);
    }
  }
} // func
//

Somehow I missed your site in the returned results when I googled ArrayLists previously…
Thank you for this link!! It definitely adds to my understanding.
:nerd_face:

2 Likes

My thinking is to make grids that are contained within selected grid cells.
Pseudocode:
1/ make a base grid of cells
2/ then loop thru the base grid cells
3/ determine which grid cells would then be subdivided into a grid of smaller grid cells via random, modulo, probability, or another determinant
4/ then make a grid of cells that is contained within a cell’s width and height

I think I understand how to do the first three steps. I’m not sure how to implement step #4.

This code does run. And is starting to do what I want but not exactly.

  • The subdivided cells only remain during mousePressed, but I want the subdivisions to remain after mouse is pressed.

Code changes are in the mousePressed section.
:thinking: :thinking: :thinking:

ArrayList<PVector>resizeableGrid = new ArrayList();

ArrayList<PVector>subGrid = new ArrayList();

float tile;

void setup() {
  size (600, 600);

  tile = width/3;

  for (float x = 0; x <= width; x+=tile) {
    for (float y = 0; y <= height; y+=tile) {
      PVector pv = new PVector(x, y);
      resizeableGrid.add(pv);
    }
  }
}

void draw() {
  background(255);
  for (PVector pv : resizeableGrid) {
    stroke(0);
    rect(pv.x, pv.y, tile, tile);
  }
}

void mousePressed() {
  //   *** count thru array

  ArrayList<PVector>subGrid = new ArrayList();

  for (int i = 0; i < resizeableGrid.size(); i++) {
    PVector pv = resizeableGrid.get(i);

    // add a cell
    for (float x = 0; x <= width; x+=tile/2) {
      for (float y = 0; y <= height; y+=tile/2) {
        PVector pv2 = new PVector(x, y);
        subGrid.add(pv2);
      }
    }
    rect (pv.x/2, pv.y/2, tile/2, tile/2);
  }//for
}//func
//
1 Like

How to store the size of the rectangles

You could make a second parallel ArrayList holding the size of it‘s cells (the two ArrayLists being a way to hold data; this you would do later with a class and objects stored in the ArrayList)

This line

This line:

This line should better add the rect to the two Arraylists instead, so a new rect would be added to the ArrayLists and then be displayed in draw() throughout.

  • When you display a rectangle in mousePressed it flashes only briefly (when you use background() in draw()). So better add it to the lists that are displayed in draw() permanently.

Then in draw() use both lists to display rects with position and size.

Chrisir

1 Like

that could be done via mouse click as well (to select a cell to subdivide)

This new grid of cells could just go into the same ArrayList (if you store the rectangle’s size also). No matter whether you store the data in two parallel ArrayLists or in one ArrayList with a class: When you init the new sub-grid within a previous cell just assign the new sub-cells the right position and size. No need to come up with a new data structure or a new ArrayList.

Even setup and draw stay the same. Just how you sub-divide is new.

1 Like

This is definitely helpful info as I had been wondering about whether I need a second ArrayList to store the sub-divides. Thank you so much!!
:nerd_face:

1 Like

I don’t think you want me to do this for you

So I just wait what you come up with

1 Like

This is where I’ve arrived. MousePressed is set to add subGrid cells with each click.

However this is currently not displaying properly. And I can’t figure out why.
In this case, I am aiming to have no extra space between the subGrid cells.

The color is not really important, only being used as an indicator of subCell positions.

My primary question at this point is why the subCells are not always abutting each other? Some are and others are not…
:thinking:

ArrayList <GridCell> grid;
ArrayList <SubGrid> sub;
float w;
float y = 0;

void setup() {
  size (800, 400);
  noLoop();
  background (255);

  grid = new ArrayList <GridCell>();
  sub = new ArrayList <SubGrid>();

  w = width/8; 
  float h = height;

  for (float x = 0; x <= width; x+=w) {
    grid.add(new GridCell(x, y, w, h));
  }
}
void draw() {
  
  float h = width/8;

  for (int i = 0; i < grid.size(); i++) {
    grid.get(i).display();
  }  

  for (int j = 0; j < sub.size(); j++) {
    sub.get(j).display();
  }
}
void mousePressed() {

  sub = new ArrayList <SubGrid>();
  
  float w = width/8;
  float h = w;

  for (int i = 0; i < grid.size(); i++) {
    sub.add(new SubGrid(grid.get(i).x, y, w, h));
  }
  redraw();
  y = y+100;
}

MAIN GRID CLASS //////////////////////////////////

class GridCell{
  float x, y;
  float w, h;
  
  GridCell(float x_, float y_, float w_, float h_){
    x = x_;
    y = y_;
    w = w_;
    h = h_;
  }
  
  void display(){
    stroke(0);
    noFill();
    rect (x, y, w, h);
  }

SUBGRID CLASS //////////////////////////////

class SubGrid {
  float x, y;
  float w, h;

  SubGrid(float x_, float y_, float w_, float h_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;
  }

  void display() {
    stroke(0);
    fill(color(random(255), random(255), random(255)), 50);
    rect (x, y, w/2, h/2);
    rect (x, y/2, w/2, h/2);
    rect (x/2, y, w/2, h/2);
    rect (x/2, y/2, w/2, h/2);
  }
}
1 Like

Remark

sub = new ArrayList <SubGrid>(); //

this deletes the whole thing

Remark

without background (255); at start of draw() you see the accumulated results of all drawings.

You can’t really see what the last mousePressed did!

Remark

I think this doesn’t do what you want:

    rect (x, y, w/2, h/2);
    rect (x, y/2, w/2, h/2);
    rect (x/2, y, w/2, h/2);
    rect (x/2, y/2, w/2, h/2);

for example, the rects are called with

0.0 0.0
100.0 0.0
200.0 0.0
300.0 0.0
400.0 0.0
500.0 0.0
600.0 0.0
700.0 0.0
800.0 0.0

in the first round.

but e.g. this line rect (x/2, y, w/2, h/2); results in

   rect (0, 0, w/2, h/2);
   rect (50, 0, w/2, h/2);
   rect (100, 0, w/2, h/2);
   rect (150, 0, w/2, h/2);

so it’s far more left than the initial rect (x, y, w/2, h/2);

That’s why you see the gaps on the right.

Here is my version of the code section (one cell is divided into four cells):

    fill( 255, 0, 0 );
    rect (x, y, w/2, h/2);
    fill( 0, 255, 0);
    rect (x, y+h/2, w/2, h/2);
    fill( 0, 0, 255);
    rect (x+w/2, y, w/2, h/2);
    fill( 255, 0, 255);
    rect (x+w/2, y+h/2, w/2, h/2);

Full Sketch

Full Sketch to demonstrate some of the above

ArrayList <GridCell> grid;
ArrayList <SubGrid> sub;
float w;
float yNew = 0;

void setup() {
  size (800, 400);
  background (255);

  grid = new ArrayList <GridCell>();
  sub = new ArrayList <SubGrid>();

  w = width/8; 
  float h = height;

  for (float x = 0; x <= width; x+=w) {
    grid.add(new GridCell(x, 0, 
      w, h-=9));
  }
}

void draw() {
  background (255);

  //float h = width/8;

  for (int i = 0; i < grid.size(); i++) { // can use short form of for-loop here
    grid.get(i).display();
  }  

  for (int j = 0; j < sub.size(); j++) {// can use short form of for-loop here
    sub.get(j).display();
  }
}

//---------------------------------------------------------------------------------

void mousePressed() {

  sub = new ArrayList <SubGrid>(); // this deletes the whole thing 

  float w = width/8;
  float h = w;

  for (int i = 0; i < grid.size(); i++) {
    if (mouseX>grid.get(i).x&&
      mouseX<grid.get(i).x+w ) {
      sub.add(new SubGrid(grid.get(i).x, yNew, w, h));
    }
  }

  yNew = yNew+55;
}

//MAIN GRID CLASS //////////////////////////////////

class GridCell {
  float x, y;
  float w, h;

  GridCell(float x_, float y_, 
    float w_, float h_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;
  }

  void display() {
    stroke(0);
    noFill();
    rect (x, y, 
      w, h);
  }
}//class 

//SUBGRID CLASS //////////////////////////////

class SubGrid {

  float x, y;
  float w, h;
  color col1 = color(random(255), random(255), random(255), 50); // set random color at the start of the class, so we don't have a flickering color
  color col2 = color(random(255), random(255), random(255), 50); // set random color at the start of the class, so we don't have a flickering color

  SubGrid(float x_, float y_, 
    float w_, float h_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;
  }

  void display() {
    stroke(0);
    fill( 255, 0, 0 );
    rect (x, y, w/2, h/2);
    fill( 0, 255, 0);
    rect (x, y+h/2, w/2, h/2);
    fill( 0, 0, 255);
    rect (x+w/2, y, w/2, h/2);
    fill( 255, 0, 255);
    rect (x+w/2, y+h/2, w/2, h/2);
  }
}//class
//

Chrisir

2 Likes

Ah ha!! Ok now I see what’s going on. I was having a hard time trying to figure out how to anchor the x, y of the subGrid cells to the main grid cells. I can move forward with this now.
Thank you !!!
:nerd_face:

1 Like

As discussed, we don’t need a class SubGrid and ArrayList <SubGrid> sub at all; it would be possible to use ArrayList <GridCell> grid; for all of it!

I just made a Sketch that does just this.

Chrisir

3 Likes

I would love to see it if you want to share it…

1 Like

This is one of the directions I want to explore…

The core idea is that

  • we replace one cell with four cells that fill the space of the old cell
  • the calculation of the pos and size of the four new cells is done in mousePressed() and then just brought into the four new cells into the ArrayList. You had calculations in the class SubGrid . Not needed.
  • Did you notice that you can (like in the image) click in a cell, and then click in a sub-cell and then again in a sub-cell and so on?

Chrisir

ArrayList<GridCell> grid = new ArrayList<GridCell>();

void setup() {
  size(800, 800);
  background(255);

  final float w = width/4; 
  final float h = w;
  final color WHITE = color(255);

  for (float x = 0; x <= width; x+=w) {
    for (float y = 0; y <= height; y+=h) {
      grid.add(new GridCell(x, y, 
        w, h, 
        WHITE));
    }//for
  }//for
}//func

void draw() {
  background (255);

  for (int i = 0; i < grid.size(); i++) { // can use short form of for-loop here
    grid.get(i).display();
  }

  // need a backward for-loop to remove dead ones here !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  // can't use short form of for-loop here
}//func 

//---------------------------------------------------------------------------------

void mousePressed() {
  // search clicked cell:
  for (GridCell oldCell : grid) {  // short form of for-loop here
    // check mouse 
    if ( oldCell.onMouse() ) {
      // replace cell with 4 cells 
      grid.add(new GridCell(oldCell.x, oldCell.y, oldCell.w/2, oldCell.h/2, getRandomColor()));              // upper left corner (old pos)
      grid.add(new GridCell(oldCell.x+oldCell.w/2, oldCell.y, oldCell.w/2, oldCell.h/2, getRandomColor()));  // upper right corner 
      grid.add(new GridCell(oldCell.x, oldCell.y+oldCell.w/2, oldCell.w/2, oldCell.h/2, getRandomColor()));  // lower left corner 
      grid.add(new GridCell(oldCell.x+oldCell.w/2, oldCell.y+oldCell.w/2, oldCell.w/2, oldCell.h/2, getRandomColor())); // lower right corner
      // kill old cell
      oldCell.isDead=true;
      // leave here (we found ONE cell, that's enough)
      return;
    }//if
  }//for
}//func 

//---------------------------------------------------------------------------------

color getRandomColor() {
  return
    color(random(255), random(255), random(255));
}//func

//====================================================================================================
//MAIN GRID CLASS //////////////////////////////////

class GridCell {

  float x, y; // pos
  float w, h; // size 
  boolean isDead = false; 
  color col1     = color(255);

  // constr 
  GridCell(float x_, float y_, 
    float w_, float h_, 
    color col1_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;
    col1 = col1_;
  }// constr 

  void display() {
    if (isDead)
      return; // leave when it's dead - no displaying 

    stroke(0);
    fill(col1);
    rect (x, y, 
      w, h);
  }//method

  boolean onMouse() { 
    if (isDead)
      return false; // leave with false (mouse is never recognized on a dead cell)

    // this can return true or false: 
    return 
      mouseX>x   &&
      mouseX<x+w &&
      mouseY>y   &&
      mouseY<y+w;
  }//method
  //
}//class 
//
3 Likes

I see. This is starting to make more and more sense.
I think part of my problem has been transitioning from the regular array[] mind set to ArrayList mind set… ArrayList feels much more nebulous right now…
But seeing these examples is super helpful! :slight_smile: :slight_smile:
Many thanks again for your help!

1 Like

new version of same Sketch

Did you notice that you can (like in the image) click in a cell, and then click in a sub-cell and then again in a sub-cell and so on?

// New version 

ArrayList<GridCell> grid = new ArrayList<GridCell>();

void setup() {
  size(800, 800);
  background(255);

  final float w = width/4; 
  final float h = w;
  final color WHITE = color(255);

  for (float x = 0; x <= width; x+=w) {
    for (float y = 0; y <= height; y+=h) {
      grid.add(new GridCell(x, y, 
        w, h, 
        WHITE));
    }//for
  }//for
}//func

void draw() {
  background (255);

  // display all cells 
  for (GridCell currentCell : grid) { // can use short form of for-loop here
    currentCell.display();
  }//for

  // backward for-loop to remove dead ones here !! 
  // can't use short form of for-loop here
  // remove dead ones (you need to have a conventional for-loop here, backwards)
  for (int i=grid.size()-1; i>=0; i--) {
    if (grid.get(i).isDead) 
      grid.remove(i);
  }//for
}//func 

//---------------------------------------------------------------------------------

void mousePressed() {
  // search clicked cell:
  for (GridCell oldCell : grid) {  // short form of for-loop here
    // check mouse 
    if ( oldCell.onMouse() ) {
      // replace cell with 4 cells 
      grid.add(oldCell.getUpperLeftCorner());   // upper left corner (old pos)
      grid.add(oldCell.getUpperRightCorner());  // upper right corner 
      grid.add(oldCell.getLowerLeftCorner());   // lower left corner 
      grid.add(oldCell.getLowerRightCorner());  // lower right corner
      // kill old cell
      oldCell.isDead=true;
      // leave here (we found ONE cell, that's enough)
      return;
    }//if
  }//for
}//func 

//---------------------------------------------------------------------------------

color getRandomColor() {
  return
    color(random(255), random(255), random(255));
}//func

//====================================================================================================
//MAIN GRID CLASS //////////////////////////////////

class GridCell {

  float x, y; // pos
  float w, h; // size 
  boolean isDead = false; 
  color col1     = color(255);

  // constr 
  GridCell(float x_, float y_, 
    float w_, float h_, 
    color col1_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;
    col1 = col1_;
  }// constr 

  void display() {
    if (isDead)
      return; // leave when it's dead - no displaying 

    stroke(0);
    fill(col1);
    rect (x, y, 
      w, h);
  }//method

  boolean onMouse() { 
    if (isDead)
      return false; // leave with false (mouse is never recognized on a dead cell)

    // this can return true or false: 
    return 
      mouseX>x   &&
      mouseX<x+w &&
      mouseY>y   &&
      mouseY<y+w;
  }//method

  //--- make child cells (all with w/2) 

  GridCell getUpperLeftCorner() {  
    // upper left corner (old pos) 
    return new GridCell(x, y, 
      w/2, h/2, getRandomColor());
  } //method     

  GridCell getUpperRightCorner() {
    // upper right corner (x changed)
    return new GridCell(x+w/2, y, 
      w/2, h/2, getRandomColor());
  } //method

  GridCell getLowerLeftCorner() {
    // lower left corner (y changed) 
    return new GridCell(x, y+w/2, 
      w/2, h/2, getRandomColor());
  } //method

  GridCell getLowerRightCorner() {
    // lower right corner (x and y changed)
    return  new GridCell(x+w/2, y+w/2, 
      w/2, h/2, getRandomColor());
  } //method
  // 
  // ---
  //
}//class 
//
3 Likes

I did notice that! :slight_smile:
And the new version is very easy to parse through. All versions have been extremely helpful!! I definitely appreciate your time spent explaining this!
:nerd_face:

1 Like

This is so cool, almost like a fractal.

1 Like

I’ve been going through the code line for line. And I do understand almost all.

However, not clear to me is: boolean isDead, where there are 2 instances.

I noted next to the lines in question what I think is happening, but I am not sure this is correct. :thinking: :thinking: :thinking:
:nerd_face:

The first instance in display():
I think this is a flow related question…

And second instance, in boolean onMouse:

2 Likes