My JFrame Flickers - java

I'm trying to make a simple java game -- driving a car through a track. I am conditioned by my teacher to use rectangles and stuff like that . My problem is when I use the method repaint() that my frame flickers. I have tried to put the repaint method just when the car changes direction, but it doesn't do any good. Any suggestions?
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class MAP extends JFrame
{
//the URL and Img designed for the images
URL cLeft,cRight,cUp;
Image img1,img2,img3;
//these will keep track of each player’s speed:
double p1Speed =.5, p2Speed =.5;
//constant for the screen size and used for the drawing the terrain
final int WIDTH = 900, HEIGHT = 650;
//these are ints that represent directions:
final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3;
//these will keep track of the player’s directions (default = up)
int p1Direction = 0;
//this is the rectangle for player 1’s (outer) car:
Rectangle p1 = new Rectangle(WIDTH/9,HEIGHT/2, WIDTH/30,WIDTH/30);
//draw the terrain
Rectangle left = new Rectangle(0,0,WIDTH/9,HEIGHT);
Rectangle right = new Rectangle((WIDTH/9)*9,0,WIDTH/9,HEIGHT);
Rectangle top = new Rectangle(0,0,WIDTH, HEIGHT/9);
Rectangle bottom = new Rectangle(0,(HEIGHT/9)*9,WIDTH,HEIGHT/9);
Rectangle center = new Rectangle((int)((WIDTH/9)*2.5),(int)((HEIGHT/9)*2.5), (int)((WIDTH/9)*5),(HEIGHT/9)*4);
//these obstacles will obstruct the path and make navigating harder
Rectangle obstacle = new
Rectangle(WIDTH/2,(int)((HEIGHT/9)*7),WIDTH/10,HEIGHT/9);
Rectangle obstacle2 = new
Rectangle(WIDTH/3,(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4);
Rectangle obstacle3 = new
Rectangle(2*(WIDTH/3),(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4);
Rectangle obstacle4 = new Rectangle(WIDTH/3,HEIGHT/9,WIDTH/30,HEIGHT/9);
Rectangle obstacle5 = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*1.5),WIDTH/30,HEIGHT/4);
Rectangle finish = new Rectangle(WIDTH/9,(HEIGHT/2)-HEIGHT/9,(int)((WIDTH/9)*1.5),HEIGHT/70);
Rectangle lineO=new Rectangle(WIDTH/9,HEIGHT/2,(int)((WIDTH/9)*1.5)/2,HEIGHT/140);
Rectangle lineI = new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+(HEIGHT/10),(int)((WIDTH/9)*1.5)/2, HEIGHT/140);
//the constructor:
public MAP() {
//the following code creates the JFrame
super("Radical Racing");
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setResizable(false);
try {
cUp = this.getClass().getResource("carUp.jpg");
cLeft = this.getClass().getResource("carLeft.jpg");
cRight = this.getClass().getResource("carRight.jpg");
} catch(Exception e) {
}
//attach the URLs to the images
img1 = Toolkit.getDefaultToolkit().getImage(cUp);
img2 = Toolkit.getDefaultToolkit().getImage(cLeft);
img3 = Toolkit.getDefaultToolkit().getImage(cRight);
repaint();
Move1 m1 = new Move1();
m1.start();
}
//this will draw the cars and the race track
public void paint(Graphics g) {
super.paint(g);
//draw the background for the racetrack
g.setColor(Color.DARK_GRAY);
g.fillRect(0,0,WIDTH,HEIGHT);
//when we draw, the border will be green
g.setColor(Color.GREEN);
//fill rectangle
g.fillRect(left.x,left.y,left.width,left.height);
g.fillRect(right.x,right.y,right.width,right.height);
g.fillRect(top.x,top.y,top.width,top.height);
g.fillRect(bottom.x,bottom.y,bottom.width,bottom.height);
g.fillRect(center.x,center.y,center.width,center.height);
g.fillRect(obstacle.x,obstacle.y,obstacle.width,obstacle.height);
g.fillRect(obstacle2.x,obstacle2.y,obstacle2.width,obstacle2.height);
g.fillRect(obstacle3.x,obstacle3.y,obstacle3.width,obstacle3.height);
g.fillRect(obstacle4.x,obstacle4.y,obstacle3.width,obstacle4.height);
g.fillRect(obstacle5.x,obstacle5.y,obstacle5.width,obstacle5.height);
//set the starting line color to white
g.setColor(Color.WHITE);
//now draw the starting line
g.fillRect(lineO.x,lineO.y,lineO.width,lineO.height);
g.fillRect(lineI.x,lineI.y,lineI.width,lineI.height);
//set the color of the finish line to yellow
g.setColor(Color.YELLOW);
//now draw the finish line
g.fillRect(finish.x,finish.y,finish.width,finish.height);
//set the color to blue for p1
g.setColor(Color.WHITE);
//now draw the actual player
g.fill3DRect(p1.x,p1.y,p1.width,p1.height,true);
//draw the images for the player
if(p1Direction==UP)
g.drawImage(img1,p1.x,p1.y,this);
if(p1Direction==LEFT)
g.drawImage(img2,p1.x,p1.y,this);
if(p1Direction==RIGHT)
g.drawImage(img3,p1.x,p1.y,this);
}
private class Move1 extends Thread implements KeyListener {
public void run() {
//now, this should all be in an infinite loop, so the process
//repeats
addKeyListener(this);
while(true) {
//now, put the code in a try block. This will let the
//program exit
//if there is an error.
try {
//first, refresh the screen:
repaint();
//increase speed a bit
// if(p1Speed<=5)
// p1Speed+=.2;
//p1.y-=(int) p1Speed;
if(p1.intersects(left) || p1.intersects(right) || p1.intersects(top) || p1.intersects(bottom) || p1.intersects(obstacle) || p1.intersects(obstacle2)|| p1.intersects(obstacle3) || p1.intersects(obstacle4) || p1.intersects(obstacle5)) {
p1Speed = -5;
}
//if the car hits the center, do the same as above
//but make the speed -2.5.
if(p1.intersects(center)) {
p1Speed = -5;
}
//increase speed a bit
if(p1Speed<=5)
p1Speed+=.2;
//these will move the player based on direction
if(p1Direction==UP) {
p1.y-=(int)p1Speed;
//repaint();
}
if(p1Direction==DOWN) {
p1.y+=(int)p1Speed;
//repaint();
}
if(p1Direction==LEFT) {
p1.x-=(int)p1Speed;
//repaint();
}
if(p1Direction==RIGHT) {
p1.x+=(int)p1Speed;
//repaint();
}
//this delays the refresh rate:
Thread.sleep(200);
} catch(Exception e) {
//if there is an exception (an error), exit the loop.
break;
}
}
}
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent event) {
if(event.getKeyChar()=='a') {
p1Direction = LEFT;
repaint();
}
if(event.getKeyChar()=='s') {
p1Direction = DOWN;
repaint();
}
if(event.getKeyChar()=='d') {
p1Direction = RIGHT;
repaint();
}
if(event.getKeyChar()=='w') {
p1Direction = UP;
repaint();
}
}
}
//this starts the program by calling the constructor:
public static void main (String[ ] args) {
new MAP();
}
}

