0
\$\begingroup\$

I am currently developing a small Spaceshooter Clone. The project can be found on github

I am having problems with my very simple collision detection (or better said some behaviour that I can't explain myself.)

I do have lasers and asteroids. (currently all represented by Rectangles) To check for collision I'm using asteroid.overlaps(laser)

Basic handling of all my elements is as follows:

  • Move all my asteroids to the left
  • Check if an asteroid "left the screen" and if so destroy it.
  • Move all my lasers to the right
  • Check if a laser "left the screen" and if so destroy it.
  • If the laser has "not left the screen" I check collision with all asteroids.

asteroids is a Libgdx-Array; lasers is a Libgdx-Array; ship is a Libgdx Rectangle

    Iterator<Asteroid> asteroidsIterator = asteroids.iterator();
    while (asteroidsIterator.hasNext()) {
        Asteroid asteroid = asteroidsIterator.next();
        asteroid.x -= 200 * Gdx.graphics.getDeltaTime();
        if (asteroid.x < 0) {
            asteroidsIterator.remove();
        } else if (asteroid.overlaps(ship)) {
            //quitGame();
        }
    }

    Iterator<Rectangle> lasersIterator = lasers.iterator();
    asteroidsIterator = asteroids.iterator(); //<-- it seems that this does not get a fresh iterator
    while (lasersIterator.hasNext()) {
        Rectangle laser = lasersIterator.next();
        laser.x += 600 * Gdx.graphics.getDeltaTime();
        if (laser.x > 800) {
            lasersIterator.remove();
            Gdx.app.log("SC", "Laser exited screen.");
        } else {
            while (asteroidsIterator.hasNext()) {
                Asteroid asteroid = asteroidsIterator.next();
                if (asteroid.overlaps(laser)) {
                    Gdx.app.log("SC", "COLLISION");
                    asteroidsIterator.remove();
                    lasersIterator.remove();
                }
            }
        }
    }

When I do single fire everything is ok.

The strange behaviour is:

When I do full-automatic fire then some asteroids are not hit. Only newly created asteroids after begining firing are destroyed and in addition to that they should be very much to the right of the screen.

EDIT: After further investigation it seems that the second call to asteroids.iterator() does not create a fresh instance. Is there a way to get a fresh/reset Iterator?

\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

As you noted, Array#iterator() does not create a new iterator when it is called but returns a cached iterator to prevent garbage collection. From the documentation:

Returns an iterator for the items in the array. Remove is supported. Note that the same iterator instance is returned each time this method is called.

The way to reset the iterator is by calling ArrayIterator#reset() which should reset the iterator to the original state.

\$\endgroup\$
1
  • \$\begingroup\$ apparently this seems not to work. \$\endgroup\$
    – Naxos84
    Commented Jun 5, 2018 at 12:41
0
\$\begingroup\$

I found the problem. The issue was that I did not get a fresh iterator of asteroids for every single laser.

Iterator<Rectangle> lasersIterator = lasers.iterator();
    asteroidsIterator = asteroids.iterator(); //<-- this should be done for EVERY laser
    while (lasersIterator.hasNext()) {
        Rectangle laser = lasersIterator.next();
        laser.x += 600 * Gdx.graphics.getDeltaTime();
        if (laser.x > 800) {
            lasersIterator.remove();
            Gdx.app.log("SC", "Laser exited screen.");
        } else {
            while (asteroidsIterator.hasNext()) {
                Asteroid asteroid = asteroidsIterator.next();
                if (asteroid.overlaps(laser)) {
                    Gdx.app.log("SC", "COLLISION");
                    asteroidsIterator.remove();
                    lasersIterator.remove();
                }
            }
        }
    }

SOLUTION

Iterator<Rectangle> lasersIterator = lasers.iterator();
    while (lasersIterator.hasNext()) {
        Rectangle laser = lasersIterator.next();
        laser.x += 600 * Gdx.graphics.getDeltaTime();
        if (laser.x > 800) {
            lasersIterator.remove();
            Gdx.app.log("SC", "Laser exited screen.");
        } else {
            asteroidsIterator = asteroids.iterator();
            while (asteroidsIterator.hasNext()) {
                Asteroid asteroid = asteroidsIterator.next();
                if (asteroid.overlaps(laser)) {
                    Gdx.app.log("SC", "COLLISION");
                    asteroidsIterator.remove();
                    lasersIterator.remove();
                }
            }
        }
    }

of even better

for (Iterator<Rectangle> lasersIterator = lasers.iterator(); lasersIterator.hasNext(); ) {
            Rectangle laser = lasersIterator.next();
            laser.x += debugMode ? 1 : 600 * delta;
            if (laser.x > 800) {
                lasersIterator.remove();
            }
            for (Iterator<Asteroid> asteroidsIterator = asteroids.iterator(); asteroidsIterator.hasNext(); ) {
                Asteroid asteroid = asteroidsIterator.next();
                if (laser.overlaps(asteroid)) {
                    asteroidsIterator.remove();
                    lasersIterator.remove();
                }
            }
        }
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .