Java 图形不会删除行,即使我调用 super.paintComponent(g)

Java graphics won't delete lines, even when I call super.paintComponent(g)

首先 post 在 SO 中,希望我做对了!

我正在尝试在 Java 中制作一款游戏,其中机器人会四处行驶并在附近的墙壁上发光。问题是,这些线条会留在屏幕上,即使机器人移动时也是如此,所以它会形成一团不会擦除的线条。

在 paintComponent() 中,我尝试了 g.fillRect(),但这并没有擦除任何线条,只是在云后面绘制了一个矩形。到目前为止我看到的每一个来源似乎都在暗示我已经做过的事情,除非我误解/忽略了一些明显的事情......

'''

//from https://www.youtube.com/watch?v=p9Y-NBg8eto

/*
Other classes in this folder:
    Robot.java      Represents a robot, its location and angular orientation.
    Obstacles.java      Represents lines; the walls the robot should detect.
    Sensor.java     Represents the beams that shine from the robot to the walls.
//*/

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.lang.Math;
import java.util.ArrayList;
public class MyPanel extends JPanel implements ActionListener, KeyListener
{
    Timer t = new Timer(5, this);

    //OBSTACLES:
    Obstacles obstacles=new Obstacles(0);

    //ROBOT:
    Robot robot = new Robot(obstacles);

    //`````````````````````````````````````````````````````````
    public MyPanel()
    {
        t.start();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        setVisible(true);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        g.dispose();
        super.paintComponent(g);
        //Graphics2D g2 = (Graphics2D) g;
        g.setColor(Color.RED);
        g.fillRect(0, 0, 450, 450);
        g.setColor(Color.BLACK);
        //Graphics2D g2 = (Graphics2D) g;
        robot.drawRobot(g);
        drawBoundedBeams(g);
        obstacles.drawObstacles(g);
        drawSun(g);
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        repaint();
    }

    @Override 
    public void keyPressed(KeyEvent e)
    {
        int code = e.getKeyCode();
        if (code==KeyEvent.VK_UP)
            robot.up();
        if (code==KeyEvent.VK_DOWN)
            robot.down();
        if (code==KeyEvent.VK_LEFT)
            robot.left();
        if (code==KeyEvent.VK_RIGHT)
            robot.right();

        robot.updateSensor();
    }
    @Override public void keyTyped(KeyEvent e) {}
    @Override public void keyReleased(KeyEvent e) {}

    //```````````````````````````````````````````````````````````
    public static void main(String [] args)
    {
        JFrame f = new JFrame();
        MyPanel panel = new MyPanel();
        f.add(panel);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(800, 600);
        f.setVisible(true);
    }

    //Dummy lines. For some reason, these delete and move with the robot, no problem.
    public void drawSun(Graphics g)
    {
        int x = (int) robot.x;
        int y = (int) robot.y;
        double t = robot.angle;
        double xang = Math.cos(t);
        double yang = Math.sin(t);
        double east = (t + Math.PI/2) % (2 * Math.PI);
        double eastx = Math.cos(east);
        double easty = Math.sin(east);
        g.drawLine(x, y, x+100, y);
        g.drawLine(x, y, x-100, y);
        g.drawLine(x, y, x, y+100);
        g.drawLine(x, y, x, y-100);
        g.drawLine(x, y, x+100, y+100);
        g.drawLine(x, y, x+100, y-100);
        g.drawLine(x, y, x-100, y+100);
        g.drawLine(x, y, x-100, y-100);
        g.drawLine(x, y, x+(int)(xang*100), y+(int)(yang*100));
        g.drawLine(x, y, x-(int)(xang*100), y-(int)(yang*100));
        g.drawLine(x, y, x+(int)(eastx*100), y+(int)(easty*100));
        g.drawLine(x, y, x-(int)(eastx*100), y-(int)(easty*100));
    }

    //This was in Sensor.java, but I moved it here to try to fix it. (Didn't work.)
    //THIS is what isn't getting deleted.
    public void drawBoundedBeams(Graphics g) //Graphics2D g2
    {
        //Graphics2D g2 = (Graphics2D) g;
        for (Integer[] beam : robot.sensor.boundedBeams)
        {
            g.drawLine(beam[0], beam[1], beam[2], beam[3]); 
        }
    }
}

'''

~~~~~~ EDIT: I made a Minimal ~~~~~~
~~~~~~  Reproducible Example. ~~~~~~

