Reputation: 57
I'm using eclipse. I can't seem to wrap my head around why this code is giving an error. It seems completely logical, and the second I remove that little line, the program works fine. I'm pretty sure the focus should be on line 98, that is what the error is saying as well. The other part I made into a comment also gives the exact same error for seemingly no reason... why would it be going too far in the objectList? Line 98 looks like this
if(objectIterator.next().getClass() == Enemy.class) //Enemy.class.isAssignableFrom(objectIterator.next().getClass()))
package robotron;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.Timer;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.event.*;
import java.util.*;
public class GameArea extends JPanel implements ActionListener
{
static final long serialVersionUID = 42L;
public static final int FRAME_RATE = 60;
public static final int TIME_BETWEEN_FRAMES = 1000/FRAME_RATE;
public static final int DIFFICULTY_INCREASE = 4;
public static final int LEFT_EDGE = 0;
public static final int RIGHT_EDGE = 800;
public static final int UPPER_EDGE = 0;
public static final int BOTTOM_EDGE = 600;
public static final int PLAYER_MOVE_UP_KEY = KeyEvent.VK_W;
public static final int PLAYER_MOVE_DOWN_KEY = KeyEvent.VK_S;
public static final int PLAYER_MOVE_LEFT_KEY = KeyEvent.VK_A;
public static final int PLAYER_MOVE_RIGHT_KEY = KeyEvent.VK_D;
public static final int UP_KEY = KeyEvent.VK_UP;
public static final int DOWN_KEY = KeyEvent.VK_DOWN;
public static final int LEFT_KEY = KeyEvent.VK_LEFT;
public static final int RIGHT_KEY = KeyEvent.VK_RIGHT;
public static LinkedList<Integer> keyPressedList = new LinkedList<Integer>();
public static Iterator<Integer> keyPressedIterator;
public static LinkedList<GameObject> storeList = new LinkedList<GameObject>();
public static Iterator<GameObject> storeIterator;
public static LinkedList<GameObject> objectList = new LinkedList<GameObject>();
public static Iterator<GameObject> objectIterator;
public static int difficultyIncrements = 0;
public static int enemyUnitCount = 0;
public Timer gameTimer = new Timer(TIME_BETWEEN_FRAMES, this);
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.YELLOW);
g2.fill(Player.playerBoundingBox);
for(GameObject object : objectList)
{
g2.fill(object.getBoundingBox());
}
for(GameObject object : objectList)
{
object.draw(g);
}
}
public GameArea(){
setFocusable(true);
setPreferredSize(new Dimension(800,600));
MyKeyListener keyListener = new MyKeyListener();
addKeyListener(keyListener);
gameTimer.start();
objectList.add(new Player());
}
public void actionPerformed(ActionEvent a)
{
//System.out.println(objectList);
for(GameObject storedObject : storeList)
{
objectList.addLast(storedObject);
}
storeList.clear();
for (GameObject object : objectList)
{
object.update();
object.move();
}
objectIterator = objectList.iterator();
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
{
if(objectIterator.next().getClass() == Enemy.class) //Enemy.class.isAssignableFrom(objectIterator.next().getClass()))
enemyUnitCount --;
objectIterator.remove();
}
}
if(enemyUnitCount == 0 )
{
objectIterator = objectList.iterator();
while(objectIterator.hasNext())
{
if(objectIterator.next().getClass() != Player.class)
{
objectIterator.remove();
}
}
initiateNewRound();
}
repaint();
}
public void initiateNewRound()
{
difficultyIncrements += DIFFICULTY_INCREASE;
gameTimer.stop();
gameTimer.setInitialDelay(1000);
spawnUnits(5 + difficultyIncrements);
gameTimer.restart();
}
public void spawnUnits(int spawnCoefficient)
{
for(int i = 0; i < spawnCoefficient*2;i++)
{
if(Math.random() * 600 < 301)
{
GameArea.objectList.add(new Walker());
}
}
for(int i = 0; i < spawnCoefficient;i++)
{
if(Math.random() * 600 < 100)
{
GameArea.objectList.add(new DeathTrap());
}
}
if(Math.random() * 600 < 200)
{
GameArea.objectList.add(new SlowTrap());
}
}
private class MyKeyListener implements KeyListener
{
public void keyPressed(KeyEvent e)
{
//System.out.println("keyPressed() " + e.getKeyCode());
if(!keyPressedList.contains(e.getKeyCode()))
{
//System.out.println("new keyPressed() " + e.getKeyCode());
keyPressedList.add(e.getKeyCode());
}
}
public void keyReleased(KeyEvent e)
{
//System.out.println("keyReleased() " + e.getKeyCode());
keyPressedList.removeFirstOccurrence(e.getKeyCode());
}
public void keyTyped(KeyEvent e)
{
}
}
}
This is the error:
This is the exact error:
Exception in thread "AWT-EventQueue-0" java.util.NoSuchElementException
at java.util.LinkedList$ListItr.next(Unknown Source)
at robotron.GameArea.actionPerformed(GameArea.java:98)
at javax.swing.Timer.fireActionPerformed(Unknown Source)
at javax.swing.Timer$DoPostEvent.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Upvotes: 1
Views: 2054
Reputation: 718788
It seems completely logical ...
The one thing that you can guarantee about program execution is that at some level it is completely logical. It will do what the code says to do ... once you understand what the code actually says. (It is worth bearing this in mind when you are debugging things.)
In case, the "logic error" lies in your understanding of what your program code is saying.
Here is the key part of your code:
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
{
if(objectIterator.next().getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
As you are no doubt aware, next()
advances the iterator and hasNext()
tests whether you can still advance the advance the iterator. (The next()
method is not the same a simple "getter". It has a side-effect.)
If you look carefully at your code, you can see that each repetition of the while
loop is going to do one of the following:
hasNext()
, next()
orhasNext()
, next()
, next()
, remove()
Suppose that you were positioned at the last element of the list at the start of the loop repetition. Here's what happens:
hasNext()
says true
.next()
call gives you the last element.if
test succeeds, the second next()
call throws the exception because there is no "next".The solution is something like this:
while(objectIterator.hasNext())
{
GameObject tmp = objectIterator.next();
if(tmp.getHealth() < 1)
{
if(tmp.getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
Some more things to note:
Your code style needs so attention. According to all mainstream Java style guides:
if
and while
keywords. If and while are NOT method calls.The opening curly brackets should be at the end of the previous line for these statements. The only cases where you should put it on a new line are when the previous line is a different statement.
while (objectIterator.hasNext()) {
GameObject tmp = objectIterator.next();
if (tmp.getHealth() < 1) {
if (tmp.getClass() == Enemy.class) {
enemyUnitCount --;
}
objectIterator.remove();
}
}
Upvotes: 0
Reputation: 425003
Although next()
seems like a "getter", it also advances the iteration pointer. ie every call to next will return a different element.
Change your code to call next()
once and assign the object returned to a variable if you need to refer to it multiple times.
Upvotes: 0
Reputation: 869
From the documentation for the method Iterator.next()
:
Returns the next element. Throws
NoSuchElementException
if the iteration has no more elements.
You are calling the next()
method twice after a single test for hasNext()
.
Upvotes: 2
Reputation: 124225
Each time you call next()
you are iterating to next object. Take a look at your code
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
// ^^^^^
{
if(objectIterator.next().getClass() == Enemy.class)
// ^^^^^
enemyUnitCount --;
objectIterator.remove();
}
}
In your while(objectIterator.hasNext())
loop condition you are checking if iterator has at least one more element, but then you are invoking next
twice in each if(...next()...)
statement which means in second call of next
you are trying to access element which may not be present.
To correct your code simply store result of next
and use this object when needed like
while(objectIterator.hasNext())
{
GameObject gameObjec = objectIterator.next();
if(gameObjec.getHealth() < 1)
{
if(gameObjec.getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
Upvotes: 3