0

I am trying to do a PAC-MAN clone in Java. I am using swing and awt for the GUI. I implemented motion into my main character and it responds to keys pressed, but when the character moves the "old image" stays there. So, rather than it looking like pacman moves through the screen he leaves a trail. It is my understanding that when I use the repaint() function the image should be cleared and painted again.

This is my code:

//PACMAN CLASS
import Entities.Ghost;
import Entities.Player;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Pacman extends JPanel implements KeyListener {

    Player player = new Player("Pacman.png", 0, 0);
    Ghost[] ghosts = new Ghost[4];

    public Pacman(){
        addKeyListener(this);
        setFocusable(true);

        ghosts[0] = new Ghost("Ghost_Red.png", 200, 200);
        ghosts[1] = new Ghost("Ghost_Red.png", 150, 150);
        ghosts[2] = new Ghost("Ghost_Red.png", 300, 100);
        ghosts[3] = new Ghost("Ghost_Red.png", 50, 300);
    }

    public void paintComponent(Graphics g){
        player.draw(g, this);
        for(Ghost ghost: ghosts){
            ghost.draw(g, this);
        }
    }

    public void update() {
        repaint();
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_ENTER){
            new Thread( () -> {
                while (true){
                    update();
                    try{
                        Thread.sleep(10);
                    }catch(InterruptedException err){
                        err.printStackTrace();
                    }
                }
            }).start();
        }

        int SPEED = 4;

        if(e.getKeyCode() == KeyEvent.VK_RIGHT && player.x < (getWidth() - player.width)){
            player.x += SPEED;
        }

        if(e.getKeyCode() == KeyEvent.VK_LEFT && player.x > 0){
            player.x -= SPEED;
        }

        if(e.getKeyCode() == KeyEvent.VK_UP && player.y > 0){
            player.y -= SPEED;
        }

        if(e.getKeyCode() == KeyEvent.VK_DOWN && player.y < (getHeight() - player.height)){
            player.y += SPEED;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

//MY MAIN
import javax.swing.*;

public class Main {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Pacman");
        Pacman panel = new Pacman();
        frame.getContentPane().add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setSize(224*2,288*2);
        frame.setResizable(false);
    }
}

I followed a tutorial to get here and the guy's graphic do work properly. Thoug he is using JAva 10 and I am using Java 16

1 Answers1

1

When doing custom painting, and especially when doing some "animations", it's really important to call super.paintComponent(g); as the first line in your paintComponent(...) method

This will repaint all the things you're not painting on that "frame", and thus this is what you need to do to solve your problem.

If you want to know more in detail what super.paintComponent() does, then read this answer.

So your code should end up looking like this:

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    player.draw(g, this);
    for(Ghost ghost : ghosts) {
        ghost.draw(g, this);
    }
    //Any extra painting do it here
}

Also, this line:

frame.setVisible(true);

Should be the last one on your program

And about this line:

frame.setSize(224*2,288*2);

Better override your JPanel's getPreferredSize, and then call frame.pack() this will make your pane to have that size and then add the frame decorations, otherwise your panel will be smaller than you think it is; for more information take a look at this question and answers: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

And as a tip, don't use "magic numbers", instead declare constants as of what those 224 and 288 means and why you multiply them by 2.

And forgot to mention that when programming games, it's better to use KeyBindings rather than infinite loops (while(true)) with KeyListeners; here's an excellent answer from @HovercraftFullOfEels that shows how to do it.

Frakcool
  • 10,915
  • 9
  • 50
  • 89