alexholstv
alexholstv

Reputation: 146

How do I correctly update an object's location in JPanel using 'repaint()'?

I'm currently working on my first game using Java. I have a red square (the player) in a grid of stone blocks. The game is looking like this: https://i.sstatic.net/P6qSE.png

After I accomplished this, I moved on to trying out the KeyListener. I also have a Player class with a few variables and a paint funcition. Here is the Player class:

import java.awt.Color;
import java.awt.Graphics;

public class Player {
    int width, height;
    int x = 300;
    int y = 300;
    
    public Player() {
        width = 25;
        height = 25;
    }
    
    public void drawPlayer(Graphics g) {
        g.setColor(Color.red);
        g.fillRect(x, y, width, height);
    }
}

And here is the KeyListener:

public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_W) {
        player.y += 25;
        repaint();
    } else if(e.getKeyCode() == KeyEvent.VK_A) {
        player.x -= 25;
        repaint();
    } else if(e.getKeyCode() == KeyEvent.VK_S) {
        player.y -= 25;
        repaint();
    } else if(e.getKeyCode() == KeyEvent.VK_D) {
        player.x += 25;
        repaint();
    }
    
    System.out.println(player.x + ", " + player.y);
    
}

As you can see at the bottom of the keyPressed function, I added: System.out.println(player.x + ", " + player.y); to make sure the KeyListener was working well (it is).

Now, since everything is working, last step was repainting the JPanel to update the players position. This is that code:

@Override
public void paint(Graphics g) {
    super.paint(g);
    
    stone.drawStone(g);
    player.drawPlayer(g);
    
    g.setColor(Color.gray);
    for (int j = 0; j < Display.WIDTH; j += tileSize) {
        for (int i = 0; i < Display.HEIGHT; i += tileSize) {
            g.drawRect(i, j, tileSize, tileSize);
        }
    }
}

In theory, my player should update position (since I already did repaint() in the KeyListener), but it doesn't. My player doesn't move. What could this be? I'm guessing it has something to do with repainting the JPanel but I don't know how to fix this. Do you have any suggestions? Thanks in advance.

Side note: I have 4 main classes, Player, Game (here is where 95% of the code came from), Display (JFrame), and Main (draws JFrame and starts gameloop (but im not currently using a gameloop)).

Upvotes: 0

Views: 210

Answers (1)

camickr
camickr

Reputation: 324118

As I suggested in my comment you are creating multiple instances of your classes all over the place.

Your Frame class has plenty of issues:

public class Frame extends JFrame {
private static Game game = new Game();

    public Frame() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(640, 640));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);
        frame.addKeyListener(new Game());
        frame.setFocusable(true);
        frame.setContentPane(game);
    }
  1. Don't use static variables. Note how you have a static variable for the "Game". The you add a KeyListener to a second instance of the "Game" class. So your KeyListener does nothing, because that instance of the Game class is never added to the frame.

  2. the frame needs to non-resizable BEFORE you pack() the frame.

  3. components need to be added to the frame BEFORE you pack() the frame.

  4. don't set a preferred size on the frame. Your Game class should override the getPreferredSize() method to return the size of the panel. This class is responsible for doing the painting, so only it knows what it preferred size should be. Also a frame has decorations (the titlebar and borders) so you game panel will not be 640x640 as you expect.

The job of the Frame class should be to simply create the JFrame and add the Game panel to the frame. All other Game logic will be contained in the Game and your other classes. Your Game class with add the KeyListener to itself in the constructor of your class.

Check out: get width and height of JPanel outside of the class for an example of this design structure. It basically does what you need except is doesn't have the KeyListener code.

Upvotes: 1

Related Questions