android游戏开发(一)简单的图形渲染

 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://download.csdn.net/detail/ma_haile/4214215

 

 

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