android遊戲開發(一)簡單的圖形渲染

來源:互聯網
上載者:User

android遊戲開發一般都是用view或surfaceView 這一章我們來學習學習 view或surfaceView 的用法 如果渲染出圖片
 
我們先看看View
   view類是android的一個超類, 這個類包含了所有的螢幕類型,每一個View都有一個用於繪圖的畫布,這個畫布可以任意擴充. 任何一個view類只需重寫onDrae()方法來實現介面顯示。
   遊戲的核心就是不斷的繪圖和重新整理介面,圖片我們通過onDraw方法來繪製,那如何來重新整理介面呢, android中提供了ivalidate方法來實現介面重新整理,注意 invalidate不能直接線上程中調用(就是不可以再子線程中調用 這個位置各位童鞋要注意喔) 因為它違背了android單執行緒模式, android ui操作並不是安全執行緒的,並且這些操作必須在ui線程中執行, 在平時使用中最常見的方式就是 通過 handler來實現ui線程的更新.
下面我們來看看樣本 一張圖片上下移動的 效果
 這個樣本有兩個類 
一個gameView 類該類需要繼承View類作為遊戲介面輸出和控制類.
一個是 MainActivity類 該類需要繼承Activity 作為程式的入口和重新整理我們的視圖.
我們先看看gameView類的內容
 
package yxqz.com;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
 
/**
 * android view簡單的圖片繪製 該類需要繼承view 基類
 * @author mahaile
 *
 */
public class GameView extends View {
 Bitmap bitmap_role;
 float width,height;
 float x,y;  //圖片渲染所在的螢幕的位置
 int direction=0;  //圖片運行方向 控製圖片向上 或向下運動
 /**
 * 構造方法
 * @param context
 * @param width 螢幕寬度
 * @param height 螢幕高度
 */
 public GameView(Context context,float width,float height) {
  super(context);
  this.width=width;
  this.height=height;
  //通過BitmapFactory.decodeResource 方法可以自動載入 res/drawable目錄下的圖片 R.drawable.role參數為android自動產生的圖片id
  bitmap_role=BitmapFactory.decodeResource(context.getResources(), R.drawable.role);
  x=width/2-bitmap_role.getWidth()/2;
 }
 
 @Override
 protected void onDraw(Canvas canvas) {
  // TODO Auto-generated method stub
  Log.d("GameView","GameView onDraw x is:"+x +"y is:"+y);  //Log類方法用於日誌輸出
  canvas.drawBitmap(bitmap_role, x, y, null);
  super.onDraw(canvas);
 }
}
 
下面是 MainActivity 類
 
package yxqz.com;
import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
 
public class MainActivity extends Activity {
    /** Called when the activity is first created. */
 GameView gameView;
 GameSurfaceView gameSurfaceView;
 
 boolean flag; //線程標示位 當為false時停止重新整理介面
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
       
        //通過displayMetrics擷取螢幕的寬高
        DisplayMetrics dm = new DisplayMetrics();
  this.getWindowManager().getDefaultDisplay().getMetrics(dm);
  int width = dm.widthPixels;
  int height = dm.heightPixels;
  gameView=new GameView(this,width,height);
        setContentView(gameView);
        flag=true;
        new Thread(new GameThread()).start();
    }
   
    class GameThread implements Runnable{
 
  public void run() {
   while(flag){
    if(gameView.direction==0){
     gameView.y+=0.2;
     if(gameView.y>=gameView.height){
      gameView.direction=1;
     }
    }else{
     gameView.y-=0.2;
     if(gameView.y<=0){
      gameView.direction=0;
     }
    }
    //通知UI線程重繪, gameView的主線程會自動調用onDraw的方法 這點要注意了 喔
    gameView.postInvalidate();
    
    //如果使用 gameView.invalidate(); 方法的話 需要需要把gameView.invalidate()寫到 handler 裡面  因為它只支援ui主線程中使用   }
  }
  }
    }
}
 
 
上面的執行個體 簡單的講解了 android View 的使用 下面我們在看看SurfaceView 是怎麼使用的
SurfaceView的特性是:可以在主線程之外的線程向螢幕中繪圖,這樣可以避免畫圖任務繁重的時候造成主線程阻塞,從而提高程式的反應速度
有一點需要注意下surfaceView 沒有OnDraw方法重新 需要自己實現並調用
使用SurfaceView 首先需要繼承SurfaceView 並實現SurfaceHolder.Callback介面
實現 SurfaceHolder.Callback介面需要實現下面幾個介面
 
//在surface的大小改變時調用  即橫豎屏切換的時候調用
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {}
//在surface建立的時候調用  這裡一般是 啟動繪製螢幕線程
public void surfaceCreated(SurfaceHolder surfaceHolder) {}
//在surface銷毀時調用  這裡一般做資源銷毀等操作
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {}
 
