熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

優化Java動畫編程中的顯示效果

2013-11-15 11:34:37  來源: JSP教程 

  Java動畫編程有多種實現方法但它們實現的基本原理是一樣的即在屏幕上畫出一系列的幀來造成運動的感覺Java多線程技術是Java動畫編程中普遍運用的技術它在控制動畫程序的流程和動畫的顯示效果方面起著重要的作用Java動畫編程中的動畫閃爍和圖像殘缺不全等現象是Java程序員經常遇到的問題本文以作者應用實例程序為基礎闡述如何運用多線程重載Update雙緩沖和圖像跟蹤等技巧來解決這類問題以達到動畫顯示的最佳效果
  
  Java多線程技術
  
  Java多線程技術簡介
  
  目前線程(Thread)已經為許多操作系統和應用開發系統所采用線程是程序的單個控制流具有順序程序的特點但是線程不是一個程序它僅僅是程序的一個執行序列線程具有很強的並發功能在同一時刻可以有多個線程同時處於執行狀態線程是動態的具有一定的生命周期分別經歷從創建執行阻塞直到消亡的過程Java語言對多線程編程的支持有兩種實現方法一種是直接繼承Thread類另一種是實現Runnable接口Thread類提供了對線程的控制方法如start()stop()run()suspend()resume()和sleep()等方法它們可以對線程的狀態進行控制
  
  動畫線程的設計與實現
  
  為了每秒中多次更新屏幕必須創建一個線程來實現動畫的循環這個循環要跟蹤當前幀並響應周期性的屏幕更新要求許多Java初學者容易犯的一個錯誤是將動畫循環放在paint()中這樣占據了主AWT線程而主線程將負責所有的繪圖和事件處理因此應該生成一個獨立的動畫線程來完成圖像的顯示和更新例如在一個Applet框架下當Applet啟動(Start)時生成一個動畫線程;在Applet停止(stop)時終止該動畫線程以釋放它所占用的CPU資源下列程序代碼(簡稱C代碼)是該動畫線程的具體實現
  
  public void start() {
   if(animatorThread==null) {
   animatorThread=new Thread(this);
  //開始動畫線程
  animatorThreadstart();
   }
  }
  public void stop(){
   //停止動畫線程
   animatorThread=null;
  }
  
  上面終止動畫線程的時候並不是調用該動畫線程的stop()方法而是設置該動畫線程為null因為如果直接調用線程的stop()方法會強制線程終止所有的執行工作有時會帶來不好的結果設置該動畫線程為null則在run()方法中由於不滿足循環條件線程會自然退出這樣也進一步優化了該動畫程序
  
  重載update()和雙緩沖技術消除閃爍
  
  在Java中動畫發生閃爍有兩個原因一個是由於在顯示下一幀畫面的時候調用了repaint()方法而repaint()方法被調用時要清除整個背景然後才調用paint()方法顯示畫面這樣在清除背景和繪制圖像的短暫時間間隔內被用戶看見的就是閃爍另一個是由於paint()方法要進行復雜的計算繪制每一幀花費的時間太長圖像中的各個像素值不能同時得到使得動畫的生成頻率低於顯示器的刷新頻率從而造成閃爍
  
  下面兩種方法可以明顯地消除或減弱閃爍
  
  重載update()方法
  
  當AWT接收到一個Applet的重繪請求時它就調用Applet的update()方法缺省情況下update()方法清除Applet的背景然後調用paint()方法重載update()方法就可以將以前在paint()方法中的繪圖代碼包含在update()方法中從而避免每次重繪時將整個區域清除既然背景不再自動清除Java程序員需要自己在update()中完成
  
  雙緩沖技術
  
  另一種消除幀之間閃爍的方法是使用雙緩沖技術它在許多動畫Applet中被使用主要原理是創建一幅後台圖像將每一幀畫入圖像然後調用drawImage()方法將整個後台圖像一次畫到屏幕上去這種方法的優點在於大部分繪制是離屏的將離屏圖像一次繪至屏幕上比直接在屏幕上繪制要有效得多在創建後台圖像前首先要通過調用createImage()方法生成合適的後台緩沖區然後獲得在緩沖區做圖的環境(即Graphics類對象)
  
  下列實例程序代碼(簡稱C代碼)就是這兩種方法的結合使用雙緩沖技術在重載update()方法中實現其中offImage是Image類的對象offGraphics是Graphics類的對象這兩個類對象是實現雙緩沖技術的關鍵相關代碼如下
  
  public void paint(Graphics g){
   update(g);
   }
   public void update(Graphics g){
   Dimension d=getSize();
   //如果後台圖像不存在就創建一個後台圖像
  if((offGraphics==null)||(dwidth!=offDimensionwidth)
   ||(dheight!=offDimensionheight)) {
   offDimension=d;
   offImage=createImage(dwidthdheight);
   offGraphics=offImagegetGraphics();
   }
   //擦除上一幀
   offGraphicssetColor(getBackground());
   offGraphicsfillRect(dwidthdheight);
   offGraphicssetColor(Colorblack);
   //將當前的幀輸出到指定的image中
   for(int i= ; i<10 ; i++){
   offGraphics.drawImage(images[i],frameNumber*5%(d.width/2)
   ,i*d.height/10,this);
   }
   //輸出指定的後台圖像
  g.drawImage(offImage,frameNumber*5%(d.width/2),0,this);
   }
  
  雙緩沖技術可以使動畫平滑,但有一個缺點,要分配一個後台圖像的緩沖,如果圖像相當大,這將占用很大一塊內存。TW.wINgWIt.coM
  圖像跟蹤與程序的逐步完善
  圖像跟蹤
  當動畫線程剛剛啟動的時候,由於沒有全部載入圖像,屏幕上顯示的畫面經常是殘缺不全的。這時可以使用MediaTracker或ImageOberver類對象進行圖像跟蹤,待圖像全部載入後,再調用drawImage()方法將圖像輸出到屏幕上去。DrawImage()方法的第四個參數正是ImageObserver類對象,所以可以用ImageObserver類對象進行圖像跟蹤。在實際應用Applet程序的init()方法中實現圖像跟蹤,相當於在動畫線程的DrawImage()方法調用以前就畫了一次圖像,因為動畫線程的初始化過程,即init()方法是先被調用的。下列代碼(簡稱“C3”代碼)展示了init()方法使用MediaTracker類對象來實現跟蹤圖像的載入,代碼如下:
  
  public void init(){
   tracker=new MidiaTracker(this);
   for(int i=1;i<=10;i++){
   image[i-1]=getImage(getCodeBase(),"image"+i+" .gif");
   //用MediaTracker類對象的addImage()方法跟蹤圖像的載入
   tracker.addImage(images[i-1],0);
   }
  ......
  }
  
  程序的進一步完善
  
  在“C2”代碼的重載update()方法中加入下列if語句,從而對MediaTracker類對象的圖像跟蹤方法做出判斷,if語句如下:
  
  if(!tracker.checkAll()){
  //如果圖像還沒有裝載完畢,則僅清除背景,同時輸出一個狀態
   g.clearRect(0,0,d.width,d.height);
   g.drawString("Please wait...",0,d.height/2);
   return;
   }
  
  在“C1”代碼的stop()方法中加入兩行代碼,用以釋放由雙緩沖技術所占用的內存資源,這時stop()方法改為:
  
  public void stop(){
   //停止動畫線程
   animatorThread=null;
   //釋放用於雙緩沖的內存資源
   offGraphics=null;
   offImage=null;
  }
  
  程序修改到此,還有一個小問題,就是動畫線程啟動後,第一幅圖像有時仍有殘留痕跡,而不是隨著圖像的更新而完全擦除掉。如果想解決此問題,只要將“C2”代碼中最後的for()循環和g.drawImage()方法改為如下代碼就可以了。
  
  for(int i=0;i<10;i++){
   offGraphics.drawImage(images[frameNumber%10],
   ,frameNumber*5%(d.width),i*d.height/10,this);
  }
  g.drawImage(offImage,0,0,this);
  
  保持恆定的幀速度
  
  為了使用戶觀看動畫時沒有閃爍感,至少需要達到每秒12幀的速度。更高的幀速度會產生更平滑的動畫。通常,在動畫顯示的每兩幀之間,調用線程的sleep()方法休眠一個固定的時間。這樣做的缺點是使用絕對的延遲時間會使延遲過長,即造成等待時間過長。為了每秒顯示10~20幀圖像,並保持恆定的幀速度(也就是恆定的顯示頻率),在動畫線程的run()方法中可加入如下代碼:
  
  try{
   startTime+=delay;
   Thread.sleep(Math.max(0,startTime-System.currentTimeMillis()));
  }catch(InterruptedException e){
   break;
  }
  
  本文著重闡述了優化Java動畫編程的顯示效果的幾種方法。當然,隨著Java技術以及其它計算機技術的發展,還將會有多種優化動畫顯示效果的方法,例如,在提高動畫的幀速度方面,可在Java中調用微軟公司的DirectDraw工具。但是本文所介紹的方法更具有通用性。
  

From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19234.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.