First post in SO, hope I'm doing this right!
I'm trying to make a game in Java where a robot drives around and shines lines at nearby walls. Problem is, these lines stay onscreen, even when the robot moves, so it makes a cloud of lines that won't erase.
In the paintComponent(), I've tried g.fillRect(), but that doesn't erase any lines, just draws a rectangle behind that cloud. Every source I've seen so far seems to suggest things I've already done, unless I'm misunderstanding / overlooking something obvious...
'''
//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);
} //*/
}
'''
You should not be disposing the default graphics context
at the start of paintComponent()
. The best thing to do is to make a copy via create and then later, dispose of that right before you return from paintComponent()
.
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();
}
If this does not help solve your problem, please make a Minimal Reproducible Example that demonstrates the problem. It should not rely on anything that is not within the JDK API (i.e. third party classes, libraries, etc.)