SurfaceHolder是surface的控制器,用來控制surface。 處理Cavas上面的效果,動畫,控製表面,大小,像素等 
這裡需要注意幾個方法
//給SurfaceView當前持有人一個回調對象
(1) abstract void addCallback(SurfaceHolder.Callback callback);
//鎖定畫布,一般在鎖定後可以返回畫布對象Canvas ,在其上面畫圖操作
(2) abstract Canvas lockCanvas();
//鎖定畫布的某個地區進行畫圖等,因為畫完圖後,會調用下面的unlockCanvasAndPost來改變顯示的內容  針對遊戲記憶體要求高的遊戲,可以不用重畫rect外地區的像素 可以提高速度
(3) abstract Canvas lockCanvas(Rect rect);
//結束鎖定畫布,並提交改變
(4) abstract void unlockCanvasAndPost(Canvas canvas);
 使用 surfaceView的整個過程 
繼承SurfaceView並實現SurfaceHolder.Callback介面 --> SurfaceView.getHolder()獲得surfaceHolder對象--> SurfaceHolder.addCallback(callback)添加回呼函數 --> SurfaceHolder.lockCanvas()獲得Canvas對象並鎖定畫布 -->
Canvas繪畫-->
SurfaceHolder.unlockCanvasAndPost(Canvas canvas)--> 結束鎖定畫圖 並提交改變,將圖形顯示
 
下面我們看看 範例程式碼 GameSufaceView
 
package yxqz.com;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;

/**
 * android surfaceview簡單的圖片繪製
 * @author mahaile
 *
 */
public class GameSurfaceView extends SurfaceView implements Callback {
 
 boolean flag; //線程標示位 當為false時停止重新整理介面
 SurfaceHolder surfaceHolder;
 GameViewThread gameViewThread;
 int x,y;
 int direction=0;  //圖片運行方向 控製圖片向上 或向下運動
 int width,height;
 Bitmap bitmap_role;
 public GameSurfaceView(Context context) {
  super(context);
  surfaceHolder=this.getHolder();
  surfaceHolder.addCallback(this); //添加回調
  bitmap_role=BitmapFactory.decodeResource(getResources(), R.drawable.role);
 }
 
 public void onDraw(Canvas canvas){
  canvas.drawColor(Color.BLACK);
  canvas.drawBitmap(bitmap_role, width/2-bitmap_role.getWidth()/2, y, null);
 }

 public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
  
 }

 public void surfaceCreated(SurfaceHolder surfaceHolder) {
  //擷取螢幕的 寬高 只有在 surface建立的時候 才有效 ,才構造方法中擷取 寬高是擷取不到的
  width=this.getWidth();
  height=this.getHeight();
  //初始化繪圖線程
  gameViewThread=new GameViewThread();
  gameViewThread.flag=true;
  gameViewThread.start();
 }

 public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
  gameViewThread.flag=false; //銷毀線程
 }

 
 class GameViewThread extends Thread{
  public boolean flag;
  public void run(){
   while(flag){
    Canvas canvas=null;
    try{
     if(direction==0){
      if(y>=height){
       direction=1; 
      }
      y+=1;
     }else{
      if(y<=0){
       direction=0; 
      }
      y-=1;
     }
     canvas=surfaceHolder.lockCanvas(); //鎖定畫布 並擷取canvas
     onDraw(canvas);//調用onDraw 渲染到螢幕
     surfaceHolder.unlockCanvasAndPost(canvas); //此步不要忘記了喔 否則介面上顯示不出來的
    }catch(Exception e){
     e.printStackTrace();
    }
    
    try {
     Thread.sleep(10);//線程休眠時間 單位是毫秒  控制幀數
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }  //每一秒重新整理一次
    
   
   }
  }
 }
}

下面看看 mainActicity代碼 程式的入口 這個就 相當簡單了

 
 
package yxqz.com;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
 GameSurfaceView gameSurfaceView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
  gameSurfaceView=new GameSurfaceView(this);
        setContentView(gameSurfaceView);
      
    }
 
}
 
 上面 分別列出了view 和surfaceView  分別跑兩個程式 發現 上面的程式中 view比surfaceView的幀數還快 這是為什麼呢, 不是說surfaceView 比view效率高嗎 ?  
  千萬不要這麼想喔,  view 對於渲染不複雜的程式 是比surfaceView 的高的 ,還有一點是 上面的程式中 沒有哪個位置 對cpu 比較消耗的, 如果對cpu 消耗比較厲害的話 surfaceView 就會比view 的效率會高的
下面是上面上個程式的源碼 ,感興趣的同學 可以 研究下  歡迎拍磚喔.. 共同學習 一起進步
http://www.bkjia.com/uploadfile/2012/0417/20120417095628177.rar
 

 
摘自 android,unity3d

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.