Nick Catlin
Nick Catlin

Reputation: 49

How can I prevent flashing?

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Racing extends JFrame {
private static final long serialVersionUID = -198172151996959655L;

//makes the screen size
final int WIDTH = 900, HEIGHT = 650;

//keeps track of player speed
double plSpeed = .5;

//numbers that represent direction
final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3, STOP = 5, START = 6;

//keeps track of player direction
int p1Direction = START;

//makes player 1's car
Rectangle p1 = new Rectangle ( 100, 325, 30, 30 );
Rectangle foreground = new Rectangle( 500, 500, 200, 200 );

//constructor
public Racing() {
    //define defaults for the JFrame
    super ("Racing");
    setSize( WIDTH, HEIGHT );
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    setBackground(Color.BLACK);

    //start the inner class
    Move1 m1 = new Move1();
    m1.start();
}

//draws the cars and race track
public void paint(Graphics g) {

    super.paint(g);
    //draw p1
    g.setColor(Color.RED);
    g.fillRect(p1.x,p1.y,p1.width,p1.height);
    g.setColor(Color.GREEN);
    g.fillRect(foreground.x,foreground.y,foreground.width,foreground.height);

}
private class Move1 extends Thread implements KeyListener {
    public void run() {
        //makes the key listener "wake up"
        addKeyListener(this);

        //should be done in an infinite loop, so it repeats
        while (true) {
            //make try block, so it can exit if it errors
            try {
                //refresh screen
                repaint();

                //makes car increase speed a bit
                if (plSpeed <= 7) {
                    plSpeed += .2;
                }

                //lets the car stop
                if (plSpeed==0) {
                    p1Direction = STOP;
                }

                //moves player based on direction
                if (p1Direction==UP) {
                    p1.y -= (int) plSpeed;
                }
                if (p1Direction==DOWN) {
                    p1.y += (int) plSpeed;
                }
                if (p1Direction==LEFT) {
                    p1.x -= (int) plSpeed;
                }
                if (p1Direction==RIGHT) {
                    p1.x += (int) plSpeed;
                }
                if (p1Direction==STOP) {
                    plSpeed = 0;
                }

                //delays refresh rate
                Thread.sleep(75);

            }
            catch(Exception e) {
                //if an error, exit
                break;
            }
        }
    }

    //have to input these (so it will compile)
    public void keyPressed(KeyEvent event) {
        try {
            //makes car increase speed a bit
            if (event.getKeyChar()=='w' ||
                event.getKeyChar()=='a' ||
                event.getKeyChar()=='s' ||
                event.getKeyChar()=='d') {
                    plSpeed += .2;
                    repaint();
            }
        } catch (Exception I) {}
    }
    public void keyReleased(KeyEvent event) {}

    //now, to be able to set the direction
    public void keyTyped(KeyEvent event) {
        if (plSpeed > 0) {
            if (event.getKeyChar()=='a') {
                if (p1Direction==RIGHT) {
                    p1Brake();
                } else {
                    if (p1Direction==LEFT) {
                    } else {
                        p1Direction = LEFT;
                    }
                }
            }
            if (event.getKeyChar()=='s') {
                if (p1Direction==UP) {
                    p1Brake();
                } else {
                    if (p1Direction==DOWN) {
                    } else {
                        p1Direction = DOWN;
                    }
                }
            }
            if (event.getKeyChar()=='d') {
                if (p1Direction==LEFT) {
                    p1Brake();
                } else {
                    if (p1Direction==RIGHT) {
                    } else {
                        p1Direction = RIGHT;
                    }
                }
            }
            if (event.getKeyChar()=='w') {
                if (p1Direction==DOWN) {
                    p1Brake();
                } else {
                    if (p1Direction==UP) {
                    } else {
                        p1Direction = UP;
                    }
                }
            }
            if (event.getKeyChar()=='z') {
                p1Brake();
            }
        }
    }

    public void p1Brake () {
        try {
            while (plSpeed != 0) {
                plSpeed -= .2;
                Thread.sleep(75);
            }
        } catch (Exception e) {
            plSpeed = 0;
        }
    }
}

//finally, to start the program
public static void main(String[] args) {
    Racing frame = new Racing();
    frame.setVisible( true );
    frame.setLocationRelativeTo( null );
    frame.setResizable( false );
}

}

This is an SSCCE of my code. If I add super.paint(g); to the top of this, inside the class, then it gets all flashy. If I leave that out, then whenever you move the player, then it creates a line of where the player has been-without repainting. I need to know how to - and where to repaint. The closest I have gotten to my answer here here:

http://www.java-forums.org/awt-swing/37406-repaint-without-flashing.html

but they have an applet (which I have never dealt with before, and assuming it would be rather tricky to translate the code from applet to frames). Can anybody help me with this?

Notes:

I didn't know you could make a frame with awt, because I was happy and familiar with swing, so I didn't want to change. Sorry about that. As you can see, whatever i draw flashes, not just the player.

Andrew, here's my screenshot: the game

Oh, and it doesn't register P2.

Upvotes: 3

Views: 3779

Answers (3)

dodo
dodo

Reputation: 156

Changing the code from applet to JFrame is not hard at all. Rename the class's extension to JPanel:

public class Racing extends JPanel

then in the method where you instantiate a new Racing change it to instantiate a new JFrame and any method in racing like setTitle(...) that now throws an error move to the method that instantiates the new JFrame, as (whatever you named the JFrame reference).setTitle(...) Then apply the following code to the rest of the JFrame:

JFrame.add(new Racing());
JFrame.setSize(*the size of Racing window*);

Upvotes: 0

