简体   繁体   English

Java awt repaint() 移动时留下痕迹

[英]Java awt repaint() leaving a trail when moving

I am trying to do a PAC-MAN clone in Java.我正在尝试在 Java 中进行 PAC-MAN 克隆。 I am using swing and awt for the GUI.我正在使用 swing 和 awt 作为 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.据我了解,当我使用 repaint() function 时,应该清除图像并重新绘制。

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尽管他使用的是 JAva 10 而我使用的是 Java 16

When doing custom painting, and especially when doing some "animations", it's really important to call super.paintComponent(g);在进行自定义绘画时,尤其是在做一些“动画”时,调用super.paintComponent(g);非常重要。 as the first line in your paintComponent(...) method作为您的paintComponent(...)方法的第一行

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 .如果您想更详细地了解super.paintComponent()的作用,请阅读此答案

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;最好覆盖您的JPanelgetPreferredSize ,然后调用frame.pack()这将使您的窗格具有该大小,然后添加框架装饰,否则您的面板将比您想象的要小; 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?有关更多信息,请查看此问题和答案: 我应该避免在 Java Swing 中使用 set(Preferred|Maximum|Minimum)Size 方法吗?

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.并且作为提示,不要使用“幻数”,而是声明常量,说明224288的含义以及为什么将它们乘以 2。

And forgot to mention that when programming games, it's better to use KeyBindings rather than infinite loops ( while(true) ) with KeyListener s;并且忘了提到,在编写游戏时,最好使用KeyBindings而不是无限循环( while(true) )和KeyListener here's an excellent answer from @HovercraftFullOfEels that shows how to do it.这是来自@HovercraftFullOfEels 的一个很好的答案,它展示了如何做到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM