2013-03-07 72 views
1

我正在尝试使用鼠标来控制使用者的两个球员Pong Applet。小应用程序甚至在使用双缓冲使用后仍然闪烁

我用双缓冲的概念,但小程序仍然闪烁! 我在犯什么错误?

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionListener; 
import java.util.Timer; 
import javax.swing.JApplet; 

public class Pong extends JApplet implements Runnable, MouseMotionListener { 
    Ball ball; 
    Paddle left_paddle; 
    Paddle right_paddle; 
    Image image; 
    Graphics DoubleBuffered; 

    @Override 
    public void init() { 
     setSize(800, 600); 
     addMouseMotionListener(this); 
     setFocusable(true); 
     requestFocusInWindow();   
    } 

    @Override 
    public void start() { 
     left_paddle = new Paddle(5, 200, this); 
     right_paddle = new Paddle(this.getWidth() - 30, this.getHeight()/2, this); 
     ball = new Ball(100, 100, left_paddle, right_paddle); 
     Thread thread = new Thread(this); 
     thread.start(); 
    } 

    @Override 
    public void run() { 
     while (true) { 
      ball.update(this); 
      repaint(); 
      try { 
       Thread.sleep(17); //Frame rate of approx 60 FPS 
      } catch (InterruptedException ex) { 

      } 
     } 
    } 

    @Override 
    public void stop() { 
    } 

    @Override 
    public void destroy() { 
    } 

    @Override 
    public void update(Graphics g) { 
     if (image == null) { 
      image = createImage(this.getWidth(), this.getHeight()); 
      DoubleBuffered = image.getGraphics(); 
     } 
     DoubleBuffered.setColor(getBackground()); 
     DoubleBuffered.fillRect(0, 0, this.getWidth(), this.getHeight()); 

     DoubleBuffered.setColor(getForeground()); 
     paint (DoubleBuffered); 

     DoubleBuffered.drawImage(image, 0, 0, this); 
    } 

    @Override 
    public void paint(Graphics g) { 
     g.setColor(Color.WHITE); 
     g.fillRect(0, 0, this.getWidth(), this.getHeight()); 
     ball.paint(g); 
     left_paddle.paint(g); 
     right_paddle.paint(g); 
     g.setColor(Color.BLACK); 
     g.drawLine(this.getWidth()/2, 0, this.getWidth()/2, this.getHeight()); 
    } 

    @Override 
    public void mouseDragged(MouseEvent e) { 
    } 

    @Override 
    public void mouseMoved(MouseEvent e) { 
     int y = e.getY(); 
     int x = e.getX(); 
     if (x < this.getWidth()/2) { //Control the left paddle 
      if (y < 0) { 
       y = 0; 
      } else if (y + left_paddle.getHeight() >= this.getHeight()) { 
       y = this.getHeight() - left_paddle.getHeight(); 
      } 
      left_paddle.mouse(y); 
     } 
     else { 
      if (y < 0) { 
       y = 0; 
      } else if (y + right_paddle.getHeight() >= this.getHeight()) { 
       y = this.getHeight() - right_paddle.getHeight(); 
      } 
      right_paddle.mouse(y); 
     } 
    } 
} 

class Ball { 
    private int x; 
    private int y; 
    private float dx=4; 
    private float dy=5; 
    private int radius = 10; 
    private Paddle left, right; 

    Ball(int x, int y, Paddle x1, Paddle y1) { 
     this.x = x; 
     this.y = y; 
     left = x1; 
     right = y1; 
    } 

    public void reset() 
    { 
     this.x = 400; 
     this.y = 200; 
    } 

    public void update(Pong ref) 
    { 
     if (x+dx < left.getX()+left.getWidth()+radius && y+dy+radius >= left.getY() && y+dy+radius <= left.getY()+left.getHeight()) { 
      x = left.getX()+left.getWidth()+radius; 
      dx *= (-1); 
      // checks the left paddle collision 
     } 
     else if (x+dx+radius >= right.getX() && y+dy+radius >= right.getY() && y+dy+radius <= right.getY()+right.getHeight()) { 
      x = right.getX() - radius; 
      dx *= (-1); 
      //checks the right paddle collision 
     } 
     //if ball touches the boundary reset it at middle point 
     else if (x+dx+radius >= ref.getWidth()) { 
      reset(); 
     } 
     else if (x + dx < radius) { 
      reset(); 
     } 
     else { 
      x += dx; 
     } 

     if (y+dy +radius > ref.getHeight()) { 
      y = ref.getHeight() - radius - 1; 
      dy *= (-1); 
     } 
     else if (y + dy < radius) { 
      y = radius; 
      dy *= (-1); 
     } 
     else { 
      y += dy; 
     } 
    } 

    public void paint (Graphics g) 
    { 
     g.setColor(Color.RED); 
     g.fillOval(x-radius, y-radius, 2*radius, 2*radius); 
    } 

} 

class Paddle { 

    private int x; 
    private int y; 
    private int width = 25; 
    private int height = 150; 
    private Timer timer; 

    public Paddle(int x, int y, Pong ref) { 
     this.x = x; 
     this.y = y; 
    } 

    public int getHeight() { 
     return height; 
    } 

    public int getWidth() { 
     return width; 
    } 

    public int getX() { 
     return x; 
    } 

    public int getY() { 
     return y; 
    } 

    public void paint (Graphics g) 
    { 
     g.setColor(Color.BLUE); 
     g.fillRect(x, y, width, height); 
    } 

    //mouse lookup 
    void mouse(int y_final) 
    { 
     y = y_final; 
    } 
} 
+2

'公共类傍扩展JApplet的实现Runnable..'实现一个'ActionListener'和使用Swing的'运行定时器'而不是。 – 2013-03-07 06:25:03

