JPanel中闪烁的图像

时间:2011-10-11 14:50:43

标签: java swing flicker graphics2d

我创建了一个将图像绘制到JPanel的游戏。这与JTimer一起运行,每隔14毫秒执行一次以移动背景,移动障碍物并移动玩家(直升机)。偶尔会出现背景和障碍物的闪烁,而且运行速度不是特别顺畅。 有没有办法解决这个问题?我是否需要在不同的类中使用线程和动画? 我也使用了双缓冲,但后来我发现JPanels是双缓冲的,所以我把它删除了。

以下是Panel类的代码。

class ImagePanel extends JPanel implements KeyListener, MouseListener,
        MouseMotionListener {

    /**
     * 
     */
    private static final long serialVersionUID = -6096603231469523786L;
    Plane o1 = new Plane();
    Tank o2 = new Tank();

    ArrayList<Plane> planeArray;
    ArrayList<Tank> tankArray;
    ArrayList<Missile> missileArray;

    int bgx;
    int bgxTwo;
    int time;
    int y;
    int score;
    int obsNum;
    int obsNum2;
    int planeSpeed;
    int missileSpeed;
    int count;

    boolean holding;
    boolean gameOver;
    boolean startscreen;
    boolean shooting;
    boolean obsOne = false;
    boolean obsTwo = false;

    Color colorone = Color.WHITE;
    Color colortwo = Color.WHITE;
    Color restartColor = Color.white;
    Color menuColor = Color.white;
    Color bulletColor = Color.white;

    Font f1;
    Font f2;
    Font f3;

    String version = "Get To The Chopper Beta 1.2";

    int level = 1;

    java.util.Timer movementtimer;
    TimerTask task;

    java.util.Timer obstacletimer;
    TimerTask taskTwo;

    private Image image;
    private Image imageTwo;
    private Image chopper;
    private Image chopper2;
    private Image tank;
    private Image plane;
    private Image missile;
    private Image explosion;

    BufferedImage bufferedImage;
    Graphics buffer;

    java.net.URL bgurl;
    java.net.URL curl;
    java.net.URL c2url;
    java.net.URL turl;
    java.net.URL purl;
    java.net.URL murl;
    java.net.URL eurl;

    // ///////// CONSTRUCTOR SETS NON-CHANGABLE VARIABLES ////////////////

    public ImagePanel() {

        setFocusable(true);
        addKeyListener(this);
        addMouseListener(this);
        addMouseMotionListener(this);

        f1 = new Font("Helvetica", Font.BOLD, 10);
        f2 = new Font("Helvetica", Font.PLAIN, 30);
        f3 = new Font("Helvetica", Font.PLAIN, 25);

        startscreen = true;

        getImages();

        planeArray = new ArrayList<Plane>();
        tankArray = new ArrayList<Tank>();
        missileArray = new ArrayList<Missile>();

        repaint();
    }

    public void getImages() {

        bgurl = getClass().getResource("images/background.png");
        switch (level) {
        case (1):
            bgurl = getClass().getResource("images/grassbackground.png");
            bulletColor = Color.black;
            break;
        case (2):
            bgurl = getClass().getResource("images/snowbackground.png");
            bulletColor = Color.red;
            break;
        }
        curl = getClass().getResource("images/heli.png");
        c2url = getClass().getResource("images/heli2.png");
        turl = getClass().getResource("images/tank.png");
        purl = getClass().getResource("images/plane.png");
        murl = getClass().getResource("images/missile.png");
        eurl = getClass().getResource("images/explosion.png");

        try {

            image = Toolkit.getDefaultToolkit().getImage(bgurl);
            imageTwo = Toolkit.getDefaultToolkit().getImage(bgurl);
            chopper = Toolkit.getDefaultToolkit().getImage(curl);
            chopper2 = Toolkit.getDefaultToolkit().getImage(c2url);
            tank = Toolkit.getDefaultToolkit().getImage(turl);
            plane = Toolkit.getDefaultToolkit().getImage(purl);
            missile = Toolkit.getDefaultToolkit().getImage(murl);
            explosion = Toolkit.getDefaultToolkit().getImage(eurl);

        } catch (Exception ex) {
            System.out.println("File Not Found");
        }

    }

    // //////// SETS VARIABLES WHEN GAME IS STARTED OR RESTARTED
    // //////////////////

    public void startGame() {
        bgx = 0;
        bgxTwo = 800;
        y = 50;
        score = 0;
        holding = false;
        gameOver = false;
        time = (int) (Math.random() * 500 + 500);
        obsNum2 = 0;
        shooting = false;

        count = 1;

        planeSpeed = -6;
        missileSpeed = -7;

        planeArray.clear();
        tankArray.clear();
        missileArray.clear();

        colorone = Color.WHITE;
        colortwo = Color.WHITE;
        restartColor = Color.white;
        menuColor = Color.white;

        movementtimer = new java.util.Timer();
        task = new TimerTask() {
            public void run() {
                moveImage();repaint();
            }
        };
        movementtimer.schedule(task, 0, 13);

        obstacletimer = new java.util.Timer();
        taskTwo = new TimerTask() {
            public void run() {
                generateObstacle();
            }
        };
        obstacletimer.schedule(taskTwo, 2000, time);

    }

    // ////////// COLLISION DETECTION //////////////////

    public void moveImage() {

        moveBackground();

        addToScore();

        if (holding) {
            y += -3;
        } else {
            y += 3;
        }

        for (int i = 0; i < planeArray.size(); i++) {
            Plane plane = planeArray.get(i);
            if (y + 30 >= plane.yPos && y + 30 <= plane.yPos + 30
                    && plane.xPos >= 200 && plane.xPos <= 250
                    || y >= plane.yPos && y <= plane.yPos + 30
                    && plane.xPos >= 200 && plane.xPos + 50 <= 250) {
                gameOver = true;
                System.out.println("Crash with plane!");
            }
        }

        for (int i = 0; i < tankArray.size(); i++) {
            Tank tank = tankArray.get(i);
            if (y + 30 >= tank.yPos && y + 30 <= tank.yPos + 30
                    && tank.xPos >= 200 && tank.xPos <= 250
                    || y >= tank.yPos && y <= tank.yPos + 30
                    && tank.xPos >= 200 && tank.xPos + 50 <= 250) {
                gameOver = true;
                System.out.println("Crash with a tank");
            }
            if (shooting) {
                if (y + 30 >= tank.bulletYPos && y <= tank.bulletYPos
                        && tank.bulletXPos >= 200 && tank.bulletXPos <= 250) {
                    gameOver = true;
                    System.out.println("Shot down");

                }
            }
        }

        for (int i = 0; i < missileArray.size(); i++) {
            Missile missile = missileArray.get(i);
            if (y + 30 >= missile.yPos && y + 30 <= missile.yPos + 30
                    && missile.xPos >= 200 && missile.xPos <= 250
                    || y >= missile.yPos && y <= missile.yPos + 30
                    && missile.xPos >= 200 && missile.xPos + 50 <= 250) {
                gameOver = true;
                System.out.println("Crash with a missile");
            }
        }

        if (y >= 300) {
            gameOver = true;
        } else if (y <= -15) {
            gameOver = true;
        }


    }

    // //////// MOVES BACKGROUND //////////////

    public void moveBackground() {

        bgx += -5;

        if (bgx == -800) {
            bgx = 800;
        }

        bgxTwo += -5;

        if (bgxTwo == -800) {
            bgxTwo = 800;
        }

        for (int i = 0; i < planeArray.size(); i++) {

            Plane obs = planeArray.get(i);
            obs.xPos = obs.xPos - 6;
        }

        for (int i = 0; i < tankArray.size(); i++) {

            Tank obs = tankArray.get(i);

            obs.xPos = obs.xPos - 5;
            if (shooting) {
                obs.bulletYPos = obs.bulletYPos - 2;
                obs.bulletXPos = obs.bulletXPos - obs.angle;
            }
        }

        for (int i = 0; i < missileArray.size(); i++) {

            Missile obs = missileArray.get(i);
            obs.xPos = obs.xPos - 7;
        }

    }

    public void addToScore() {

        score += 5;

        increaseDiff();

    }

    public void increaseDiff() {

        if (score == 10000) {
            shooting = true;
            for (int i = 0; i < tankArray.size(); i++) {
                Tank tank = tankArray.get(i);
                tank.bulletXPos = tank.xPos;
            }
        }
        if (score > 5000 && score < 9999) {
            time = (int) (Math.random() * 400 + 250);
            planeSpeed = -7;
            missileSpeed = -8;

        } else if (score > 10000 && score < 14999) {
            time = (int) (Math.random() * 400 + 150);
            planeSpeed = -8;
            missileSpeed = -10;

        } else if (score > 15000 && score < 19999) {
            time = (int) (Math.random() * 400 + 150);
            planeSpeed = -9;
            missileSpeed = -11;
            obsNum2 = (int) (Math.random() * 2 + 1);
        } else if (score > 20000 && score < 29999) {
            time = (int) (Math.random() * 300 + 100);
            planeSpeed = -10;
            missileSpeed = -13;
            obsNum2 = (int) (Math.random() * 2 + 1);
        } else if (score > 30000) {
            time = (int) (Math.random() * 300 + 100);
            planeSpeed = -12;
            missileSpeed = -15;
            obsNum2 = (int) (Math.random() * 2 + 1);
        }
    }

    public void generateObstacle() {

        obsNum = (int) (Math.random() * 5 + 1);

        if (obsNum == 1 || obsNum == 4 || obsNum2 == 1) {
            planeArray.add(new Plane());
        }

        if (obsNum == 2) {
            tankArray.add(new Tank());
        }

        if (obsNum == 3 || obsNum == 5 || obsNum2 == 2) {
            missileArray.add(new Missile());
        }

    }


    public void update(Graphics g) {
        paint(g);
    }

    // /////////////// MAIN PAINT METHOD //////////////////////

    @Override
    public void paint(Graphics g) {

        g.clearRect(0,0,800,400);

        if (!startscreen) {

            g.drawImage(image, bgx, 0, null);
            g.drawImage(imageTwo, bgxTwo, 0, null);

            for (int i = 0; i < planeArray.size(); i++) {
                Plane obs = planeArray.get(i);

                if (obs.xPos <= -50) {
                    planeArray.remove(i);
                } else {

                    g.drawImage(plane, obs.xPos, obs.yPos, null);
                }
            }

            for (int i = 0; i < tankArray.size(); i++) {
                Tank obs = tankArray.get(i);

                if (obs.xPos <= -50) {
                    tankArray.remove(i);
                } else {

                    g.drawImage(tank, obs.xPos, obs.yPos, null);
                    if (shooting) {
                        g.setColor(bulletColor);
                        g.fillOval(obs.bulletXPos, obs.bulletYPos, 5,
                                5);
                    }
                }
            }

            for (int i = 0; i < missileArray.size(); i++) {
                Missile obs = missileArray.get(i);

                if (obs.xPos <= -50) {
                    missileArray.remove(i);
                } else {

                    g.drawImage(missile, obs.xPos, obs.yPos, null);
                }
            }

            if (gameOver) {
                movementtimer.cancel();
                obstacletimer.cancel();
                g.setColor(Color.WHITE);
                g.setFont(f2);
                g.drawString("GAME OVER", 250, 150);
                g.setFont(f3);
                g.drawString("Your score: " + score, 250, 200);
                g.setColor(restartColor);
                g.drawString("Click to restart!", 250, 250);
                g.setColor(menuColor);
                g.drawString("Back to menu", 250, 300);
                g.drawImage(explosion, 200, y, this);
            }

        } else if (startscreen) {

            g.drawImage(image, 0, 0, this);
            g.drawImage(imageTwo, 0, 0, this);
            g.drawImage(chopper, 200, 50, this);
            g.setColor(Color.WHITE);
            g.setFont(f2);
            g.drawString("Choose a level:", 200, 150);
            g.setFont(f3);
            g.setColor(colorone);
            g.drawString("Grass Level!", 250, 200);
            g.setColor(colortwo);
            g.drawString("Snow Level!", 250, 250);

        }

        if (count <= 9 && !gameOver && !startscreen) {
            g.drawImage(chopper, 200, y, this);
            count++;
        } else if (count >= 10 && count < 20 && !gameOver && !startscreen) {
            g.drawImage(chopper2, 200, y, this);
            count++;
        } else if (count == 20 && !gameOver && !startscreen) {
            count = 1;
            g.drawImage(chopper, 200, y, this);
        }

        g.setFont(f1);
        g.setColor(Color.WHITE);
        g.drawString(version, 10, 10);
        g.drawString("Score: " + score + "", 700, 10);
    }



    // ///////////////////OVERRIDE KEYPRESSED EVENTS//////////////////////

    @Override
    public void keyPressed(KeyEvent e) {
        // TODO Auto-generated method stub

        if (e.getKeyCode() == 32) {
            holding = true;
            repaint();
        }

    }

    @Override
    public void keyReleased(KeyEvent e) {
        // TODO Auto-generated method stub

        if (e.getKeyCode() == 32) {
            holding = false;
            repaint();
        }

    }

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub

    }

    public void mousePressed(MouseEvent e) {

        if (e.getX() >= 250 && e.getX() <= 400 && e.getY() >= 180
                && e.getY() <= 200 && startscreen) {
            startscreen = false;
            level = 1;
            getImages();
            startGame();
        }

        if (e.getX() >= 250 && e.getX() <= 400 && e.getY() >= 230
                && e.getY() <= 250 && startscreen) {
            startscreen = false;
            level = 2;
            getImages();
            startGame();
        }

        if (e.getX() >= 250 && e.getX() <= 420 && e.getY() >= 230
                && e.getY() <= 250 && gameOver) {
            startGame();
        }

        if (e.getX() >= 250 && e.getX() <= 420 && e.getY() >= 280
                && e.getY() <= 320 && gameOver) {
            gameOver = false;
            startscreen = true;
            repaint();
        }

    }

    @Override
    public void mouseClicked(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    public void mouseMoved(MouseEvent e) {
        if (e.getX() >= 250 && e.getX() <= 400 && e.getY() >= 180
                && e.getY() <= 200 && startscreen) {
            colorone = Color.RED;
            repaint();
        } else if (e.getX() >= 250 && e.getX() <= 400 && e.getY() >= 230
                && e.getY() <= 250 && startscreen) {
            colortwo = Color.RED;
            repaint();
        } else if (startscreen) {
            colorone = Color.white;
            colortwo = Color.white;
            repaint();
        }

        if (e.getX() >= 250 && e.getX() <= 420 && e.getY() >= 230
                && e.getY() <= 250 && gameOver) {
            restartColor = Color.red;
            repaint();
        } else if (e.getX() >= 250 && e.getX() <= 420 && e.getY() >= 280
                && e.getY() <= 320 && gameOver) {
            menuColor = Color.red;
            repaint();
        } else if (gameOver) {
            restartColor = Color.white;
            menuColor = Color.white;
            repaint();
        }
    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseReleased(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseDragged(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }
}

对于所有代码感到抱歉,正如您可能会说的那样,我是Java和编程的新手(从去年大学开始),但这是我希望进步并从事事业的事情。

由于 汤姆

2 个答案:

答案 0 :(得分:2)

你试图在Swing程序中做AWT图形 - 不要这样做。相反,在Swing图形程序中没有更新的地方,你不应该重写paint方法,而应该重写JPanel的paintComponent方法。这样你就可以利用Swing的双重缓冲。

这是一个显示AWT与Swing动画的SSCCE,不幸的是,我并没有像我希望的那样看到两者之间存在太大差异。

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class PaintVsPaintComponent extends JPanel {
   public static final String DUKE_WAVE = "http://duke.kenai.com/iconSized/duke4.gif";
   private static final int PREF_WIDTH = 300;
   private static final int PREF_HEIGHT = 250;
   private static final int TIMER_DELAY = 20;
   private static final int DELTA_X = 1;
   private static final int DELTA_Y = DELTA_X;
   private boolean awtDrawing;
   private BufferedImage image;
   private int x = 0;
   private int y = 0;

   public PaintVsPaintComponent(boolean awtDrawing, BufferedImage image) {
      this.awtDrawing = awtDrawing;
      this.image = image;

      new Timer(TIMER_DELAY, new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            timerActionPerformed(ae);
         }
      }).start();
   }

   private void timerActionPerformed(ActionEvent ae) {
      x += DELTA_X;
      y += DELTA_Y;

      if (x >= getWidth()) {
         x = 0;
      }
      if (y >= getHeight()) {
         y = 0;
      }

      repaint();
   }

   @Override
   public void paint(Graphics g) {
      super.paint(g);
      if (awtDrawing) {
         drawImage(g);
      }
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (!awtDrawing) {
         drawImage(g);
      }
   }

   private void drawImage(Graphics g) {
      g.drawImage(image, x, y, null);
   }

   @Override
   public void update(Graphics g) {
      if (awtDrawing) {
         paint(g);
      } else {
         super.update(g);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_WIDTH, PREF_HEIGHT);
   }

   private static void createAndShowGui() {
      BufferedImage dukeWaveImage = null;

      URL dukeWaveUrl;
      try {
         dukeWaveUrl = new URL(DUKE_WAVE);
         dukeWaveImage = ImageIO.read(dukeWaveUrl);


         PaintVsPaintComponent awtPanel = new PaintVsPaintComponent(true, dukeWaveImage);
         PaintVsPaintComponent swingPanel = new PaintVsPaintComponent(false, dukeWaveImage);
         awtPanel.setBorder(BorderFactory.createTitledBorder("AWT Panel"));
         swingPanel.setBorder(BorderFactory.createTitledBorder("Swing Panel"));

         JPanel gridPanel = new JPanel(new GridLayout(1, 0));
         gridPanel.add(awtPanel);
         gridPanel.add(swingPanel);

         JFrame frame = new JFrame("PaintVsPaintComponent");
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.getContentPane().add(gridPanel);
         frame.pack();
         frame.setLocationByPlatform(true);
         frame.setVisible(true);
      } catch (MalformedURLException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }

   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }

}

答案 1 :(得分:2)

不要使用TimerTask。

你应该使用Swing Timer。然后,对GUI的所有更新都将在Event Dispatch Thread上完成。