LibGDX - Collisions using Rectangles inside ArrayLists with Iterator

Hello all, thanks for taking the time to help me out.

I’m trying to make a top down space shooter where you shoot asteroids as you fly through space.

I’m using a similar method as in the LibGDX tutorial for making the ‘Drop’ game for generating asteroids and having them fall down the screen, as well as adding the asteroids to an ArrayList to keep track of all of them as well as remove them if necessary.

I’m using that same method for keeping track of the shots that the player fires.

The problem isn’t in when the asteroids collide with the player, but having the asteroids collide with the bullets.

This is the first part of the approach that I’m taking to this, the iterator: my problem is that I’m unable to say

if(asteroid.overlaps(shot)) { iter.remove(); }

because the shots and asteroids are declared locally in their spawn methods…

		Iterator<Rectangle> iter = asteroids.iterator();
		while(iter.hasNext()) {
			Rectangle asteroid = iter.next();
			asteroid.y -= 200 * Gdx.graphics.getDeltaTime();
			if(asteroid.y < -64) {
				iter.remove();
			}
			if(asteroid.overlaps(playerShip)) {
				//
				iter.remove();
			}

  		}
		
		Iterator<Rectangle> shotIter = shots.iterator();
		while(shotIter.hasNext()) {
			Rectangle shot = shotIter.next();
			shot.y += 500 * Gdx.graphics.getDeltaTime();
			if(shot.y > 600) {
				shotIter.remove();
			}

		}
	public void fire() {
		Rectangle shot = new Rectangle();
		shot.x = playerShip.x + 26;
		shot.y = playerShip.y + 32;
		shot.width = 32;
		shot.height = 32;
		shots.add(shot);
		lastFired = TimeUtils.nanoTime();
		
	}
	
	public void spawnAsteroid() {
		Rectangle asteroid = new Rectangle();
		asteroid.x = MathUtils.random(600 - 64);
		asteroid.y = 320;
		asteroid.width = 64;
		asteroid.height = 64;
		asteroids.add(asteroid);
		lastAsteroid = TimeUtils.nanoTime();
	}

Are there any suggestions or should is there another beginner-friendly way to manage collisions like this?

I know it’s messy but I’m very new to Java game development (but not to Java itself)

Not sure what the problem is. You have the shots and asteroids in separate lists, you can check if any of them overlap.

I get a runtime error and the game crashes when I try to do that.

Can you post your error? I can’t find any flaw in the code you posted.

It seems to me that your problem is the position in the code of your


if(asteroid.overlaps(shot)) { iter.remove(); }

A solution would be:


Iterator<Rectangle> iter = asteroids.iterator();
      while(iter.hasNext()) {
          Rectangle asteroid = iter.next();
          if(asteroid.y < -64 || asteroid.overlaps(playerShip)) {
              iter.remove(); continue(); // We continue because the asteroid has been remove & can't collide with a Shot
          }
          Iterator<Rectangle> shotIter = shots.iterator();  // Loop of shots to check if they collide with the asteroid
          while(shotIter.hasNext()) {
              Rectangle shot = shotIter.next();
              if(shot.y > 600) { 
                  shotIter.remove(); continue; // Remove the bullets as it is out of screen 
              if(asteroid.overlaps(shot)) {
                  shotIter.remove(); iter.remove(); break; // Again no need to check for further collisions with this asteroid because it has been removed
              }
         }
      }

@Drabla Check the last iteration. You should not break, you should continue.


-    shotIter.remove(); iter.remove(); break;
+    shotIter.remove(); iter.remove(); continue;

Hmm.

It tought of it this way:

Loop Asteroids {
Loop Shoots {
checkForCollisions(); remove Asteroid && Shoot;

If the collision happens: We remove the asteroid and the shot.
If we would continue; we would just check collisions with the next bullet, but the same asteroid (that we just removed).
If we break; we leave the shots loop and skip to the next asteroid.

Or do i just have a big brain f*rt? :slight_smile:

Yeah, didn’t notice it. But one thing again.

Your code


if (shot.y > 600 || asteroid.overlaps(shot))
{
    shotIter.remove();
    iter.remove();
    break;
}

Had a problem. It kills both the shot and the asteroid even if the shot moves out of screen without happening collision.

Ah there you got me :wink:
Fixed.
Thanks!

I’m sure you didn’t, else you would have most certainly posted the error.

Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: java.lang.Error: Unresolved compilation problem: 
	The method overlaps(Rectangle) is undefined for the type ArrayList<Rectangle>

	at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)
Caused by: java.lang.Error: Unresolved compilation problem: 
	The method overlaps(Rectangle) is undefined for the type ArrayList<Rectangle>

	at com.connorkuehl.blasteroids.PlayScreen.render(PlayScreen.java:162)
	at com.badlogic.gdx.Game.render(Game.java:46)
	at com.connorkuehl.blasteroids.BlasteroidsGame.render(BlasteroidsGame.java:31)
	at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:207)
	at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)

That is a complication error, so you are using the overlaps method wrong. You need to write loops and use rectangles in overlaps, see drabla’s posts above.

Special thanks to drabla, and thanks for everyone else who’s been contributing thus far you guys are great.

[s]I used the loop approach and I think it would work but there’s just one snag, the shots nor the asteroids are moving anymore.

The rectangle overlap loop looks like so, and it was also supposed to control the downward or upward movement of the asteroid or the shot respectively. Should I be controlling their movement another way?[/s]

EDIT: Thank you all, I’ve fixed the issue. The problem with the objects not moving was simply me overlooking a logic error.

		Iterator<Rectangle> asteroidIter = asteroids.iterator();
		while(asteroidIter.hasNext()) {
			Rectangle asteroid = asteroidIter.next();
			asteroid.y -= 200 * Gdx.graphics.getDeltaTime();
			if(asteroid.y < -64 || asteroid.overlaps(playerShip)) {
				asteroidIter.remove(); continue;
			}
			Iterator<Rectangle> shotIter = shots.iterator();
			while(shotIter.hasNext()) {
				Rectangle shot = shotIter.next();
				shot.y += 500 * Gdx.graphics.getDeltaTime();
				if(shot.y > 600) {
					shotIter.remove(); continue;
				}
				if(asteroid.overlaps(shot)) {
					shotIter.remove();
					asteroidIter.remove();
					break;
				}
			}
		}