回答

3

一般来说,你应该避免覆盖顶层容器paintupdate方法,如JApplet

您必须记得致电super.update,将您创建的图形上下文传递给它。您还必须记得致电super.paint。这里有很多重要的功能,你不想跳过。

你也应该创建,因为他们往往生猪内存中的任何图形的处置;)

但是,视为你使用Swing组件,无论如何,你应该自己创建从像自定义组件( JPanel)并使用它的paintComponent方法。

造成这种情况的主要原因是,Swing组件双默认缓冲......

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionListener; 
import javax.swing.Timer; 
import javax.swing.JApplet; 
import javax.swing.JPanel; 

public class Pong extends JApplet { 

    private GamePane gamePane; 

    @Override 
    public void init() { 
     setSize(800, 600); 
     gamePane = new GamePane(); 
     setLayout(new BorderLayout()); 
     add(gamePane); 
    } 

    @Override 
    public void start() { 
     gamePane.start(); 
    } 

    @Override 
    public void stop() { 
    } 

    @Override 
    public void destroy() { 
    } 

    public class GamePane extends JPanel implements MouseMotionListener { 

     Ball ball; 
     Paddle left_paddle; 
     Paddle right_paddle; 

     public GamePane() { 
      setBackground(Color.WHITE); 
      addMouseMotionListener(this); 
      setFocusable(true); 
      requestFocusInWindow(); 
     } 

     public void start() { 
      left_paddle = new Paddle(5, 200); 
      right_paddle = new Paddle(this.getWidth() - 30, this.getHeight()/2); 
      ball = new Ball(100, 100, left_paddle, right_paddle); 
      Timer timer = new Timer(40, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        ball.update(GamePane.this); 
        repaint(); 
       } 
      }); 
      timer.setRepeats(true); 
      timer.setCoalesce(true); 
      timer.start(); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); //To change body of generated methods, choose Tools | Templates. 

      ball.paint(g); 
      left_paddle.paint(g); 
      right_paddle.paint(g); 
      g.setColor(Color.BLACK); 
      g.drawLine(this.getWidth()/2, 0, this.getWidth()/2, this.getHeight()); 

     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
     } 

     @Override 
     public void mouseMoved(MouseEvent e) { 
      int y = e.getY(); 
      int x = e.getX(); 
      if (x < this.getWidth()/2) { //Control the left paddle 
       if (y < 0) { 
        y = 0; 
       } else if (y + left_paddle.getHeight() >= this.getHeight()) { 
        y = this.getHeight() - left_paddle.getHeight(); 
       } 
       left_paddle.mouse(y); 
      } else { 
       if (y < 0) { 
        y = 0; 
       } else if (y + right_paddle.getHeight() >= this.getHeight()) { 
        y = this.getHeight() - right_paddle.getHeight(); 
       } 
       right_paddle.mouse(y); 
      } 
     } 
    } 

    class Ball { 

     private int x; 
     private int y; 
     private float dx = 4; 
     private float dy = 5; 
     private int radius = 10; 
     private Paddle left, right; 

     Ball(int x, int y, Paddle x1, Paddle y1) { 
      this.x = x; 
      this.y = y; 
      left = x1; 
      right = y1; 
     } 

     public void reset() { 
      this.x = 400; 
      this.y = 200; 
     } 

     public void update(GamePane ref) { 
      if (x + dx < left.getX() + left.getWidth() + radius && y + dy + radius >= left.getY() && y + dy + radius <= left.getY() + left.getHeight()) { 
       x = left.getX() + left.getWidth() + radius; 
       dx *= (-1); 
       // checks the left paddle collision 
      } else if (x + dx + radius >= right.getX() && y + dy + radius >= right.getY() && y + dy + radius <= right.getY() + right.getHeight()) { 
       x = right.getX() - radius; 
       dx *= (-1); 
       //checks the right paddle collision 
      } //if ball touches the boundary reset it at middle point 
      else if (x + dx + radius >= ref.getWidth()) { 
       reset(); 
      } else if (x + dx < radius) { 
       reset(); 
      } else { 
       x += dx; 
      } 

      if (y + dy + radius > ref.getHeight()) { 
       y = ref.getHeight() - radius - 1; 
       dy *= (-1); 
      } else if (y + dy < radius) { 
       y = radius; 
       dy *= (-1); 
      } else { 
       y += dy; 
      } 
     } 

     public void paint(Graphics g) { 
      g.setColor(Color.RED); 
      g.fillOval(x - radius, y - radius, 2 * radius, 2 * radius); 
     } 
    } 

    public class Paddle { 

     private int x; 
     private int y; 
     private int width = 25; 
     private int height = 150; 
     private Timer timer; 

     public Paddle(int x, int y) { 
      this.x = x; 
      this.y = y; 
     } 

     public int getHeight() { 
      return height; 
     } 

     public int getWidth() { 
      return width; 
     } 

     public int getX() { 
      return x; 
     } 

     public int getY() { 
      return y; 
     } 

     public void paint(Graphics g) { 
      g.setColor(Color.BLUE); 
      g.fillRect(x, y, width, height); 
     } 

     //mouse lookup 
     void mouse(int y_final) { 
      y = y_final; 
     } 
    } 
} 
+0

我理解了覆盖JPanel的paintComponent方法的使用概念,但无法理解这里使用Swing Timer! 请解释! – Snehasish 2013-03-07 06:50:55

+1

Swing计时器可确保您执行的任何更新(在actionPerformed方法内都在Event Dispatching Thread中执行),这可确保在更新游戏状态时不会发生重绘 – MadProgrammer 2013-03-07 08:15:08

相关问题