Search code examples
javaarraylistmethods2d-games

If statement ignores return method, other solutions?


I have a class called Cells and in it I have an update method that runs this piece of code:

if(goalReached){
  if(returnNearestCell() > -1 && isTarget && this.checkCollide(cells.get(returnNearestCell()).x, cells.get(returnNearestCell()).y, cells.get(returnNearestCell()).mass)){
    addMass(cells.get(returnNearestCell()).mass);
    cells.get(returnNearestCell()).mass = 20;
    cells.get(returnNearestCell()).x = (int) Math.floor(Math.random() * 1001);
    cells.get(returnNearestCell()).y = (int) Math.floor(Math.random() * 701);
    isTarget = false;
  }
  if(returnNearestCell() > -1 && !isTarget){
    goalX = cells.get(returnNearestCell()).x; 
    goalY = cells.get(returnNearestCell()).y; 
    target = cells.indexOf(returnNearestCell());
    isTarget = true;

  }else if(returnNearestCell() == -1 ){ 
    goalX = (int) Math.floor(Math.random() * 1001);
    goalY = (int) Math.floor(Math.random() * 701);
    isTarget = false;
  }
  if(!isTarget){
    addMass(5);
  }
  goalReached = false;
}

Basically to sum it up, each cell looks for the nearest cell with a smaller mass and if a cell is found then set the goalX and goalY to the position of that cell. If no such cell with the same criteria is found then just go to a random position. The code works fine until for some reason the first if statement gets ignored:

returnNearestCell() > -1

Then I get an ArrayIndexOutOfBoundsException.

My returnNearestCell method goes as follows:

public int returnNearestCell(){

int x = 0;
int distance = 9999999;
int min = distance;

for(Cell cell : cells){
  if(this != cell){
    distance = (int)Math.sqrt((this.x - cell.x)*(this.x - cell.x ) + (cell.y - this.y)*(cell.y  - this.y));
    if(distance < min && this.mass > cell.mass + 10){
      min = distance;
      x = cells.indexOf(cell);
    }else if(distance < min && this.mass < cell.mass + 10 && cell.cellCount == cells.size()){
      x = -1;
    }
  }
}

return x;
}

This method returns the index of the cell with the criteria or -1. My question is: Is there any way to avoid this OutofBoundsException? I've tried multiple methods like doing a double check but I still get the same issue.


Solution

  • cells.get(returnNearestCell()).mass = 20;
    cells.get(returnNearestCell()).x = (int) Math.floor(Math.random() * 1001);
    cells.get(returnNearestCell()).y = (int) Math.floor(Math.random() * 701);
    

    Here, you are mutating the cell and then call returnNearestCell() again. Since that method now runs with the changed parameters, the return value is possibly different. Most importantly, you shift the cell along the x coordinate and it is then in a different position when evaluated by the next call to returnNearestCell().

    You might want to look up non-atomic updates and concurrent modification for more on this topic.

    Is there any way to store an object into a variable and access it through that variable?

    Yes and it's the solution to your problem:

    if (goalReached) {
       // retrieve nearest cell once before modification
       final int nearestCellIndex = returnNearestCell();
       if (nearestCellIndex > -1 && isTarget) {
           // save cell.
           final Cell nearestCell = cells.get(nearestCellIndex);
    
           if (this.checkCollide(nearestCell.x, nearestCell.y, nearestCell.mass)) {
    
                // remainder of your code
           }
       }
    }
    

    Note that it is probably preferable to have returnNearestCell() return Optional<Cell> or at least a Cell object directly. Same goes for checkCollide() which could simply take a Cell object as parameter.