JAVA双缓冲机制

http://stchou.iteye.com/blog/810701

以前都不了解双缓冲是什么个东东,

 

但是为了解决我的坦克大战疯狂的闪屏

 后,终于对其有了一个了解。

Java代码   收藏代码
  1. package My2;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Graphics;  
  5. import java.awt.Image;  
  6. import java.awt.event.KeyEvent;  
  7. import java.awt.event.WindowAdapter;  
  8. import java.awt.event.WindowEvent;  
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. import javax.tools.JavaCompiler;  
  13.   
  14.   
  15.   
  16.   
  17. public class tankGame extends java.awt.Frame implements java.awt.event.KeyListener{  
  18.     //窗体宽度  
  19.     public static final int WINDOW_WIDTH = 800;  
  20.     //窗体高度  
  21.     public static final int WINDOW_HEIGHT = 600;  
  22.     //窗体刷新率  
  23.     public static final int REFRESH_RATE = 50;  
  24.     //玩家坦克  
  25.     static Tank myTank = null;  
  26.     // 坦克起始位置左上角坐标  
  27.     public static final int Tank_X = 385;  
  28.     public static final int Tank_Y = 550;  
  29.     //敌方坦克同时出现的最大数量  
  30.     private int tankMaxNum = 10;  
  31.     //当前敌方坦克数量  
  32.     private int tankNum = 0;  
  33.     //存放敌方坦克的容器  
  34.     static List<Tank> enemyTanks = new ArrayList<Tank>();  
  35.     //存放墙的容器  
  36.     static List<Wall> wallList = new ArrayList<Wall>();  
  37.     static int wallNum=35;  
  38.     //屏幕画布  
  39.     static java.awt.Graphics g = null;  
  40.     Image offScreenImage = null;  
  41.   
  42.       
  43.       
  44.     public static void main(String[] args){  
  45.         tankGame game = new tankGame();  
  46.           
  47.         game.showUI();  
  48.         game.Init();  
  49.         game.addKeyListener(game);  
  50.     }  
  51.       
  52.       
  53.     public void paint(java.awt.Graphics g){  
  54.         drawTank();  
  55.     }  
  56.       
  57.       
  58.     public static void drawTank(){  
  59.   
  60.         if(myTank==nullreturn ;  
  61.         g.fillRect(00, WINDOW_WIDTH, WINDOW_HEIGHT);    
  62.         myTank.draw(g);  
  63.         for (int i=0;i<enemyTanks.size();i++){  
  64.             enemyTanks.get(i).draw(g);  
  65.         }  
  66.           
  67.         for (int i=0;i<wallList.size();i++){  
  68.             wallList.get(i).draw(g);  
  69.         }  
  70.     }  
  71.       
  72.     public void Init(){  
  73.         //加入我方坦克  
  74.         myTank = new Tank(Tank_X,Tank_Y,true,0);  
  75.         myTank.draw(g);  
  76.           
  77.         //加入敌方坦克  
  78.         for (int i = 0; i < tankMaxNum; i++) {  
  79.             Tank enemyTank = new Tank(200 + 50 * i, 100false1);  
  80.             enemyTanks.add(enemyTank);  
  81.             tankNum++;  
  82.         }  
  83.           
  84. //        加入城墙  
  85.         for (int i=0;i<wallNum;i++){  
  86.             Wall wall = new Wall(100+i*18,300);  
  87.             wallList.add(wall);  
  88.             wall = new Wall(100+i*18,318);  
  89.             wallList.add(wall);  
  90.         }  
  91.           
  92.          // 启动重画线程  
  93.         PaintThread pt = new PaintThread();  
  94.         Thread t = new Thread(pt);  
  95.         t.start();  
  96.     }  
  97.       
  98.     /** 
  99.      * 显示窗体 
  100.      */  
  101.     public void showUI(){  
  102.         this.setTitle("我打坦克大战");  
  103.         this.setLocation(200100);  
  104.         this.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);  
  105.            this.setResizable(false);  
  106.             this.addWindowListener(  
  107.                 new WindowAdapter() {  
  108.                     public void windowClosing(WindowEvent e) {  
  109.                         setVisible(false);  
  110.                         System.exit(0);  
  111.                     }  
  112.                 }  
  113.             );  
  114.         this.setBackground(Color.BLACK);  
  115.         this.setVisible(true);  
  116.         g=this.getGraphics();  
  117.     }  
  118.       
  119.       
  120.       /** 
  121.      * 重写update方法,先将窗体上的图形画在图片对象上,再一次性显示 
  122.      */  
  123. //    public void update(Graphics g) {  
  124. //       if (offScreenImage == null) {  
  125. //             offScreenImage = this.createImage(WINDOW_WIDTH,  
  126. //                     WINDOW_HEIGHT);  
  127. //            }  
  128. //            Graphics gOffScreen = offScreenImage.getGraphics();// 获取图片内的所有图形,形成虚拟窗口  
  129. //            Color c = gOffScreen.getColor();  
  130. //            gOffScreen.setColor(Color.BLACK);// 设置屏幕窗口的颜色  
  131. //            gOffScreen.fillRect(0, 0, WINDOW_WIDTH,WINDOW_HEIGHT);  
  132. //            gOffScreen.setColor(c);  
  133. //            paint(gOffScreen); // 把虚拟窗口画在图片上  
  134. //            g.drawImage(offScreenImage, 0, 0, null);// 把图片画在窗口上  
  135. //      //    drawTank();  
  136. //  
  137. //   }  
  138.       
  139.       
  140.      /** 
  141.      * 用线程重画,每隔一段时间重画窗体 
  142.      * @author Magci 
  143.      * 
  144.      */  
  145.     public class PaintThread implements Runnable {  
  146.   
  147.         /** 
  148.          * 每隔REFRESH_RATE毫秒重画一次窗体 
  149.          */  
  150.         public void run() {  
  151.             while (true) {  
  152.                 repaint();  
  153.                 try {  
  154.                     Thread.sleep(REFRESH_RATE);  
  155.                 } catch (InterruptedException e) {  
  156.                     e.printStackTrace();  
  157.                 }  
  158.             }  
  159.         }  
  160.     }  
  161.       
  162.     public void keyPressed(KeyEvent e) {  
  163.         if(e.getKeyCode()==java.awt.event.KeyEvent.VK_UP){//如果按键为向上键  
  164.             myTank.move(0);//向上  
  165.         }  
  166.         if(e.getKeyCode()==java.awt.event.KeyEvent.VK_DOWN){//如果按键为向下键  
  167.             myTank.move(1);   
  168.         }  
  169.         if(e.getKeyCode()==java.awt.event.KeyEvent.VK_LEFT){//如果按键为向左键  
  170.             myTank.move(2);   
  171.         }  
  172.         if(e.getKeyCode()==java.awt.event.KeyEvent.VK_RIGHT){//如果按键为向右键  
  173.             myTank.move(3);  
  174.         }if(e.getKeyCode()==java.awt.event.KeyEvent.VK_SPACE){  
  175.             myTank.fire(g);  
  176.         }  
  177.         //drawTank();  
  178.     }  
  179.   
  180.   
  181.     public void keyReleased(KeyEvent e) {  
  182.     }  
  183.   
  184.   
  185.     public void keyTyped(KeyEvent e) {  
  186.     }  
  187.   
  188. }  

 

 

