Stackoverflow error with ActionListeners

460 views Asked by At

When I try to control my character with the arrow keys, everything works fine but after a while I get this error:

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError

and then

at java.awt.AWTEventMulticaster.keyPressed(AWTEventMulticaster.java:249)

multiple times. The class that I have isn't even 249 lines of code long so I don't know where to look for the problem. My code is very messy right now but I'll post it if it helps anyone come up with the answer.

import javax.swing.JButton;
import javax.swing.JComponent;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.image.*;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

public class mainFrame extends JPanel implements Runnable, KeyListener {
    static boolean gameIsRunning = false;
    static final int TARGET_FPS = 1;
    static int x = 100;
    static int y = 100;
    static long startTime = 0;
    static long elapsedTime = 0;
    static long waitTime = 0;
    JFrame window = new JFrame("Out from Eden");
    JPanel panel = new JPanel();
    getResources get = new getResources();
    BufferedImage player = get.getImg("player");
    static int playerVal = 0;
    static int i = 0;
    static String currentState = "";
    static int lastFacing = 0;

    public void createFrame() {
        gameIsRunning = true;
        gameStart();
    }

    public void setGame(boolean game) {
        gameIsRunning = game;
    }

    public void gameStart() {
        (new Thread(new mainFrame())).start();
    }

    public void run() {
        while (gameIsRunning == true) {
            startTime = System.nanoTime();
            updateGame();
            renderGame();
            elapsedTime = System.nanoTime() - startTime;
            waitTime = (TARGET_FPS * 10) - (elapsedTime / 1000000);

            if (waitTime < 0) {
                waitTime = 5;
            }
            try {
                Thread.sleep(waitTime);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void updateGame() {
        if (x > 800) {
            x = 0;
        }

        if (currentState == "left") {
            x--;
        }
        if (currentState == "right") {
            x++;
        }
        player = royImage();

    }

    public BufferedImage royImage() {
        if (currentState == "right") {
            lastFacing = 2;
            i++;
            if (playerVal == 0) {
                playerVal = 1;
                i = 0;
                player = get.getImg("royWalk1");
            }
            if (playerVal == 1 && i > 20) {
                playerVal = 2;
                i = 0;
                return get.getImg("royWalk2");
            }
            if (playerVal == 2 && i > 20) {
                playerVal = 3;
                i = 0;
                player = get.getImg("royWalk3");
            }
            if (playerVal == 3 && i > 20) {
                playerVal = 4;
                i = 0;
                player = get.getImg("royWalk4");
            }
            if (playerVal == 4 && i > 20) {
                playerVal = 0;
                i = 0;
                player = get.getImg("royWalk1");
            }
        }

        if (currentState == "left") {
            lastFacing = 1;
            i++;
            if (playerVal == 0) {
                playerVal = 1;
                i = 0;
                player = get.getImg("royWalkL1");
            }
            if (playerVal == 1 && i > 20) {
                playerVal = 2;
                i = 0;
                player = get.getImg("royWalkL2");
            }
            if (playerVal == 2 && i > 20) {
                playerVal = 3;
                i = 0;
                player = get.getImg("royWalkL3");
            }
            if (playerVal == 3 && i > 20) {
                playerVal = 4;
                i = 0;
                player = get.getImg("royWalkL4");
            }
            if (playerVal == 4 && i > 20) {
                playerVal = 0;
                i = 0;
                player = get.getImg("royWalkL1");
            }
        }

        if (currentState == "null") {
            i = 0;
            playerVal = 0;
            if (lastFacing == 1) {
                player = get.getImg("playerL");
            }
            if (lastFacing == 2) {
                player = get.getImg("player");
            }
        }
        return player;
    }

    public void renderGame() {
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setBounds(30, 30, 700, 500);
        panel.setLayout(new BorderLayout());
        window.getContentPane().add(panel);
        panel.add(this);
        window.setFocusable(true);
        window.setFocusTraversalKeysEnabled(false);
        window.setVisible(true);
        window.addKeyListener(this);
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.drawString("Hello", x, y);
        g2.drawLine(0, 63, 700, 63);
        g2.drawImage(player, x - 100, y - 100, null);
    }

    public void keyTyped(KeyEvent e) {

    }

    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == KeyEvent.VK_UP) {
            currentState = "up";
        }
        if (code == KeyEvent.VK_DOWN) {
            currentState = "down";
        }
        if (code == KeyEvent.VK_LEFT) {
            currentState = "left";
        }
        if (code == KeyEvent.VK_RIGHT) {
            currentState = "right";
        }
    }

    public void keyReleased(KeyEvent e) {
        currentState = "null";
    }
}

Could anyone help me figure out why I am getting the stack overflow error and how to avoid it?

1

There are 1 answers

0
Hovercraft Full Of Eels On

Your while true loop is shooting you in the foot as you're adding a KeyListener umpteen thousand times within that loop. Don't do that, in particular your renderGame() method. Why would you even want to call a method that is for setting the GUI that many times? It would make much more sense to call that method once.

Also, instead use a Swing Timer (Google the tutorial) in place of your while loop, avoid KeyListeners in favor of Key Binding (Google the tutorial, and have a look at this example) and do your set-up code only once.

Also, your code is at risk of causing Swing threading errors as you're calling Thread.sleep(...) and while (true) in a non-background thread. For safety's sake, use a Swing Timer instead.

Also, you're comparing Strings wrong. Don't compare Strings using == or !=. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two object references are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of

if (fu == "bar") {
  // do something
}

do,

if ("bar".equals(fu)) {
  // do something
}

or,

if ("bar".equalsIgnoreCase(fu)) {
  // do something
}