3

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();
    }
}
kleopatra
  • 51,061
  • 28
  • 99
  • 211
Stormel
  • 143
  • 3
  • 9
  • *"Any suggestions?"* Fix your shift key and use it once at the start of every sentence, as well as for any use of the word 'I'. – Andrew Thompson Dec 14 '11 at 17:05

3 Answers3

10

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.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
3

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

Community
  • 1
  • 1
Paul
  • 19,704
  • 14
  • 78
  • 96
2

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.

Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192