Don't draw directly in the JFrame in its paint method. Instead draw in a JPanel or JComponent and override its paintComponent method since Swing does double buffering by default, and this will allow you to take advantage of this.

You need to buffer your drawing instead of drawing right on the frame. See this related question and also the API for BufferStrategy.

You can avoid the flickering on your graphical interface by using the Double Buffering Technique. Here is an article that gives one example of double buffering.
This part of the Java Tutorial also gives further advice and examples.

Related

Java, Imported Images flickering even after double buffer (JFrame)

After using a double buffer which I will show below after using imported images they still occasionally flicker. The flickering occurs only in the animated GIF sprites and not in solid tiles such as the ground of the program. I thought it may be the fact that when changing image from a standing position to the moving position of the player there is a moment with no image so it disappears but that cannot be right since the player flickers even when not changing image and just moving.
Base code of the program (compressed a lot of it and removed a bunch for simplicity of reading) :
import javax.swing.*;
import java.awt.*;
public class FrontHand extends JFrame implements Runnable{
public static void main(String []args){
// Start Main Thread
FrontHand Thread1 = new FrontHand();
Thread1.run();
}
// Define Frame Properties
private FrontHand(){
ImageImport.main();
setSize(1600, 900);
setResizable(false);
setFocusable(true);
setVisible(true);
requestFocus();
addKeyListener(new AL());
addMouseListener(new ML());
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
// Frame Double Buffer
public void paint(Graphics g){
Image dbImage = createImage(getWidth(), getHeight());
Graphics dbg = dbImage.getGraphics();
paintComponents(dbg);
g.drawImage(dbImage, 0, 0, this);
}
// Call paint functions
public void paintComponents(Graphics g){
// draw GUI
InVar.GUI.paintIcon(this, g, 0, 0);
// draw Ground Tiles
for (int i = 0; i != 10; i++) {
for (int n = 0; n != 22; n++) {
InVar.grass_tile.paintIcon(this, g, n * 62 + 118, 106 + i * 62);
// g.drawRect(n * 62 + 118, 106 + i * 62, 62, 62);
}
}
// Draw Player
InVar.player.paintIcon(this, g, InVar.player_x, InVar.player_y);
repaint();
}
// player movement
private void move(){PRETEBD THERE IS ADDITION AND SUBTRACTION TO THE PLAYER X AND Y HERE}
// check if there is any tiles left to move too and if null then redefine as non moving
if (InVar.p_m_x_counter == 0 && InVar.p_m_y_counter == 0){
InVar.player_moving = false;
// change the sprite of the player to the corresponding stationary one to the current player's sprite
if (InVar.player == InVar.player_m_up){
InVar.player = InVar.player_s_up;
}
else if (InVar.player == InVar.player_m_down){
InVar.player = InVar.player_s_down;
}
else if (InVar.player == InVar.player_m_left){
InVar.player = InVar.player_s_left;
}
else if (InVar.player == InVar.player_m_right){
InVar.player = InVar.player_s_right;
}
}
else{
InVar.player_moving = true;
}
}
#Override
public void run(){
while (InVar.game_running){
try{
Thread.sleep(5);
move();
}catch (InterruptedException e){System.out.println("Interrupted Exception Caught, ignore");}
}
}
}
The code that is used to import images :
ImageIcon a_1 = new ImageIcon(FrontHand.class.getResource("/Sprites/Tiles/GrassTile1.jpg"));
a_1.setImage(a_1.getImage());
InVar.grass_tile = a_1;
Before I was using .getScaledInstance for the animated GIF's which is what I also thought was causing the flickering but not using it and just externally changing the size of them did not fix the issue of the flickering.

