Android應用程序入門 推箱子游戲開發(一) surfaceView 實現動畫效果

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

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

 

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

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負責在具體的位置顯示圖片。這種進一步分離,使得各模塊的功能更加獨立和明確。

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實現一個完整的歡迎界面


 

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