如何防止闪烁?

时间:2012-01-18 04:54:25

标签: java swing animation graphics

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 );
}

}

这是我的代码的SSCCE。如果我添加super.paint(g);最重要的是,在课堂内,它会变得华而不实。如果我把它留下来,那么每当你移动玩家时,它就会创建一条玩家所在的线 - 而不是重新绘制。我需要知道如何 - 以及在哪里重绘。我在这里最接近我的答案:

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

但他们有一个小程序(我以前从未处理过,并假设将代码从小程序转换为框架相当棘手)。有人可以帮我吗?

注意:

我不知道你可以用awt制作一个框架,因为我很开心并熟悉挥杆,所以我不想改变。对于那个很抱歉。正如你所看到的,无论我画的是什么,而不仅仅是玩家。

安德鲁,这是我的截图: the game

哦,它没有注册P2。

3 个答案:

答案 0 :(得分:3)

Racing UI

我做了一些改变。以下是我记得的一些内容。

  1. 将自定义绘画从顶级容器重构为JPanel,并将绘画移至paintComponent()
  2. 删除了ThreadThread.sleep(n)&amp;替换为Timer / ActionListener
  3. 在EDT上构建了GUI。
  4. 已移除设置JFrame的大小。而是为JPanel(实际绘图区域)设置首选尺寸,并调用JFrame.pack()以获得正确的整体尺寸。
  5. 使用setLocationByPlatform(true)代替very splash-screen like setLocationRelativeTo(null)
  6. 仔细检查代码以获取更多提示。

    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 );
            }
        });
    }
    }
    

答案 1 :(得分:1)

你永远不应该尝试直接在画布上绘制,使用后台线程始终保持下一帧准备就绪,并将其与旧帧交换。

    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);
        }

    }
}

答案 2 :(得分:0)

将代码从applet更改为JFrame并不难。 将类的扩展名重命名为JPanel:

public class Racing extends JPanel

然后在实例化新赛车的方法中 将其更改为实例化新的JFrame 以及setTitle(...)之类的竞赛中的任何方法现在都会将错误移动到实例化新JFrame的方法,如(whatever you named the JFrame reference).setTitle(...) 然后将以下代码应用于JFrame的其余部分:

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