推箱子游戲開發(一) surfaceView 實現動畫效果

SurfaceView是View的子類,常用於實現遊戲中的動畫效果。SurfaceView最大的特點就是:從主線程中,把具體的繪圖線程獨立出來。這樣做的好處在於:當繪圖任務比較繁重時,避免主線程的阻塞,從而提高主線程的反應速度。

        廢話少說,言歸正傳,下面用幾個例子說明surfaceview的使用。

(一) 基本功能:用SurfaceView顯示一副背景圖片。 運行後的效果很簡單,就是在屏幕上顯示一副圖片。

  1. package com.pushBox; 
  2.  
  3. import android.app.Activity; 
  4. import android.content.Context; 
  5. import android.graphics.Bitmap; 
  6. import android.graphics.BitmapFactory; 
  7. import android.graphics.Canvas; 
  8. import android.os.Bundle; 
  9. import android.view.SurfaceHolder; 
  10. import android.view.SurfaceView; 
  11.  
  12. public class PushBoxActivity extends Activity { 
  13.     //歡迎界面 
  14.     WelcomeView welcomeView = null;  
  15.      
  16.     /** Called when the activity is first created. */ 
  17.     @Override 
  18.     public void onCreate(Bundle savedInstanceState) { 
  19.         super.onCreate(savedInstanceState); 
  20.          
  21.         //顯示歡迎界面 
  22.         welcomeView = new WelcomeView( this );         
  23.         setContentView( welcomeView );  
  24.     } 
  25.      
  26.     //內部類,歡迎界面 
  27.     class WelcomeView extends SurfaceView implements SurfaceHolder.Callback 
  28.     { 
  29.         private SurfaceHolder holder;     
  30.         private WelcomeViewDrawThread welcomeViewDrawThread; 
  31.         //背景圖片,大小640 * 480 
  32.         Bitmap background; 
  33.          
  34.         //圖片顯示的位置 
  35.         int backgroundX = 0
  36.         int backgroundY = 0
  37.          
  38.         public WelcomeView( Context context ) 
  39.         { 
  40.             super( context );            
  41.             holder = this.getHolder(); 
  42.             holder.addCallback( this );          
  43.             background = BitmapFactory.decodeResource( getResources(), R.drawable.background ); 
  44.             //創建一個繪圖線程 
  45.             welcomeViewDrawThread = new WelcomeViewDrawThread( this, holder ); 
  46.         } 
  47.          
  48.         //自定義的繪圖函數,具體的繪圖在這裏完成 
  49.         public void onDraw( Canvas c ) 
  50.         { 
  51.             c.drawBitmap( background, backgroundX, backgroundY, null );          
  52.         } 
  53.          
  54.         @Override 
  55.         public void surfaceChanged(SurfaceHolder holder, int format, int width, 
  56.                 int height) { 
  57.             // TODO Auto-generated method stub           
  58.         } 
  59.         @Override 
  60.         public void surfaceCreated(SurfaceHolder holder) { 
  61.             // TODO Auto-generated method stub 
  62.             //啓動繪圖線程 
  63.             welcomeViewDrawThread.setFlag( true ); 
  64.             welcomeViewDrawThread.start(); 
  65.         } 
  66.         @Override 
  67.         public void surfaceDestroyed(SurfaceHolder holder) { 
  68.             // TODO Auto-generated method stub 
  69.             welcomeViewDrawThread.setFlag( false ); 
  70.         } 
  71.     }     
  72.          
  73.     //內部類,歡迎界面的繪圖線程 
  74.     class WelcomeViewDrawThread extends Thread 
  75.     { 
  76.         private WelcomeView welcomeView; 
  77.         private SurfaceHolder holder; 
  78.         private boolean isRun;   
  79.         private int sleepSpan = 200
  80.          
  81.         public WelcomeViewDrawThread( WelcomeView welcomeView, SurfaceHolder holder ) 
  82.         { 
  83.             this.welcomeView = welcomeView; 
  84.             this.holder = holder; 
  85.             isRun = true
  86.         } 
  87.         public void setFlag( boolean flag ) 
  88.         { 
  89.             isRun = flag; 
  90.         } 
  91.  
  92.         @Override 
  93.         public void run() { 
  94.             // TODO Auto-generated method stub 
  95.             while( isRun ) 
  96.             { 
  97.                 Canvas c = null
  98.                 try 
  99.                 { 
  100.                     c = holder.lockCanvas(); 
  101.                     synchronized( holder ) 
  102.                     { 
  103.                         //調用繪圖函數 
  104.                         welcomeView.onDraw( c );                         
  105.                     } 
  106.                 }finally 
  107.                 { 
  108.                     if( c != null
  109.                     { 
  110.                         holder.unlockCanvasAndPost( c ); 
  111.                     } 
  112.                 } 
  113.                  
  114.                 try
  115.                     //睡眠200毫秒 
  116.                     Thread.sleep( sleepSpan ); 
  117.                 } 
  118.                 catch(Exception e){ 
  119.                     e.printStackTrace(); 
  120.                 } 
  121.             } 
  122.         }        
  123.     } 
package com.pushBox;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class PushBoxActivity extends Activity {
	//歡迎界面
	WelcomeView welcomeView = null;	
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        //顯示歡迎界面
        welcomeView = new WelcomeView( this );        
        setContentView( welcomeView ); 
    }
    
    //內部類,歡迎界面
    class WelcomeView extends SurfaceView implements SurfaceHolder.Callback
    {
    	private SurfaceHolder holder;    
    	private WelcomeViewDrawThread welcomeViewDrawThread;
    	//背景圖片,大小640 * 480
    	Bitmap background;
    	
    	//圖片顯示的位置
    	int backgroundX = 0;
    	int backgroundY = 0;
    	
    	public WelcomeView( Context context )
    	{
    		super( context );    		
    		holder = this.getHolder();
    		holder.addCallback( this );    		
    		background = BitmapFactory.decodeResource( getResources(), R.drawable.background );
    		//創建一個繪圖線程
    		welcomeViewDrawThread = new WelcomeViewDrawThread( this, holder );
    	}
    	
    	//自定義的繪圖函數,具體的繪圖在這裏完成
    	public void onDraw( Canvas c )
    	{
    		c.drawBitmap( background, backgroundX, backgroundY, null );    		
    	}
    	
    	@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			// TODO Auto-generated method stub			
		}
		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			//啓動繪圖線程
			welcomeViewDrawThread.setFlag( true );
			welcomeViewDrawThread.start();
		}
		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			welcomeViewDrawThread.setFlag( false );
		}
    }    
        
    //內部類,歡迎界面的繪圖線程
    class WelcomeViewDrawThread extends Thread
    {
    	private WelcomeView welcomeView;
    	private SurfaceHolder holder;
    	private boolean isRun;  
    	private int sleepSpan = 200;
    	
    	public WelcomeViewDrawThread( WelcomeView welcomeView, SurfaceHolder holder )
    	{
    		this.welcomeView = welcomeView;
    		this.holder = holder;
    		isRun = true;
    	}
    	public void setFlag( boolean flag )
    	{
    		isRun = flag;
    	}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while( isRun )
			{
				Canvas c = null;
				try
				{
					c = holder.lockCanvas();
					synchronized( holder )
					{
						//調用繪圖函數
						welcomeView.onDraw( c );						
					}
				}finally
				{
					if( c != null )
					{
						holder.unlockCanvasAndPost( c );
					}
				}
				
				try{
					//睡眠200毫秒
					Thread.sleep( sleepSpan );
				}
				catch(Exception e){
					e.printStackTrace();
				}
			}
		}    	
    }
}