MyPanel.java: '''

/*
Classes in this (reprex) folder:
MyPanel.java    displays things         ****PROBLEM HERE(?)
Robot.java      stores location and orientation
Sensor.java     Shines beams outward    ****PROBLEM HERE(?)

(I tried to keep the file structure consistent,
 in case that was a factor for the issue.)
//*/

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.lang.Math;
import java.util.ArrayList;
public class MyPanel extends JPanel implements ActionListener, KeyListener
{
    Timer t = new Timer(5, this);

    Robot robot = new Robot();

    //`````````````````````````````````````````````````````````
    public MyPanel()
    {
        t.start();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        setVisible(true);
    }


    //********************************************
    //********************************************
    //********************************************
    //**** Problem seems to be HERE. *************
    //**** ~~~~~~~~~~~~~~~~~~~~~~~~  *************
    //**** (See also: the method in  *************
    //**** Sensor.java; drawBeams()) *************
    //********************************************
    //********************************************
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();

        // And to smooth out the graphics, you can do the following
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        g2.setColor(Color.RED);
        g2.fillRect(0, 0, 450, 450);
        g2.setColor(Color.BLACK);
        robot.sensor.drawBeams(g2);
        g2.dispose();
    }

    @Override 
    public void actionPerformed(ActionEvent e) 
    {
        repaint();
    }

    @Override 
    public void keyPressed(KeyEvent e)
    {
        int code = e.getKeyCode();
        if (code==KeyEvent.VK_UP)
            robot.up();
        if (code==KeyEvent.VK_DOWN)
            robot.down();
        if (code==KeyEvent.VK_LEFT)
            robot.left();
        if (code==KeyEvent.VK_RIGHT)
            robot.right();

        robot.updateSensor();
    }
    @Override public void keyTyped(KeyEvent e) {}
    @Override public void keyReleased(KeyEvent e) {}

    //```````````````````````````````````````````````````````````
    public static void main(String [] args)
    {
        JFrame f = new JFrame();
        MyPanel panel = new MyPanel();
        f.add(panel);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(800, 600);
        f.setVisible(true);
    }
}

'''

Sensor.java: '''

import java.lang.Math;
import java.util.ArrayList;
import java.awt.*;

class Sensor
{
    private Robot robot;

    public int numPieces;
    public Integer range = 300;
    public ArrayList<Double> offsets = new ArrayList<Double>();         //the angles of each beam
    public ArrayList<Integer[]> beams = new ArrayList<Integer[]>();     //the beams that stretch out to the range   public ArrayList<Integer[]> boundedBeams = new ArrayList<Integer[]>();

    public Sensor(Robot robot)
    {
        this.robot=robot;
        make12Sonars();
    }
    public void make12Sonars()  
    {
        numPieces=12;
        double offset = 0;
        while (offset < 2*Math.PI)
        {
            offsets.add(offset);
            offset += Math.PI / 6;
        }
    }

    public void updateSensor()
    {
        makeBeams();
    }

    //```````````````````````````````````````````````````````
    public void makeBeams()     //Makes the maximum beams from the angles.
    {
        System.out.println("~~~MAKING BEAMS~~~");
        for (Integer i=0; i<offsets.size(); i++)
        {
            System.out.println("\tat index "+i);
            Double offset = offsets.get(i);
            Double angle = (offset + robot.angle) % (2*Math.PI);

            Integer[] beam = getSegment(robot.x, robot.y, angle, Double.valueOf(range));
            beams.add(i, beam);
            System.out.println("\t\tadded "+beam[0]+", "+beam[1]+", "+beam[2]+", "+beam[3]);
        }
    }

    static public Integer[] getSegment(Double startX, Double startY, Double angle, Double radius)
    {
        Double x2 = radius * Math.cos(angle) + startX;
        Double y2 = radius * Math.sin(angle) + startY;
        Integer[] segment = {startX.intValue(), startY.intValue(), x2.intValue(), y2.intValue()};
        return segment;
    }


    //********************************************
    //********************************************
    //********************************************
    //**** Problem seems to be HERE. *************
    //**** ~~~~~~~~~~~~~~~~~~~~~~~~  *************
    //**** (The lines drawn here     *************
    //****  do not delete.)          *************
    //********************************************
    //********************************************
    public void drawBeams(Graphics g)
    {
        Integer x = (int) robot.x;
        Integer y = (int) robot.y;
        for (Integer[] beam : beams)
        {
            g.drawLine(beam[0], beam[1], beam[2], beam[3]);
        }
    }
}

'''

Robot.java: '''

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.lang.Math;
class Robot
{
    public double x=0, y=0; //center of the robot
    public double velx=0, vely=0; //velocity of the robot
    public double angle=0, speed=4; //radians, speed(before_direction)

    public Sensor sensor;
    public Robot()
    {
        sensor=new Sensor(this);
    }
    public void updateSensor() {sensor.updateSensor();}

    //`````````````````````````````````````````````````````````````
    //*
    public void up() {x+=velx; y+=vely;}
    public void down() {x-=velx; y-=vely;}
    public void left()
    {
        angle -= 0.1;
        angle = angle % (2*Math.PI);
        velx = speed * Math.cos(angle);
        vely = speed * Math.sin(angle);
    }
    public void right()
    {
        angle += 0.1;
        angle = angle % (2*Math.PI);
        velx = speed * Math.cos(angle);
        vely = speed * Math.sin(angle);
    }   //*/
}

'''

您不应在 paintComponent() 的开头处理 default graphics context。最好的办法是通过创建创建一个副本,然后在 paintComponent().

return 之前处理掉它
Try this as a your `paintComponent()` method.

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();

        // And to smooth out the graphics, you can do the following
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        g2.setColor(Color.RED);
        g2.fillRect(0, 0, 450, 450);
        g2.setColor(Color.BLACK);
        robot.drawRobot(g2);
        drawBoundedBeams(g2);
        obstacles.drawObstacles(g2);
        drawSun(g2);
        g2.dispose();
    }

如果这不能帮助解决您的问题,请创建一个 Minimal Reproducible Example 来演示问题。它不应依赖 JDK API 之外的任何内容(即第三方 类、库等)