Java robot class - getting Pixel color after they're painted

I need to create a colorPicker tool for my little ms paint app.
I originally asked how to switch from my Graphics 2D implementation to a Graphics2D-->BufferedImage one, (and then it would be easy to get the pixels) but I have instead been suggested to get the pixel colors thought the robot class.
First of all, here's my MCEVE: NB. It cannot be a single class, it won't save.
import java.awt.*;
import javax.swing.*;
public class Runner {
public static void main(String[] args){
JFrame Maiframe = new JFrame("Paint");
Canvas DrawingBoard = new Canvas();
Maiframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Maiframe.setSize(700, 500);
Maiframe.add(DrawingBoard);
Maiframe.setVisible(true);
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
public class Canvas extends JPanel {
public int xp; //present x
public int yp; //present y
public int xo; //old x
public int yo; //old y (Drawing from starting to new point as mouse drags)
public Canvas(){
super();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
xo = e.getX();
yo = e.getY();
Color col = RGBFinder();
System.out.println("RGB : Red =" + col.getRed() + "Green" + col.getGreen() + "Blue" + col.getRed());
}
});
addMouseMotionListener(new MouseMotionAdapter() { //get coords as mouse drags
#Override
public void mouseDragged(MouseEvent e) {
xp = e.getX();
yp = e.getY();
if(SwingUtilities.isLeftMouseButton(e))
repaint(); //call paintcomponent
}
public void mouseMoved(MouseEvent e1){ //keep trak of coords when mouse is not dragging
xo = e1.getX();
yo = e1.getY();
}
});
}
public void draw(int x, int y, Graphics g){ //draw the line
if(xo != 0)
g.drawLine(xo, yo, x, y);
xo = x; //old x is now present x and so on
yo = y;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
draw(xp, yp, g);
}
}
public Color RGBFinder(){
try{
robot = new Robot();
}
catch(AWTException e){
System.out.println("Could not create color picker robot");
}
PointerInfo pi = MouseInfo.getPointerInfo();
Point p = pi.getLocation();
Color pixelColor = robot.getPixelColor(p.x, p.y);
//also tried robot.getPixelColor(p.getX(), p.getY());
//also tried to pass coordinates from listener to RGBFinder, and use those, no luck. (event.getX() ...)
return pixelColor;
}
And it works just fine.
I needed to implement something to get the color from any pixel, when the mouse clicks.
I did this: (adding this method to Canvas, and calling it from the mouse clicker listener)
public Color RGBFinder(){
try{
robot = new Robot();
}
catch(AWTException e){
System.out.println("Could not create color picker robot");
}
PointerInfo pi = MouseInfo.getPointerInfo();
Point p = pi.getLocation();
Color pixelColor = robot.getPixelColor(p.x, p.y);
//also tried robot.getPixelColor(p.getX(), p.getY());
//also tried to pass coordinates from listener to RGBFinder, and use those, no luck. (event.getX() ...)
return pixelColor;
}
Example of call:
//replace old mouseListener with this
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
xo = e.getX();
yo = e.getY();
Color col = RGBFinder();
System.out.println(" da tela Red =" + col.getRed() + "Green" + col.getGreen() + "Blue" + col.getRed());
}
});
Unfortunately, from this implementation I get undefined behaviour. The color read is always 255, 255, 255. Exept if I color the hole panel, then it gets it right 9 times out of 10, but in some areas it's still missing it.
I have also tried wrapping the whole thing into a bufferedImage with robot#screenCap but that doesn't even remotely work.
What am I doing wrong here?
Thank you very much.
EDIT1:
There are doubts as to how a line can remain on screen after a second one has been drawn. I'll provide a screenshot:
NBB. This works because an instance of Canvas is create inside of a JFrame into Runnable, so the changes are saved, avoiding the need for shapes and arrayLists.
I'll also add a full version of the code which prints wrong RGB results, remember that this does not save the lines as it stands. Please refer to the two separate classes above for testing.
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
public class Canvas extends JPanel{
public int xp; //present x
public int yp; //present y
public int xo; //old x
public int yo; //old y (Drawing from starting to new point as mouse drags)
public Robot robot;
public static void main(String[] args){
JFrame Maiframe = new JFrame("Paint");
Canvas DrawingBoard = new Canvas();
Maiframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Maiframe.setSize(700, 500);
Maiframe.add(DrawingBoard);
Maiframe.setVisible(true);
}
public Canvas(){
super();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
xo = e.getX();
yo = e.getY();
Color col = RGBFinder();
System.out.println("RGB --> Red =" + col.getRed() + "Green" + col.getGreen() + "Blue" + col.getRed());
}
});
addMouseMotionListener(new MouseMotionAdapter() { //get coords as mouse drags
#Override
public void mouseDragged(MouseEvent e) {
xp = e.getX();
yp = e.getY();
if(SwingUtilities.isLeftMouseButton(e))
repaint(); //call paintcomponent
}
public void mouseMoved(MouseEvent e1){ //keep trak of coords when mouse is not dragging
xo = e1.getX();
yo = e1.getY();
}
});
}
public void draw(int x, int y, Graphics g){ //draw the line
if(xo != 0)
g.drawLine(xo, yo, x, y);
xo = x; //old x is now present x and so on
yo = y;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
draw(xp, yp, g);
}
public Color RGBFinder(){
try{
robot = new Robot();
}
catch(AWTException e){
System.out.println("Could not create color picker robot");
}
PointerInfo pi = MouseInfo.getPointerInfo();
Point p = pi.getLocation();
Color pixelColor = robot.getPixelColor(p.x, p.y);
//also tried robot.getPixelColor(p.getX(), p.getY());
//also tried to pass coordinates from listener to RGBFinder, and use those, no luck. (event.getX() ...)
return pixelColor;
}
}
my little ms paint app
Well its not much of a paint app. All it does is draw a single line. Whenever you attempt to draw the second line the first will be removed.
So the first step you need to do is decide how you want the painting to work. There are two common approaches:
Store Objects you want to paint in an ArrayList and then the paintComponent(...) method will paint each Object in the List.
Paint directly to a BufferedImage and then the paintComponent(...) method can just paint the BufferedImage.
Check out Custom Painting Approaches for working examples of both of these approaches and give the pros/cons of using each approach.
I have instead been suggested to get the pixel colors thought the robot class
It depends which painting approach you want to use.
If you use the Draw on Component approach then you would use the MouseInfo and Robot to get the pixel color:
PointerInfo pi = MouseInfo.getPointerInfo();
Point p = pi.getLocation();
System.out.println( robot.getPixelColor(p.x, p.y) );
If you use the Draw on Image approach then you would get the pixel color from the BufferedImage:
int rgb = bufferedImage.getRGB(mouseEvent.getX(), mouseEvent.getY());
Color color = new Color( rgb );
System.out.println( color );
Final Update
You still have not posted a SSCCE. The code you posted does NOT draw a line. Even if it did draw a line, how do you expect us to click (with accuracy) a single pixel line.
The point of a SSCCE is to demonstrate the concept you are asking about. You are asking how to get the Color of a pixel on your panel. How the drawing gets on the panel is irrelevant to the question so the painting code should be as simple as possible.
Following is a proper SSCCE. Note:
The createAndShowGUI() and main() methods will be the same for all SSCCE. The difference is the `DrawingPanel code/class will change to demonstrate your problem.
The custom painting is hardcoded. There is no need for mouseMoved/mouseDragged logic (unless that is the problem) you are trying to solve. All you care about is having different colors to click on.
Just use a simple System.out.println(...) to display the value of the Color object.
All I did was copy the relevant pieces of code from you class and remove the irrelevant code to keep the code simple and straight forward. Anybody can do that.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DrawingCanvas extends JPanel
{
private Robot robot;
public DrawingCanvas()
{
addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
try
{
robot = new Robot();
}
catch(Exception re) { System.out.println(re); }
PointerInfo pi = MouseInfo.getPointerInfo();
Point p = pi.getLocation();
Color pixelColor = robot.getPixelColor(p.x, p.y);
System.out.println(pixelColor);
}
});
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor( Color.RED );
g.fillRect(0, 0, 40, 40);
g.setColor( Color.GREEN );
g.fillRect(40, 40, 40, 40);
g.setColor( Color.BLUE );
g.fillRect(80, 80, 40, 40);
}
private static void createAndShowGUI()
{
JPanel panel = new DrawingCanvas();
JFrame frame = new JFrame("DrawingCanvas");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setSize(200, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() ); // Java 8 only
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
Just copy/paste/compile/execute to see that the code works.
I'll let you figure out why your code doesn't appear to work.
NBB. This works because an instance of Canvas is create inside of a JFrame into Runnable, so the changes are saved, avoiding the need for shapes and arrayLists.
That statement is completely wrong. Painting done with the Graphics Object in the paintComponent() method is only temporary until the next time the paintComponent() method is invoked.
For example add the following code after the frame.setVisible() statement:
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Graphics g = panel.getGraphics();
g.setColor( Color.YELLOW );
g.fillRect(120, 120, 40, 40);
}
});
The yellow square will disappear when the frame is resized. For permanent painting you need to use one of the two approaches I suggested in my original answer.
Edit 2:
This is the output I get when I click on the red, green, blue, background respectively:
C:\Java>java DrawingCanvas
java.awt.Color[r=255,g=0,b=0]
java.awt.Color[r=0,g=255,b=0]
java.awt.Color[r=0,g=0,b=255]
java.awt.Color[r=238,g=238,b=238]

Why doesn't my code go in the keyPressed() method? (Even if i press keys)

I'm trying to create a brickbreakers game. Obviously i'm still struggling with the beginning of it. I need my "block" to move but if i press some key my code won't even go in the keyPressed()-method. Does anybody know why?
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class VGKernel extends JPanel implements KeyListener {
public Rectangle screen, ball, block; // The screen area and ball location/size.
public Rectangle bounds; // The boundaries of the drawing area.
public JFrame frame; // A JFrame to put the graphics into.
public VGTimerTask vgTask; // The TimerTask that runs the game.
public boolean down, right; // Direction of ball's travel.
public VGKernel(){
super();
screen = new Rectangle(0, 0, 600, 400);
ball = new Rectangle(0, 0, 20, 20);
block = new Rectangle(0, 350, 40, 10);
bounds = new Rectangle(0, 0, 600, 400); // Give some starter values.
frame = new JFrame("VGKernel");
vgTask = new VGTimerTask();
addKeyListener(this);
}
class VGTimerTask extends TimerTask{
public void run(){
moveBall();
frame.repaint();
}
}
// Now the instance methods:
public void paintComponent(Graphics g){
// Get the drawing area bounds for game logic.
bounds = g.getClipBounds();
// Clear the drawing area, then draw the ball.
g.clearRect(screen.x, screen.y, screen.width, screen.height);
g.fillRect(ball.x, ball.y, ball.width, ball.height);
g.fillRect(block.x, block.y, block.width, block.height);
}
public void moveBall(){
// Ball should really be its own class with this as a method.
if (right) ball.x+=1; // If right is true, move ball right,
else ball.x-=1; // otherwise move left.
if (down) ball.y+=1; // Same for up/down.
else ball.y-=1;
if (ball.x > (bounds.width - ball.width)) // Detect edges and bounce.
{ right = false; ball.x = bounds.width - ball.width; }
if (ball.y > (bounds.height - ball.height))
{ down = false; ball.y = bounds.height - ball.height;}
if (ball.x <= 0) { right = true; ball.x = 0; }
if (ball.y <= 0) { down = true; ball.y = 0; }
}
public void keyPressed(KeyEvent evt) {
if(evt.getKeyCode() == KeyEvent.VK_G && block.x > 0) {
block.x -= 10;
}
if(evt.getKeyCode() == KeyEvent.VK_H && block.x < 560) {
block.x += 10;
}
}
public void keyTyped(KeyEvent evt){ }
public void keyReleased(KeyEvent evt){ }
public static void main(String arg[]){
java.util.Timer vgTimer = new java.util.Timer(); // Create a Timer.
VGKernel panel = new VGKernel(); // Create and instance of our kernel.
// Set the intial ball movement direction.
panel.down = true;
panel.right = true;
// Set up our JFRame
panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.frame.setSize(panel.screen.width, panel.screen.height);
panel.frame.setContentPane(panel);
panel.frame.setVisible(true);
// Set up a timer to do the vgTask regularly.
vgTimer.schedule(panel.vgTask, 0, 10);
}
}
Put
setFocusable(true);
inside your constructor.

main methods and key listener

Would anyone be able to tell me why this program says I am missing a main method? I have one at the bottom of this code.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class Collision extends JFrame
{
final int WIDTH = 900, HEIGHT = 650;
double p1Speed = .5, p2Speed = .5;
//these are the ints that represent directions
final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3;
//these will keep track of the players directions(default = up)
int p1Direction = UP;
int p2Direction = UP;
Rectangle left = new Rectangle(0,0,WIDTH/9,HEIGHT);
Rectangle right = new Rectangle((WIDTH/9)*8,0,WIDTH/9,HEIGHT);
Rectangle top = new Rectangle(0,0,WIDTH,HEIGHT/9);
Rectangle bottom = new Rectangle(0,(HEIGHT/9)*8, WIDTH,HEIGHT/9);
Rectangle center = new Rectangle((int)((WIDTH/9)* 2.5),(int)((HEIGHT/9)*2.5),(int)
((WIDTH/9)*5),(HEIGHT/9)*4);
Rectangle obstacle = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*7),WIDTH/10,HEIGHT/9);
Rectangle obstacle2 = new Rectangle(WIDTH/3,(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4);
Rectangle obstacle3 = new Rectangle(2*(WIDTH/3),(int)
((HEIGHT/9)*5),WIDTH/10,HEIGHT/4);
Rectangle obstacle4 = new Rectangle(WIDTH/3,HEIGHT/9,WIDTH/30,HEIGHT/9);
Rectangle obstacle5 = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*1.5),WIDTH/30,HEIGHT/4);
Rectangle finish = new Rectangle(WIDTH/9,(HEIGHT/2)-HEIGHT/9,(int)
((WIDTH/9)*1.5),HEIGHT/70);
Rectangle p1 = new Rectangle(WIDTH/9,HEIGHT/2, WIDTH/30,WIDTH/30);
Rectangle p2 = new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+
(HEIGHT/10),WIDTH/30,WIDTH/30);
public Collision()
{
//the following code creates the JFrame
super("Radical Racing");
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
//start the inner class (which works on it's own because it is a thread)
Move1 m1 = new Move1();
Move2 m2 = new Move2();
m1.start();
m2.start();
}
public void paint(Graphics g)
{
super.paint(g);
//draw the bckround for the racetrack
g.setColor(Color.DARK_GRAY);
g.fillRect(0,0,WIDTH,HEIGHT);
//When we drawthe border will be green
g.setColor(Color.GREEN);
//the following rectangle is the start line for the outer player
Rectangle lineO = new
Rectangle(WIDTH/9,HEIGHT/2,(int)((WIDTH/9)*1.5)/2,HEIGHT/140);
//the following rctangle is the start line for the inner player
Rectangle lineI = new
Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+(HEIGHT/10),
(int)((WIDTH/9)*1.5)/2,HEIGHT/140);
//now using the rectangles, draw it
g.fillRect(left.x,left.y,left.width,left.height);
g.fillRect(right.x,right.y,right.width,right.height);
g.fillRect(top.x,top.y,top.width,top.height);
g.fillRect(bottom.x,bottom.y,bottom.width,bottom.height);
g.fillRect(center.x,center.y,center.width,center.height);
g.fillRect(obstacle.x,obstacle.y,obstacle.width,obstacle.height);
g.fillRect(obstacle2.x,obstacle2.y,obstacle2.width,obstacle2.height);
g.fillRect(obstacle3.x,obstacle3.y,obstacle3.width,obstacle3.height);
g.fillRect(obstacle4.x,obstacle4.y,obstacle4.width,obstacle4.height);
g.fillRect(obstacle5.x,obstacle5.y,obstacle5.width,obstacle5.height);
//set the starting line color
g.setColor(Color.WHITE);
//the draw the starting line
g.fillRect(lineO.x,lineO.y,lineO.width,lineO.height);
g.fillRect(lineI.x,lineI.y,lineI.width,lineI.height);
//set the color of the finish line to yellow
g.setColor(Color.YELLOW);
g.fillRect(finish.x,finish.y,finish.width,finish.height);
//set the color to blue for p1
g.setColor(Color.BLUE);
//now draw the actual player
g.fill3DRect(p1.x,p1.y,p1.width,p1.height,true);
//set the color to red for p2
g.setColor(Color.red);
//now draw the actual player
g.fill3DRect(p2.x,p2.y,p2.width,p2.height,true);
}
private class Move1 extends Thread implements KeyListener
{
public void run()
{
//add the code to make the KeyListener "wake up"
addKeyListener(this);
//now, put the code should all be in an infinite loop, so the process repeats.
while(true)
{
try
{
//first refresh the screen:
repaint();
//check to see if the car hits the outside of the walls.
//If so make it slow it's speed by setting it's speed to .4.
if(p1.intersects(left) || p1.intersects(right) ||
p1.intersects(top) || p1.intersects(bottom) ||
p1.intersects(obstacle) || p1.intersects(obstacle2) ||
p1.intersects(p2) || p1.intersects(obstacle3) ||
p1.intersects(obstacle4) || p1.intersects(obstacle5))
{
p1Speed = -4;
}
if(p1.intersects(center))
{
p1Speed = -2.5;
}
//increase speed a bit
if(p1Speed<=5)
p1Speed+=.2;
//these will move the player based on direction
if(p1Direction == UP)
{
p1.y-=(int)p1Speed;
}
if(p1Direction ==DOWN)
{
p1.y+=(int)p1Speed;
}
if(p1Direction == LEFT)
{
p1.x-=(int)p1Speed;
}
if(p1Direction == RIGHT)
{
p1.x+=(int)p1Speed;
}
//This delays the refresh rate
Thread.sleep(75);
}
catch(Exception e)
{//if there is an exception (an error), exit the loop
break;
}
}
}
//You must also implement this method from Key Listener
public void keyPressed(KeyEvent event)
{
}
//You must also implement this method from key listener
public void keyReleased(KeyEvent event)
{
}
//You must also implement this method from key listener
public void keyTyped(KeyEvent event)
{
if(event.getKeyChar()=='a')
{
p1Direction = LEFT;
}
if(event.getKeyChar()=='s')
{
p1Direction = DOWN;
}
if(event.getKeyChar()=='d')
{
p1Direction = RIGHT;
}
if(event.getKeyChar()=='w')
{
p1Direction = UP;
}
}
}
private class Move2 extends Thread implements KeyListener
{
public void run()
{
//add the code to make the key listener wake up
addKeyListener(this);
//now this should all be in an infinite loop so that the process repeats
while(true)
{
try
{
//first refresh the screen
repaint();
//check to see if the car hits the outside walls.
//if so make it slow its speed by setting it's speed to -4.
if(p2.intersects(left) || p2.intersects(right) ||
p2.intersects(top) || p2.intersects(bottom) ||
p2.intersects(obstacle) || p2.intersects(obstacle2) ||
p1.intersects(p2))
{
p2Speed = -4;
}
if(p2.intersects(center))
{
p2Speed = -2.5;
}
//increase speed a bit
if(p2Speed<=5)
p2Speed = .2;
//these will move the player based off direction
if(p2Direction == UP)
{
p2.y-=(int)p2Speed;
}
if(p2Direction ==DOWN)
{
p2.y+=(int)p2Speed;
}
if(p2Direction == LEFT)
{
p2.x-=(int)p2Speed;
}
if(p2Direction == LEFT)
{
p2.x+=(int)p2Speed;
}
//this delays the refresh rate:
Thread.sleep(75);
}
catch(Exception e)
{
//if there is an exception, exit the loop.
break;
}
}
}
//you must also implement this method from key listener
public void keyPressed(KeyEvent event)
{
}
public void keyReleased(KeyEvent event)
{
}
public void keyTyped(KeyEvent event)
{
if(event.getKeyChar()=='j')
{
p2Direction = LEFT;
}
if(event.getKeyChar()=='k')
{
p2Direction = DOWN;
}
if(event.getKeyChar()=='l')
{
p2Direction = RIGHT;
}
if(event.getKeyChar()=='i')
{
p2Direction = UP;
}
}
//This starts the program by calling the constructor:
public static void main(String [] args)
{
new Collision();
}
}
KeyListeners only work if the component listened to has the focus, and often KeyListeners fail because this is not so. So one thing to do is to test this, and if the component has lost the focus than do things to correct this.
But having said this, I have to ask what book you're using, since in general, you want to avoid using KeyListeners with Swing applications in favor of Key Bindings. Also, it is usually not recommended to draw directly in a JFrame, so you may wish to use a different book.

Repaint leaves trail

I know that this isn't the first time that this question has been asked, but the responses haven't helped me much, so I am helping I am finally going to get my answer
I have made this little game where I have made a car drive around a track (using rectangles was mandatory). When I use the repaint() metod the rectangle representing the car repaints in the new location, but leaves a trail behind.
I have this code:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class MAP extends JFrame
{
//constant for the screen size and used for the drawing the terrain
final int WIDTH = 900, HEIGHT = 650;
//the URL and Img designed for the images
URL cLeft,cRight,cUp;
Image img1,img2,img3;
//these will keep track of each player’s speed:
double p1Speed =.5;
//these are ints that represent directions:
final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3;
//these will keep track of the player’s directions (default = up)
int p1Direction = 0;
JPanel panel;
//draw the terrain
Rectangle left = new Rectangle(0,0,WIDTH/9,HEIGHT);
Rectangle right = new Rectangle((WIDTH/9)*9,0,WIDTH/9,HEIGHT);
Rectangle top = new Rectangle(0,0,WIDTH, HEIGHT/9);
Rectangle bottom = new Rectangle(0,(HEIGHT/9)*9,WIDTH,HEIGHT/9);
Rectangle center = new Rectangle((int)((WIDTH/9)*2.5),(int)((HEIGHT/9)*2.5),(int)((WIDTH/9)*5),(HEIGHT/9)*4);
//these obstacles will obstruct the path and make navigating harder
Rectangle obstacle = new
Rectangle(WIDTH/2,(int)((HEIGHT/9)*7),WIDTH/10,HEIGHT/9);
Rectangle obstacle2 = new
Rectangle(WIDTH/3,(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4);
Rectangle obstacle3 = new
Rectangle(2*(WIDTH/3),(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4);
Rectangle obstacle4 = new Rectangle(WIDTH/3,HEIGHT/9,WIDTH/30,HEIGHT/9);
Rectangle obstacle5 = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*1.5),WIDTH/30,HEIGHT/4);
Rectangle finish = new Rectangle(WIDTH/9,(HEIGHT/2)-HEIGHT/9,(int)((WIDTH/9)*1.5),HEIGHT/70);
Rectangle lineO=new Rectangle(WIDTH/9,HEIGHT/2,(int)((WIDTH/9)*1.5)/2,HEIGHT/140);
Rectangle lineI = new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+(HEIGHT/10),(int)((WIDTH/9)*1.5)/2, HEIGHT/140);
//this is the rectangle for player 1’s (outer) car:
Rectangle p1 = new Rectangle(WIDTH/9,HEIGHT/2, WIDTH/30,WIDTH/30);
public MAP(){
super("Radical Racing");
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setResizable(false);
setVisible(true);
setLocationRelativeTo(null);
//the following code creates the JFrame
try
{
cUp = this.getClass().getResource("carUp.jpg");
cLeft = this.getClass().getResource("carLeft.jpg");
cRight = this.getClass().getResource("carRight.jpg");
}catch(Exception e)
{}
//attach the URLs to the images
img1 = Toolkit.getDefaultToolkit().getImage(cUp);
img2 = Toolkit.getDefaultToolkit().getImage(cLeft);
img3 = Toolkit.getDefaultToolkit().getImage(cRight);
panel=new JPanel(){
public void paint(Graphics g)
{
//super.paint(g);
//draw the background for the racetrack
g.setColor(Color.DARK_GRAY);
g.fillRect(0,0,WIDTH,HEIGHT);
//when we draw, the border will be green
g.setColor(Color.GREEN);
//fill rectangle
g.fillRect(left.x,left.y,left.width,left.height);
g.fillRect(right.x,right.y,right.width,right.height);
g.fillRect(top.x,top.y,top.width,top.height);
g.fillRect(bottom.x,bottom.y,bottom.width,bottom.height);
g.fillRect(center.x,center.y,center.width,center.height);
g.fillRect(obstacle.x,obstacle.y,obstacle.width,obstacle.height);
g.fillRect(obstacle2.x,obstacle2.y,obstacle2.width,obstacle2.height);
g.fillRect(obstacle3.x,obstacle3.y,obstacle3.width,obstacle3.height);
g.fillRect(obstacle4.x,obstacle4.y,obstacle3.width,obstacle4.height);
g.fillRect(obstacle5.x,obstacle5.y,obstacle5.width,obstacle5.height);
//set the starting line color to white
g.setColor(Color.WHITE);
//now draw the starting line
g.fillRect(lineO.x,lineO.y,lineO.width,lineO.height);
g.fillRect(lineI.x,lineI.y,lineI.width,lineI.height);
//set the color of the finish line to yellow
g.setColor(Color.YELLOW);
//now draw the finish line
g.fillRect(finish.x,finish.y,finish.width,finish.height);
//set the color to blue for p1
g.setColor(Color.WHITE);
//now draw the actual player
g.fill3DRect(p1.x,p1.y,p1.width,p1.height,true);
//draw the images for the player
if(p1Direction==UP)
g.drawImage(img1,p1.x,p1.y,this);
if(p1Direction==LEFT)
g.drawImage(img2,p1.x,p1.y,this);
if(p1Direction==RIGHT)
g.drawImage(img3,p1.x,p1.y,this);
}
};
panel.setPreferredSize(new Dimension(950,600));
this.add(panel);
pack();
Move1 move=new Move1();
move.start();
}
private class Move1 extends Thread implements KeyListener
{
public void run()
{
//now, this should all be in an infinite loop, so the process
//repeats
addKeyListener(this);
while(true)
{
//now, put the code in a try block. This will let the
//program exit
//if there is an error.
try
{
//increase speed a bit
// if(p1Speed<=5)
// p1Speed+=.2;
//p1.y-=(int) p1Speed;
if(p1.intersects(left) || p1.intersects(right) || p1.intersects(top) ||
p1.intersects(bottom) || p1.intersects(obstacle) || p1.intersects(obstacle2)||
p1.intersects(obstacle3) || p1.intersects(obstacle4) || p1.intersects(obstacle5))
{
p1Speed = -5;
}
//if the car hits the center, do the same as above
//but make the speed -2.5.
if(p1.intersects(center))
{
p1Speed = -2.5;
}
//increase speed a bit
if(p1Speed<=5)
p1Speed+=.2;
//these will move the player based on direction
if(p1Direction==UP)
{
p1.y-=(int)p1Speed;
}
if(p1Direction==DOWN)
{
p1.y+=(int)p1Speed;
}
if(p1Direction==LEFT)
{
p1.x-=(int)p1Speed;
}
if(p1Direction==RIGHT)
{
p1.x+=(int)p1Speed;
}
panel.repaint();
//this delays the refresh rate:
Thread.sleep(200);
}
catch(Exception e)
{
//if there is an exception (an error), exit the loop.
break;
}
}
}
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent event) {
if(event.getKeyChar()=='a')
{
p1Direction = LEFT;
}
if(event.getKeyChar()=='s')
{
p1Direction = DOWN;
}
if(event.getKeyChar()=='d')
{
p1Direction = RIGHT;
}
if(event.getKeyChar()=='w')
{
p1Direction = UP;
}
}
}
//this starts the program by calling the constructor:
public static void main (String[ ] args)
{
new MAP();
}
}
Uncomment super.paint(g) [line 87] in your paint method.
It is responsible for clearing the canvas of any stale objects.
The reason is that in the line g.fillRect(0,0,WIDTH,HEIGHT); it actually is referring to java.awt.image.ImageObserver#WIDTH and java.awt.image.ImageObserver#HEIGHT instead of your instance variables. You can see this with any IDE.
Because of that the expected black background is painted only in a 1x2 pixel area in the top-left corner. And since the call to super.paint(g); is commented out, not even the gray background is repainted. As a result, old drawings of the car are not overdrawn.
The code needs to be changed to use MAP.this.WIDTH, or the WIDTH field needs to be renamed to something which does not conflict with the fields inherited from JPanel, or the field needs to be moved into the same JPanel to have higher precedence, or you could also use the getWidth() method from JPanel. And likewise for height.

Categories