(二) 初露鋒芒:用SurfaceView顯示一個動態打開的門。運行後的效果,左右兩扇門緩緩打開。    

        如果只用SurfaceView顯示一副背景圖片,那絕對是“大炮打蚊子”------大材小用。從主線程中拉出一個單獨的線程,就是爲了處理動態效果。這裏具體實現的時候有兩個線程:welcomeViewGoThread和welcomeViewDrawThread。welcomeViewGoThread只負責修改圖片顯示的座標,welcomeViewDrawThread負責在具體的位置顯示圖片。這種進一步分離,使得各模塊的功能更加獨立和明確。

  1. package com.pushBox; 
  2.  
  3. import android.app.Activity; 
  4. import android.content.Context; 
  5. import android.graphics.Bitmap; 
  6. import android.graphics.BitmapFactory; 
  7. import android.graphics.Canvas; 
  8. import android.os.Bundle; 
  9. import android.view.SurfaceHolder; 
  10. import android.view.SurfaceView; 
  11.  
  12. public class PushBoxActivity extends Activity { 
  13.     //歡迎界面 
  14.     WelcomeView welcomeView = null;  
  15.     //歡迎界面的動畫線程 
  16.     WelcomeViewGoThread welcomeViewGoThread = null
  17.      
  18.     /** Called when the activity is first created. */ 
  19.     @Override 
  20.     public void onCreate(Bundle savedInstanceState) { 
  21.         super.onCreate(savedInstanceState); 
  22.          
  23.         //顯示歡迎界面 
  24.         welcomeView = new WelcomeView( this );         
  25.         setContentView( welcomeView );  
  26.         welcomeViewGoThread = new WelcomeViewGoThread( welcomeView ); 
  27.         //啓動動畫線程 
  28.         welcomeViewGoThread.start(); 
  29.     } 
  30.      
  31.     //內部類,歡迎界面 
  32.     class WelcomeView extends SurfaceView implements SurfaceHolder.Callback 
  33.     { 
  34.         private SurfaceHolder holder;     
  35.         private WelcomeViewDrawThread welcomeViewDrawThread; 
  36.         //背景圖片,大小640 * 480 
  37.         Bitmap background; 
  38.         //左邊的木門,大小180 * 450 
  39.         Bitmap leftWood; 
  40.         Bitmap rightWood; 
  41.          
  42.         //圖片顯示的位置 
  43.         int backgroundX = 0
  44.         int backgroundY = 0
  45.         int leftWoodX = 10
  46.         int leftWoodY = 15
  47.         int rightWoodX = 150
  48.         int rightWoodY = 15
  49.          
  50.         public WelcomeView( Context context ) 
  51.         { 
  52.             super( context );            
  53.             holder = this.getHolder(); 
  54.             holder.addCallback( this );          
  55.             background = BitmapFactory.decodeResource( getResources(), R.drawable.background ); 
  56.             leftWood = BitmapFactory.decodeResource( getResources(), R.drawable.image33 ); 
  57.             rightWood = BitmapFactory.decodeResource( getResources(), R.drawable.image3 ); 
  58.              
  59.             //創建一個繪圖線程 
  60.             welcomeViewDrawThread = new WelcomeViewDrawThread( this, holder ); 
  61.         } 
  62.          
  63.         //自定義的繪圖函數,具體的繪圖在這裏完成 
  64.         public void onDraw( Canvas c ) 
  65.         { 
  66.             c.drawBitmap( background, backgroundX, backgroundY, null );   
  67.             c.drawBitmap( leftWood, leftWoodX, leftWoodY, null );  
  68.             c.drawBitmap( rightWood, rightWoodX, rightWoodY, null );  
  69.         } 
  70.          
  71.         @Override 
  72.         public void surfaceChanged(SurfaceHolder holder, int format, int width, 
  73.                 int height) { 
  74.             // TODO Auto-generated method stub           
  75.         } 
  76.         @Override 
  77.         public void surfaceCreated(SurfaceHolder holder) { 
  78.             // TODO Auto-generated method stub 
  79.             //啓動繪圖線程 
  80.             welcomeViewDrawThread.setFlag( true ); 
  81.             welcomeViewDrawThread.start(); 
  82.         } 
  83.         @Override 
  84.         public void surfaceDestroyed(SurfaceHolder holder) { 
  85.             // TODO Auto-generated method stub 
  86.             welcomeViewDrawThread.setFlag( false ); 
  87.         } 
  88.     }  
  89.      
  90.     //內部類,歡迎界面的動畫線程,只修改座標,不負責具體顯示 
  91.     class WelcomeViewGoThread extends Thread 
  92.     { 
  93.         private WelcomeView welcomeView; 
  94.         private int sleepSpan = 200
  95.         private boolean isRun; 
  96.          
  97.         public WelcomeViewGoThread( WelcomeView welcomeView ) 
  98.         { 
  99.             this.welcomeView = welcomeView; 
  100.             isRun = true
  101.         } 
  102.         public void setFlag( boolean flag ) 
  103.         { 
  104.             isRun = flag; 
  105.         } 
  106.          
  107.         @Override 
  108.         public void run() { 
  109.             // TODO Auto-generated method stub 
  110.             while( isRun ) 
  111.             { 
  112.                 // 修改木門座標 
  113.                 welcomeView.leftWoodX -= 2
  114.                 welcomeView.rightWoodX += 2
  115.                 if( welcomeView.leftWoodX < -90
  116.                 { 
  117.                     welcomeView.leftWoodX = 10
  118.                     welcomeView.rightWoodX = 150
  119.                 }                
  120.                 try
  121.                     //睡眠200毫秒 
  122.                     Thread.sleep( sleepSpan ); 
  123.                 } 
  124.                 catch(Exception e){ 
  125.                     e.printStackTrace(); 
  126.                 } 
  127.             } 
  128.         }        
  129.     } 
  130.          
  131.     //內部類,歡迎界面的繪圖線程 
  132.     class WelcomeViewDrawThread extends Thread 
  133.     { 
  134.         private WelcomeView welcomeView; 
  135.         private SurfaceHolder holder; 
  136.         private boolean isRun;   
  137.         private int sleepSpan = 200
  138.          
  139.         public WelcomeViewDrawThread( WelcomeView welcomeView, SurfaceHolder holder ) 
  140.         { 
  141.             this.welcomeView = welcomeView; 
  142.             this.holder = holder; 
  143.             isRun = true
  144.         } 
  145.         public void setFlag( boolean flag ) 
  146.         { 
  147.             isRun = flag; 
  148.         } 
  149.  
  150.         @Override 
  151.         public void run() { 
  152.             // TODO Auto-generated method stub 
  153.             while( isRun ) 
  154.             { 
  155.                 Canvas c = null
  156.                 try 
  157.                 { 
  158.                     c = holder.lockCanvas(); 
  159.                     synchronized( holder ) 
  160.                     { 
  161.                         //調用繪圖函數 
  162.                         welcomeView.onDraw( c );                         
  163.                     } 
  164.                 }finally 
  165.                 { 
  166.                     if( c != null
  167.                     { 
  168.                         holder.unlockCanvasAndPost( c ); 
  169.                     } 
  170.                 } 
  171.                  
  172.                 try
  173.                     //睡眠200毫秒 
  174.                     Thread.sleep( sleepSpan ); 
  175.                 } 
  176.                 catch(Exception e){ 
  177.                     e.printStackTrace(); 
  178.                 } 
  179.             } 
  180.         }        
  181.     } 
package com.pushBox;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class PushBoxActivity extends Activity {
	//歡迎界面
	WelcomeView welcomeView = null;	
	//歡迎界面的動畫線程
	WelcomeViewGoThread welcomeViewGoThread = null;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        //顯示歡迎界面
        welcomeView = new WelcomeView( this );        
        setContentView( welcomeView ); 
        welcomeViewGoThread = new WelcomeViewGoThread( welcomeView );
        //啓動動畫線程
        welcomeViewGoThread.start();
    }
    
    //內部類,歡迎界面
    class WelcomeView extends SurfaceView implements SurfaceHolder.Callback
    {
    	private SurfaceHolder holder;    
    	private WelcomeViewDrawThread welcomeViewDrawThread;
    	//背景圖片,大小640 * 480
    	Bitmap background;
    	//左邊的木門,大小180 * 450
    	Bitmap leftWood;
    	Bitmap rightWood;
    	
    	//圖片顯示的位置
    	int backgroundX = 0;
    	int backgroundY = 0;
    	int leftWoodX = 10;
    	int leftWoodY = 15;
    	int rightWoodX = 150;
    	int rightWoodY = 15;
    	
    	public WelcomeView( Context context )
    	{
    		super( context );    		
    		holder = this.getHolder();
    		holder.addCallback( this );    		
    		background = BitmapFactory.decodeResource( getResources(), R.drawable.background );
    		leftWood = BitmapFactory.decodeResource( getResources(), R.drawable.image33 );
    		rightWood = BitmapFactory.decodeResource( getResources(), R.drawable.image3 );
    		
    		//創建一個繪圖線程
    		welcomeViewDrawThread = new WelcomeViewDrawThread( this, holder );
    	}
    	
    	//自定義的繪圖函數,具體的繪圖在這裏完成
    	public void onDraw( Canvas c )
    	{
    		c.drawBitmap( background, backgroundX, backgroundY, null );  
    		c.drawBitmap( leftWood, leftWoodX, leftWoodY, null ); 
    		c.drawBitmap( rightWood, rightWoodX, rightWoodY, null ); 
    	}
    	
    	@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			// TODO Auto-generated method stub			
		}
		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			//啓動繪圖線程
			welcomeViewDrawThread.setFlag( true );
			welcomeViewDrawThread.start();
		}
		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			welcomeViewDrawThread.setFlag( false );
		}
    } 
    
    //內部類,歡迎界面的動畫線程,只修改座標,不負責具體顯示
    class WelcomeViewGoThread extends Thread
    {
    	private WelcomeView welcomeView;
    	private int sleepSpan = 200;
    	private boolean isRun;
    	
    	public WelcomeViewGoThread( WelcomeView welcomeView )
    	{
    		this.welcomeView = welcomeView;
    		isRun = true;
    	}
    	public void setFlag( boolean flag )
    	{
    		isRun = flag;
    	}
    	
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		while( isRun )
    		{
    			// 修改木門座標
    			welcomeView.leftWoodX -= 2;
    			welcomeView.rightWoodX += 2;
    			if( welcomeView.leftWoodX < -90 )
    			{
    				welcomeView.leftWoodX = 10;
        			welcomeView.rightWoodX = 150;
    			}    			
    			try{
    				//睡眠200毫秒
    				Thread.sleep( sleepSpan );
    			}
    			catch(Exception e){
    				e.printStackTrace();
    			}
    		}
    	}    	
    }
        
    //內部類,歡迎界面的繪圖線程
    class WelcomeViewDrawThread extends Thread
    {
    	private WelcomeView welcomeView;
    	private SurfaceHolder holder;
    	private boolean isRun;  
    	private int sleepSpan = 200;
    	
    	public WelcomeViewDrawThread( WelcomeView welcomeView, SurfaceHolder holder )
    	{
    		this.welcomeView = welcomeView;
    		this.holder = holder;
    		isRun = true;
    	}
    	public void setFlag( boolean flag )
    	{
    		isRun = flag;
    	}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while( isRun )
			{
				Canvas c = null;
				try
				{
					c = holder.lockCanvas();
					synchronized( holder )
					{
						//調用繪圖函數
						welcomeView.onDraw( c );						
					}
				}finally
				{
					if( c != null )
					{
						holder.unlockCanvasAndPost( c );
					}
				}
				
				try{
					//睡眠200毫秒
					Thread.sleep( sleepSpan );
				}
				catch(Exception e){
					e.printStackTrace();
				}
			}
		}    	
    }
}

(三) 脫胎換骨:修改程序框架。

           上述的程序框架有問題,所有代碼都放在一個文件裏。下面要做的就是把相關的class都獨立出來。代碼改起來也很簡單,只要把幾個內部類單獨寫到一個文件即可。

(四) 重出江湖:用SurfaceView實現一個完整的歡迎界面

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章