能是能画出一个坦克,但是闪得你受不了,

 

其主要的原因是,要了解paint闪烁的原因

  每一个paint的过后,程序会自行的调用repaint的方法,但是repaint方法中的绘制有的分配一个与原来窗口一样的的内存空间,但里面是没有存储东西的,所以一次次的paint,repaint的交替就会产生闪烁

 

解决方法:双缓冲技术的工作原理:先在内存中分配一个和窗口一样大的空间(在内存中的空间我门是看不到的),然后利用getGraphics()方法去获得该空间并将它全部一次性的显示到屏幕上.这样显示出来就非常的流畅了.避免了闪烁效果.

Java代码   收藏代码
  1. package My4;  
  2. import java.awt.*;  
  3. import java.awt.event.*;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6.   
  7. public class TankClient extends Frame implements java.awt.event.KeyListener{  
  8.   
  9.     public static final int WINDOW_WIDTH = 800;  
  10.     public static final int WINDOW_HEIGHT = 600;  
  11.     //窗体刷新率  
  12.     public static final int REFRESH_RATE = 50;  
  13.     Image offScreenImage = null;  
  14.     //屏幕画布  
  15.     static java.awt.Graphics g = null;  
  16.     //玩家坦克  
  17.     static Tank myTank = null;  
  18.     // 坦克起始位置左上角坐标  
  19.     public static final int Tank_X = 385;  
  20.     public static final int Tank_Y = 550;  
  21.     //敌方坦克同时出现的最大数量  
  22.     private int tankMaxNum = 10;  
  23.     //当前敌方坦克数量  
  24.     private int tankNum = 0;  
  25.     //存放敌方坦克的容器  
  26.     static List<Tank> enemyTanks = new ArrayList<Tank>();  
  27.     //存放墙的容器  
  28.     static List<Wall> wallList = new ArrayList<Wall>();  
  29.     static int wallNum=35;  
  30.     //草容器  
  31.     static List<Grass> grassList = new ArrayList<Grass>();  
  32.     //方块容器  
  33.     static List<Stone> stoneList = new ArrayList<Stone>();  
  34.       
  35.     static boolean GameBegin=false;  
  36.       
  37.     public static void main(String[] args) {  
  38.   
  39.         // 创建一个窗体  
  40.         TankClient main =new TankClient();  
  41.         main.showUI();  
  42.         main.addKeyListener(main);  
  43.     }  
  44.   
  45.     public void showUI() {  
  46.         this.setTitle("我打坦克大战");  
  47.         this.setBounds(200100, WINDOW_WIDTH, WINDOW_HEIGHT);  
  48.         this.setResizable(false);  
  49.         this.setBackground(Color.GREEN);  
  50.         this.addWindowListener(new WindowAdapter() {  
  51.             public void windowClosing(WindowEvent e) {  
  52.                 setVisible(false);  
  53.                 System.exit(0);  
  54.             }  
  55.         });  
  56.         this.setVisible(true);  
  57.         g=this.getGraphics();  
  58.   
  59.     }  
  60.   
  61.       
  62.       
  63.     public void Init(){  
  64.         if(GameBegin==false){  
  65.             return;  
  66.         }  
  67.         //加入我方坦克  
  68.         myTank = new Tank(Tank_X,Tank_Y,true,0);  
  69.         myTank.draw(g);  
  70.         //清空各种容器  
  71.         enemyTanks.clear();  
  72.         wallList.clear();  
  73.         grassList.clear();  
  74.         stoneList.clear();  
  75.         //加入敌方坦克  
  76.         for (int i = 0; i < tankMaxNum; i++) {  
  77.             Tank enemyTank = new Tank(200 + 50 * i, 50false1);  
  78.             enemyTanks.add(enemyTank);  
  79.             enemyTanks.get(i).Go();  
  80.             tankNum++;  
  81.         }  
  82.           
  83.         //加入城墙  
  84.         for (int i=0;i<10;i++){  
  85.             Wall wall = new Wall(100+i*18,100);  
  86.             wallList.add(wall);  
  87.             wall = new Wall(100+i*18,118);  
  88.             wallList.add(wall);  
  89.         }  
  90.         for (int i=0;i<16;i++){  
  91.             Wall wall = new Wall(450+i*18,100);  
  92.             wallList.add(wall);  
  93.             wall = new Wall(450+i*18,118);  
  94.             wallList.add(wall);  
  95.         }  
  96.         for (int i=1;i<=13;i++){  
  97.             Wall wall = new Wall(450+18*7,100+i*18);  
  98.             wallList.add(wall);  
  99.             wall = new Wall(450+18*8,100+i*18);  
  100.             wallList.add(wall);  
  101.         }  
  102.         for (int i=1;i<=2;i++){  
  103.             Wall wall = new Wall(100-18*i,136);  
  104.             wallList.add(wall);  
  105.             wall = new Wall(100-18*i,154);  
  106.             wallList.add(wall);  
  107.         }  
  108.         for (int i=1;i<=2;i++){  
  109.             Wall wall = new Wall(100-18*i,172);  
  110.             wallList.add(wall);  
  111.             wall = new Wall(100-18*i,180);  
  112.             wallList.add(wall);  
  113.         }  
  114.         for (int i=0;i<8;i++){  
  115.             Wall wall = new Wall(100+i*18,198);  
  116.             wallList.add(wall);  
  117.             wall = new Wall(100+i*18,216);  
  118.             wallList.add(wall);  
  119.         }  
  120.         for (int i=8;i<=9;i++){  
  121.             Wall wall = new Wall(100+18*i,234);  
  122.             wallList.add(wall);  
  123.             wall = new Wall(100+18*i,252);  
  124.             wallList.add(wall);  
  125.         }  
  126.         for (int i=8;i<=9;i++){  
  127.             Wall wall = new Wall(100+18*i,270);  
  128.             wallList.add(wall);  
  129.             wall = new Wall(100+18*i,288);  
  130.             wallList.add(wall);  
  131.         }  
  132.         for (int i=-2;i<8;i++){  
  133.             Wall wall = new Wall(100+i*18,306);  
  134.             wallList.add(wall);  
  135.             wall = new Wall(100+i*18,324);  
  136.             wallList.add(wall);  
  137.         }  
  138.   
  139.         for (int i=-2;i<35;i++){  
  140.             Wall wall = new Wall(100+i*18,400);  
  141.             wallList.add(wall);  
  142.             wall = new Wall(100+i*18,418);  
  143.             wallList.add(wall);  
  144.         }  
  145.         //画草  
  146.         for (int i=1;i<=13;i++){  
  147.             Grass grass = new Grass(250+18*7,100+i*18);  
  148.             grassList.add(grass);  
  149.             grass = new Grass(250+18*8,100+i*18);  
  150.             grassList.add(grass);  
  151.         }  
  152.         for (int i=1;i<=13;i++){  
  153.             Grass grass = new Grass(250+18*5,100+i*18);  
  154.             grassList.add(grass);  
  155.             grass = new Grass(250+18*6,100+i*18);  
  156.             grassList.add(grass);  
  157.         }  
  158.         //画出石头  
  159.         for (int i=-2;i<35;i++){  
  160.             Stone stone = new Stone(100+i*18,382);  
  161.             stoneList.add(stone);  
  162.             stone = new Stone(100+i*18,364);  
  163.             stoneList.add(stone);  
  164.         }  
  165.           
  166.          // 启动重画线程  
  167.         PaintThread pt = new PaintThread();  
  168.         Thread t = new Thread(pt);  
  169.         t.start();  
  170.     }  
  171.     /** 
  172.      * 绘制方法 
  173.      */  
  174.     public void paint(Graphics g) {  
  175.         g.setColor(Color.BLACK);//设置黑色背景  
  176.         g.fillRect(00, WINDOW_WIDTH, WINDOW_HEIGHT);  
  177.         if(GameBegin==false){//游戏开始提示标语  
  178.             g.setColor(Color.WHITE);  
  179.             g.drawString("请按F1开始游戏"100100);  
  180.         }  
  181.           
  182.           
  183.         if(myTank==nullreturn ;  
  184.         myTank.draw(g);  
  185.               
  186.         myTank.draw(g);  
  187.         for (int i=0;i<enemyTanks.size();i++){  
  188.             enemyTanks.get(i).draw(g);  
  189.         }  
  190.         //画出城墙  
  191.         for (int i=0;i<wallList.size();i++){  
  192.             wallList.get(i).draw(g);  
  193.         }  
  194.         //画出草地  
  195.         for (int i=0;i<grassList.size();i++){  
  196.             grassList.get(i).draw(g);  
  197.         }  
  198.         //画出钢快  
  199.         for (int i=0;i<stoneList.size();i++){  
  200.             stoneList.get(i).draw(g);  
  201.         }  
  202.     }  
  203.   
  204.       
  205.       
  206.     // 重写update方法,先将窗体上的图形画在图片对象上,再一次性显示  
  207.     public void update(Graphics g) {  
  208.         if (offScreenImage == null) {  
  209.             offScreenImage = this.createImage(WINDOW_WIDTH, WINDOW_HEIGHT);  
  210.         }  
  211.         Graphics gImage = offScreenImage.getGraphics();  
  212.         Color c = gImage.getColor();  
  213.         gImage.setColor(Color.GREEN);  
  214.         gImage.fillRect(00, WINDOW_WIDTH, WINDOW_HEIGHT);  
  215.         gImage.setColor(c);  
  216.         paint(gImage);  
  217.         g.drawImage(offScreenImage, 00null);  
  218.     }  
  219.   
  220.     // 用线程重画,每隔一段时间重画窗体  
  221.     private class PaintThread implements Runnable {  
  222.   
  223.         public void run() {  
  224.             while (true) {  
  225.                 repaint();  
  226.                 try {  
  227.                     Thread.sleep(REFRESH_RATE);  
  228.                 } catch (InterruptedException e) {  
  229.                     e.printStackTrace();  
  230.                 }  
  231.             }  
  232.         }  
  233.     }  
  234.   
  235.   
  236.     public void keyPressed(KeyEvent e) {  
  237.         if(e.getKeyCode()==java.awt.event.KeyEvent.VK_UP){//如果按键为向上键  
  238.             myTank.move(0);//向上  
  239.         }  
  240.         if(e.getKeyCode()==java.awt.event.KeyEvent.VK_DOWN){//如果按键为向下键  
  241.             myTank.move(1);   
  242.         }  
  243.         if(e.getKeyCode()==java.awt.event.KeyEvent.VK_LEFT){//如果按键为向左键  
  244.             myTank.move(2);   
  245.         }  
  246.         if(e.getKeyCode()==java.awt.event.KeyEvent.VK_RIGHT){//如果按键为向右键  
  247.             myTank.move(3);  
  248.         }if(e.getKeyCode()==java.awt.event.KeyEvent.VK_SPACE){  
  249.             myTank.fire();  
  250.         }if(e.getKeyCode()==java.awt.event.KeyEvent.VK_F1){//游戏开始  
  251.             GameBegin=true;  
  252.             Init();  
  253.         }  
  254.         //drawTank();  
  255.     }  
  256.   
  257.   
  258.     public void keyReleased(KeyEvent e) {  
  259.     }  
  260.   
  261.   
  262.     public void keyTyped(KeyEvent e) {  
  263.     }  
  264. }  

 

 

就不会再次闪烁了~

主要就是重写了update方法,制定了其刷新的方式~

 

原理:
 1.建立一个Image对象DbBuffer,通过DbBuffer=createrImage(int width,int height)来在内存中开辟一个长为width 宽为heithr空间.次空间的大小可以和你动画窗口的大小保持一致,也可以利用getwidth()和getheight()来获得动画窗口的大小.
 2.建立一个Graphics 对象GraImage通过GraImage=DbBuffer.getGraphics();去把要绘制的对象并存放到分配好的内存空间中.
 3.利用paint(GraImage);将其全部绘制带内存之中,最后调用我门的paint(Graphics g)方法中的g.drawImage(DbBuffer,0,0,null)将DbBuffer全部一次性的绘制到我门的动画窗口,然后把我门内存中分配的空间窗口关闭调用dispose()方法.

Java代码   收藏代码
  1. // 重写update方法,先将窗体上的图形画在图片对象上,再一次性显示  
  2.     public void update(Graphics g) {  
  3.         if (offScreenImage == null) {  
  4.             offScreenImage = this.createImage(WINDOW_WIDTH, WINDOW_HEIGHT);  
  5.         }  
  6.         Graphics gImage = offScreenImage.getGraphics();  
  7.         Color c = gImage.getColor();  
  8.         gImage.setColor(Color.GREEN);  
  9.         gImage.fillRect(00, WINDOW_WIDTH, WINDOW_HEIGHT);  
  10.         gImage.setColor(c);  
  11.         paint(gImage);  
  12.         g.drawImage(offScreenImage, 00null);  
  13.     }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值