Andrew Thompson
Andrew Thompson

Reputation: 168815

Racing UI

I made a number of changes. Here are some I can recall.

  1. Refactored custom painting from top-level container to JPanel, and moved painting to paintComponent().
  2. Removed Thread and Thread.sleep(n) & replaced with a Timer/ActionListener.
  3. Constructed the GUI on the EDT.
  4. Removed setting the size of the JFrame. Instead sets a preferred size for the JPanel (the actual drawing area) and calls JFrame.pack() to get the correct overall size.
  5. Uses setLocationByPlatform(true) instead of the very splash-screen like setLocationRelativeTo(null).

Check the code carefully for further tips.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Racing extends JPanel implements KeyListener {
private static final long serialVersionUID = -198172151996959655L;

//keeps track of player speed
double plSpeed = .5;

//numbers that represent direction
final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3, STOP = 5, START = 6;

//keeps track of player direction
int p1Direction = START;

//makes player 1's car
Rectangle p1 = new Rectangle ( 100, 25, 30, 30 );

//constructor
public Racing() {
    //define defaults for the JFrame
    setBackground(Color.BLACK);

    //makes the screen size
    setPreferredSize(new Dimension(400,50));

    //makes the key listener "wake up"
    addKeyListener(this);
    setFocusable(true);

    ActionListener al = new ActionListener() {
        public void actionPerformed(ActionEvent ae) {
            //refresh screen
            repaint();

            //makes car increase speed a bit
            if (plSpeed <= 7) {
                plSpeed += .2;
            }

            //lets the car stop
            if (plSpeed==0) {
                p1Direction = STOP;
            }

            //moves player based on direction
            if (p1Direction==UP) {
                p1.y -= (int) plSpeed;
            }
            if (p1Direction==DOWN) {
                p1.y += (int) plSpeed;
            }
            if (p1Direction==LEFT) {
                p1.x -= (int) plSpeed;
            }
            if (p1Direction==RIGHT) {
                p1.x += (int) plSpeed;
            }
            if (p1Direction==STOP) {
                plSpeed = 0;
            }
        }
    };

    Timer t = new Timer(75,al);
    t.start();
}

//draws the cars and race track
@Override
public void paintComponent(Graphics g) {

    super.paintComponent(g);
    //draw p1
    g.setColor(Color.RED);
    g.fillRect(p1.x,p1.y,p1.width,p1.height);

}

//have to input these (so it will compile)
public void keyPressed(KeyEvent event) {
    System.out.println(event);
    try {
        //makes car increase speed a bit
        if (event.getKeyChar()=='w' ||
            event.getKeyChar()=='a' ||
            event.getKeyChar()=='s' ||
            event.getKeyChar()=='d') {
                plSpeed += .2;
                //repaint();
        }
    } catch (Exception I) {}
}
public void keyReleased(KeyEvent event) {}

//now, to be able to set the direction
public void keyTyped(KeyEvent event) {
    if (plSpeed > 0) {
        if (event.getKeyChar()=='a') {
            if (p1Direction==RIGHT) {
                p1Brake();
            } else {
                if (p1Direction==LEFT) {
                } else {
                    p1Direction = LEFT;
                }
            }
        }
        if (event.getKeyChar()=='s') {
            if (p1Direction==UP) {
                p1Brake();
            } else {
                if (p1Direction==DOWN) {
                } else {
                    p1Direction = DOWN;
                }
            }
        }
        if (event.getKeyChar()=='d') {
            if (p1Direction==LEFT) {
                p1Brake();
            } else {
                if (p1Direction==RIGHT) {
                } else {
                    p1Direction = RIGHT;
                }
            }
        }
        if (event.getKeyChar()=='w') {
            if (p1Direction==DOWN) {
                p1Brake();
            } else {
                if (p1Direction==UP) {
                } else {
                    p1Direction = UP;
                }
            }
        }
        if (event.getKeyChar()=='z') {
            p1Brake();
        }
    }
}

public void p1Brake () {
    try {
        while (plSpeed != 0) {
            plSpeed -= .2;
        }
    } catch (Exception e) {
        plSpeed = 0;
    }
}

//finally, to start the program
public static void main(String[] args) {
    SwingUtilities.invokeLater( new Runnable() {
        public void run() {
            JFrame f = new JFrame("Racing");
            f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
            f.add(new Racing());
            f.pack();
            f.setLocationByPlatform(true);
            f.setResizable( false );
            f.setVisible( true );
        }
    });
}
}

Upvotes: 3

panzerschreck
panzerschreck

Reputation: 3642

You should never attempt to draw directly onto the canvas, use a background thread that keeps the next frame ready always and swap it with the old one.

    while (state == RUNNING)
    {
        long beforeTime = System.nanoTime();
        gEngine.update(); // update stuff like game score life etc..

        Canvas c = null;
        try
        {
            c = mSurfaceHolder.lockCanvas(null);
            synchronized (mSurfaceHolder)
            {                   
                drawable.setBounds(0, 0, 800, 600);
                drawable.draw(c); // flash new background if required for the new frame
                gEngine.draw(c);    // update game state
            }
        } finally
        {
            if (c != null)
            {
                mSurfaceHolder.unlockCanvasAndPost(c);
            }
        }

        this.sleepTime = delay
                - ((System.nanoTime() - beforeTime) / 1000000L);

        try
        {
            if (sleepTime > 0)
            {
                Thread.sleep(sleepTime);
            }
        } catch (InterruptedException ex)
        {
            Logger.getLogger(PaintThread.class.getName()).log(Level.SEVERE,
                    null, ex);
        }

    }
}

Upvotes: 1

Related Questions