1
\$\begingroup\$

This is a follow-up question to my previous question. I got my key holding to move, using boolean variables and making another method with a javax.swing.Timer for delays(Thank you to KingDolphin), but strangely when I move my Icon it seems to increase how many pixels it moves each time by 1. It moves one pixel the first keyPressed, then two for the next, then three, etc. This may not seem like much, but when you are moving by 30+ pixels, it gets out of control. I really have no Idea how to fix it. I have tried changing some things, and I have "done my homework"(Googled and searched StackExchange sites including this one and StackOverflow), but have found nothing even related to it. Here's my layoutGame and move methods(The problem is in there), and thank you for helping me out:

    private void layoutGame() {
        JLabel title = new JLabel("Dodge The Enemies!");
        Font titleFont = new Font(Font.SERIF, Font.BOLD, 32);
        title.setFont(titleFont);
        title.setHorizontalAlignment(JLabel.CENTER);
        title.setBackground(Color.BLACK);
        title.setForeground(Color.WHITE);
        title.setOpaque(true);
        add(title, BorderLayout.NORTH);

        JLabel background = new JLabel();
        background.setIcon(backDrop);
        add(background, BorderLayout.CENTER);

        JLabel you = new JLabel();
        you.setBounds(x, y, 50, 50);
        you.setIcon(new ImageIcon(this.getClass().getClassLoader().getResource("happy.png")));
        background.add(you, JLabel.CENTER);

        JTextPane direction = new JTextPane();
        direction.setText("Direction");
        add(direction, BorderLayout.SOUTH);

        direction.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyChar() == 'w') {
                    wPressed = true;
                    move(you);
                } else if (e.getKeyChar() == 'a') {
                    aPressed = true;
                    move(you);
                } else if (e.getKeyChar() == 's') {
                    sPressed = true;
                    move(you);
                } else if (e.getKeyChar() == 'd') {
                    dPressed = true;
                    move(you);
                }
                direction.setText(null);
            }
            public void keyReleased(KeyEvent e) {
                wPressed = false;
                aPressed = false;
                sPressed = false;
                dPressed = false;
            }
        });
    }

    private void move(JLabel icon) {
        int delay = 100; //milliseconds
        ActionListener taskPerformer = new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                if (wPressed) {
                    y = y - 1;
                } else if(aPressed) {
                    x = x - 1;
                } else if(sPressed) {
                    y = y + 1;
                } else if(dPressed) {
                    x = x + 1;
                }
                icon.setBounds(x, y, 50, 50);
                icon.repaint();
            }
        };
        new Timer(delay, taskPerformer).start();
    }
\$\endgroup\$
2
  • 4
    \$\begingroup\$ I would really recommend you to reduce your code to the actually relevant parts. There is a lot of fluff in there which definitely won't have anything to do with the problem. The more code you post, the less people will be willing to dig through all of it until they found your bug. \$\endgroup\$ – Philipp Jun 19 '17 at 8:37
  • \$\begingroup\$ @Philipp Ok, I will shorten that. Thank you for your feedback \$\endgroup\$ – CodingNinja Jun 19 '17 at 17:34
2
\$\begingroup\$

The reason for this lies in the way you've implemented the move method: in there, you create a new javax.swing.Timer object that is responsible for increasing or decreasing the icon's x or y position.

However, note the following:

  1. Timers execute their actionPerformed method not just once, but indefinitely until they're canceled.
  2. You create a new Timer object every time a key is pressed.
  3. Your timers are never canceled, i.e., they keep running forever.

This means before long, you've created a whole bunch of Timers that all run concurrently and that all increase/decrease your icons position. That's why you see an additive effect. You can see this quite easily if you add the following debug line to the actionPerformed method inside move:

public void actionPerformed(ActionEvent evt) {
    System.out.println("timer " + hashCode() + " running");

Now, watch the terminal output while you play the game.

I don't think you actually need a timer at all, you can just move the code that's currently inside actionPerformed directly into move and the effect will disappear.

(However, an even better tip would be to read up on "game loops".)

\$\endgroup\$
1
  • \$\begingroup\$ Thank you, this solved my problem. I still used the timer, but I declared it privately. All I had to do was start it in my move method, and stop it in my keyReleased method. So relieved! \$\endgroup\$ – CodingNinja Jun 19 '17 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.