Rectangle Collision in ArrayList

Hi everybody,
this is my first post. I am new to Processing and therefor having some trouble with a game that I am supposed to code in college.
Also, please excuse my bad English, I am from Germany :wink:

In my coding class, I am supposed to program the game “Rush Hour”, where in a grid, I have to manouvre a red car out of a traffic jam (https://www.youtube.com/watch?v=HI0rlp7tiZ0).

Now, I am having trouble with checking, if cars are colliding while moving. I did some research, but I honestly have no clue on how to check the collisions between the cars. I arranged them as objects in an ArrayList, do you have any tips/solutions for me? I am desperate right now…
Here are the classes, that are crucial for my problem:
class Level:

class Level
{
  // Cars Legende: (int name, posX,posY,r,g,b,vertical,truck)


  int cellSize=80;
  int cellNumber=6;
  int checkKey;
  boolean win;

  public ArrayList<Cars> carArray = new ArrayList<Cars>();

  //Rotes Auto (immer Name '42')
  Cars carRed= new Cars(42, (width/2)-2*this.cellSize, height/2-this.cellSize, 255, 0, 0, false, false);








  Level()
  {

    //Autos in ArrayList einfügen // Cars Legende: (int name, posX,posY,r,g,b,vertical,truck)
    //Trucks
    carArray.add(new Cars(1, width/2-2*this.cellSize, height/2, 0, 255, 0, false, true));
    carArray.add(new Cars(2, width/2-3*this.cellSize, height/2-2*this.cellSize, 255, 0, 255, true, true));
    carArray.add(new Cars(3, width/2, height/2-3*this.cellSize, 0, 255, 255, true, true));
    carArray.add(new Cars(4, width/2+this.cellSize, height/2-2*this.cellSize, 0, 0, 255, true, true));

    //Autos
    carArray.add(new Cars(5, width/2-3*this.cellSize, height/2+this.cellSize, 100, 100, 50, true, false)); 
    carArray.add(new Cars(6, width/2+this.cellSize, height/2+2*this.cellSize, 150, 200, 0, false, false));
    carArray.add(new Cars(7, width/2+this.cellSize, height/2+this.cellSize, 50, 200, 0, false, false));
    carArray.add(new Cars(8, width/2+2*this.cellSize, height/2-this.cellSize, 100, 100, 100, true, false));
    carArray.add(new Cars(9, width/2+2*this.cellSize, height/2-3*this.cellSize, 255, 255, 0, true, false));
    carArray.add(new Cars(10, width/2-3*this.cellSize, height/2-3*this.cellSize, 0, 150, 0, false, false));
  }

  void update()
  {

    //Spielfeld
    this.matchField();

    //rotes Auto einsetzen
    carRed.update();

    //restliche Autos aus Array anzeigen
    for (int i=0; i<=carArray.size()-1; i++)
    {
      Cars car=carArray.get(i);
      car.update();
    }
    // Autos dürfen nicht aus dem Spielfeld rausfahren
    this.checkBoundaries();

    //Autos bewegen
    this.checkKeyPressed();
    this.movement();
  }






  public void checkMousePressed()
  {
    if (mousePressed)
    {
      println("mouse level");
    }
  }


  public void matchField()

  {
    //Textanweisung
    textAlign(CENTER);
    text("Drive the red car to the right!", width/2, 10);

    //Spielfeld
    stroke(250);
    strokeWeight(4);
    fill(200);
    rectMode(CENTER);
    rect(width/2, height/2, this.cellSize*this.cellNumber, this.cellSize*this.cellNumber);
    fill(0);

    //Karo Muster
    for (int i=(width/2-(this.cellSize*this.cellNumber/2)); i<=(width/2+(this.cellSize*this.cellNumber/2)); i=i+this.cellSize)
    {

      line(i, height/2-(this.cellSize*this.cellNumber/2), i, ((height/2)+this.cellNumber/2*this.cellSize));
      for (int j=(height/2-(this.cellSize*this.cellNumber/2)); j<=(height/2+(this.cellSize*this.cellNumber/2)); j=j+this.cellSize)
      {
        line(width/2-this.cellSize*this.cellNumber/2, j, width/2+this.cellSize*this.cellNumber/2, j);
      }
    }

    //Ausgang
    stroke(200);
    line(width/2+this.cellNumber/2*this.cellSize, height/2-this.cellSize+4, width/2+this.cellNumber/2*this.cellSize, height/2-4);
  }

  public void checkBoundaries()
  {
    for (int i=0; i<=carArray.size()-1; i++)
    {
      Cars car=carArray.get(i);
      if (car.vertical)
      {
        if (car.truck)
        {
          if (car.posY<=(height/2-(this.cellSize*this.cellNumber/2)))
          {
            car.posY=(height/2-(this.cellSize*this.cellNumber/2));
          } else if (car.posY+3*this.cellSize>=height/2+(this.cellSize*this.cellNumber/2))
          {
            car.posY=height/2;
          }
        } else
        {
          if (car.posY<=(height/2-(this.cellSize*this.cellNumber/2)))
          {
            car.posY=(height/2-(this.cellSize*this.cellNumber/2));
          } else if (car.posY+2*this.cellSize>=height/2+(this.cellSize*this.cellNumber/2))
          {
            car.posY=(height/2+this.cellSize);
          }
        }
      }
      if (!car.vertical)
      {
        if (car.truck)
        {
          if (car.posX<=(width/2-(this.cellSize*this.cellNumber/2)))
          {
            car.posX=(width/2-(this.cellSize*this.cellNumber/2));
          } else if (car.posX+3*this.cellSize>=width/2+(this.cellSize*this.cellNumber/2))
          {
            car.posX=width/2;
          }
        } else
        {
          if (car.posX<=(width/2-(this.cellSize*this.cellNumber/2)))
          {
            car.posX=(width/2-(this.cellSize*this.cellNumber/2));
          } else if (car.posX+2*this.cellSize>=height/2+(this.cellSize*this.cellNumber/2))
          {
            car.posX=(height/2+this.cellSize);
          }
        }
      }
    }
  }

  public void checkKeyPressed()
  {
    if (keyPressed)
    {
      switch(key)
      {
      case '1':  
        this.checkKey=1;
        println(this.checkKey);
        break;
      case '2':  
        this.checkKey=2;
        println(this.checkKey);
        break;
      case '3':  
        this.checkKey=3;
        println(this.checkKey);
        break;
      case '4':  
        this.checkKey=4;
        println(this.checkKey);
        break;
      case '5':  
        this.checkKey=5;
        println(this.checkKey);
        break;
      case '6':  
        this.checkKey=6;
        println(this.checkKey);
        break;
      case '7':  
        this.checkKey=7;
        println(this.checkKey);
        break;
      case '8':  
        this.checkKey=8;
        println(this.checkKey);
        break;
      case '9':  
        this.checkKey=9;
        println(this.checkKey);
        break;
      case '0':  
        this.checkKey=10;
        println(this.checkKey);
        break;
      case 'ß':  
        this.checkKey=11;
        println(this.checkKey);
        break;
      case 'r':  
        this.checkKey=42;
        println(this.checkKey);
        break;
      }
    }
  }

  public void movement()
  {
    switch(this.checkKey)
    {
    case 1: 
      this.carArray.get(0).checkKeyPressed();
      break;
    case 2: 
      this.carArray.get(1).checkKeyPressed();
      break;
    case 3: 
      this.carArray.get(2).checkKeyPressed();
      break;
    case 4: 
      this.carArray.get(3).checkKeyPressed();
      break;
    case 5: 
      this.carArray.get(4).checkKeyPressed();
      break;
    case 6: 
      this.carArray.get(5).checkKeyPressed();
      break;
    case 7: 
      this.carArray.get(6).checkKeyPressed();
      break;
    case 8: 
      this.carArray.get(7).checkKeyPressed();
      break;
    case 9: 
      this.carArray.get(8).checkKeyPressed();
      break;
    case 10: 
      this.carArray.get(9).checkKeyPressed();
      break;
    case 42: 
      this.carRed.checkKeyPressed();
      break;
    }
  }


  public void checkCollision()
  {

    boolean hit=collision();

    if (hit) {
    }
    {
    }
  }

  public boolean collision()
  {
    return false;
  }
}

and here is the “Cars” class:

class Cars
{
  int cellSize=80; 
  int round= 15;                        //Eckenrundung
  int opacity=90;                       //Transparenz
  int move=2;                          //Bewegung
  int name;                            // Für Auswählen des Autos
  int posX;                          // X-Position des Autos
  int posY;                         // Y-Position des Autos
  int w;                            // Auto Breite
  int h;                            // Auto Höhe
  int r;            //RGB Werte für Farbe
  int g;
  int b;
  boolean vertical;  //setzt die Ausrichtung des Autos
  boolean truck;      // Setzt die Länge des Autos


  Cars()
  {
  }
  //Konstruktor für die Autos
  Cars(int name, int posX, int posY, int r, int g, int b, boolean vertical, boolean truck)
  {
    this.name=name;
    this.posX=posX;
    this.posY=posY;
    this.r=r;
    this.g=g;
    this.b=b;
    this.vertical=vertical;
    this.truck=truck;
  }

  public void update()
  {
    push();
    fill(this.r, this.g, this.b, this.opacity);
    rectMode(CORNER);

    //Autos zeichnen
    
    if (this.vertical)
    {
      if (this.truck)
      {
        this.w=this.cellSize;
        this.h=3*this.cellSize;
        rect(this.posX, this.posY, this.w, this.h, this.round);
        textAlign(CENTER);
        textSize(32);
        fill(0);
        strokeWeight(2);
        text(this.name, this.posX+this.cellSize/2, this.posY+1.5*this.cellSize);
      } else
      {
        this.w=this.cellSize;
        this.h=2*this.cellSize;
        rect(this.posX, this.posY, this.w, this.h, this.round);
        textAlign(CENTER);
        textSize(32);
        fill(0);
        strokeWeight(2);
        text(this.name, this.posX+this.cellSize/2, this.posY+this.cellSize);
      }
    } else if (this.truck)
    {
      this.w=3*this.cellSize;
      this.h=this.cellSize;
      rect(this.posX, this.posY, this.w, this.h, this.round);
      textAlign(CENTER);
      textSize(32);
      fill(0);
      strokeWeight(2);
      text(this.name, this.posX+1.5*this.cellSize, this.posY+this.cellSize/2);
    } else
    {
      this.w=2*this.cellSize;
      this.h=this.cellSize;
      rect(this.posX, this.posY, this.w, this.h, this.round);
      textAlign(CENTER);
      textSize(32);
      fill(0);
      strokeWeight(2);
      text(this.name, this.posX+this.cellSize, this.posY+this.cellSize/2);
    }
    pop();

    
  }



  public void checkKeyPressed()
  {
    if (keyPressed)
    {
      if (this.vertical==true)
      {
        if (key=='w')
        {
          this.posY=this.posY-this.move;
        }
        if (key=='s')
        {
          this.posY=this.posY+this.move;
        }
      } else
      {
        if (key=='a')
        {
          this.posX=this.posX-this.move;
        }
        if (key=='d')
        {
          this.posX=this.posX+this.move;
        }
      }
    }
  }
}

If you need more information or the whole Processing file, feel free to ask for it!

Thank you VERY much!

Greetings from Germany

1 Like

you have to use nested loops. Other tools you may want to add to speed up efficiency are quadtrees or quadgrid, but thats not likely what you are looking for.

To begin, cosider the box you are checking, you now have to check that box to every other box.

If you have the one arraylist then you check one item against nothing by simply looping once.

ie

for (int i=0;i<boxes.size();i++){
  
   //Box refers to a arbitrary Box class not attached with sketch
   Box b = boxes.get(i);  
  // add any other code
}

now if you want the boxes to check other boxes you have to loop through all the boxes once again.

for (int i=0;i<boxes.size();i++){
  
   //Box refers to a arbitrary Box class not attached with sketch
   Box b = boxes.get(i);  
  // add any other code
for (int j=0;j<boxes.size();j++){
  Box b1 = boxes.get(j);
  
 // here you would add you check code;
 boolean collide = b.compare(b1);

 if(collide){
//do something
}
}}

the code to check collision should be fairly simple.

you want to know if any of the four bounding points are overlapping with any of the other squares lines.

ie

boolean compare(Box a){

return x > a.x && x < a.x + a.width && y > a.y && y < y + y.height||

          x + width > a.x && x + width < a.x + a.width && y > a.y && y < y + y.height||

          x + width > a.x && x + width < a.x + a.width && y + height > a.y && y + height< y + y.height||

x > a.x && x < a.x + a.width && y + height > a.y && y + height< y + y.height||
}

I think that should be it.

or you can try line line collisions which are a little bit more complex but will also do the job.

in general I would recommend reading through this blog post.

1 Like

Actually, the inner for loop could start at i+1 instead of 0

1 Like

Thank you for your answers! Now, I’m trying to figure out the code in the boolean compare(Box A) method. Am I right if I’m assuming, that I have to put that method in my “Cars” class? Then, for example “x” would be referring to “this.posX” (in my case), right? But what should I type for y.height? I’m very confused, right now.

Also, with “Boxes” you are referring to the Cars-Class and my carArray-List (for boxes-Arraylist), am I right?

the box class refers to any arbitrary rectangle shape, if that happens to be your car, then great.

The box a function just takes a class as a parameter in this case box, which will have 4 checkable sides. hence the 4 lines,

a box has four points, defined by (x,y),(x + width,y),(x+width,y+height),(x,y+height) in clockwise order, therefore you have to check all four points are inside the other rectangle.

Please note this is assuming no rotation is happening on the boxes.