Android游戏开发中常用的三种视图
来源:互联网 发布:js 点击按钮刷新div 编辑:程序博客网 时间:2024/06/07 21:49
简介
Android游戏开发中常用的三种视图是View、SurfaceView和GLSurfaceView
下面简单介绍这三种视图:
- View:显示视图,内置画布,提供图形绘制函数、触屏事件、按键事件函数等;
- SurfaceView:基于View视图进行拓展的视图类,更适用于2D游戏开发;
- GLSurfaceView:基于SurfaceView视图类再次拓展的视图类,用于3D游戏开发的视图。
在2D游戏开发中,大致分为两种游戏框架:View游戏框架和SurfaceView游戏框架。两者的主要区别有:
1) 更新画布
View是由系统主UI线程进行更新,通过调用View提供的postInvalidate()和invalidate()这两个函数重新绘制的。棋牌类游戏,其画面更新属于被动更新,这类游戏适用于View游戏框架。
SurfaceView可在UI线程或者新的线程中更新。RPG、飞行射击类游戏,其画面更新属于主动更新,需要不断重绘,这类游戏实用于SurfaceView游戏框架。
2)视图机制
View视图没有双缓冲机制,而SurfaceView视图有。
实例
View游戏框架,此Demo跟踪用户的方向键点击事件,以及触屏事件,具体步骤如下:
1.新建Android项目“ViewDemo”,此处略去若干字
2.创建一个类MyView,此类继承View,代码如下:
package com.cpxiao.viewdemo;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;/** * Created by cpxiao on 15/9/19. */public class MyView extends View { private Paint mPaint; /** * 重写构造方法 */ public MyView(Context context) { super(context); init(); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { //设置焦点 setFocusable(true); mPaint = new Paint(); mPaint.setColor(Color.RED); mPaint.setTextSize(30); } /** * 重写绘图方法 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawText("MyView", textX, textY, mPaint); } int textX = 100; int textY = 100; /** * 重写按键按下事件的方法 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //判断按下的是否为方向键(上下左右) if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { textY -= 10; } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { textY += 10; } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { textX -= 10; } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { textX += 10; } //重绘画布的函数有invalidate()和postInvalidate(),区别在于invalidate()不能在子线程中循环调用,而postInvalidate()可以。 invalidate(); // postInvalidate(); return super.onKeyDown(keyCode, event); } /** * 重写按键抬起事件的方法 */ @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return super.onKeyUp(keyCode, event); } /** * 重写触屏事件方法 */ @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); if (event.getAction() == MotionEvent.ACTION_DOWN) { textX = x; textY = y; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { textX = x; textY = y; } else if (event.getAction() == MotionEvent.ACTION_UP) { textX = x; textY = y; } invalidate(); return true; // return super.onTouchEvent(event); }}
3.MainActivity代码如下:
package com.cpxiao.viewdemo;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.Window;import android.view.WindowManager;public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); View view = new MyView(this); //隐藏标题栏部分(程序名字) requestWindowFeature(Window.FEATURE_NO_TITLE); //隐藏状态栏部分(电池电量、时间等部分) getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(view); }}
SurfaceView游戏框架
1.新建Android项目“SurfaceViewDemo”,此处略去若干字
2.新建类“MySurfaceView”,此类继承SurfaceView,并且实现android.view.SurfaceHolder.Callback接口,代码如下:
package com.cpxiao.surfaceviewdemo;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;/** * Created by cpxiao on 15/9/19. */public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback { //SurfaceHolder用于控制SurfaceView的大小、格式等,用于监听SurfaceView的状态。 private SurfaceHolder mSurfaceHolder; private Paint mPaint; //初始化文本坐标 private int textX = 100; private int textY = 100; public MySurfaceView(Context context) { super(context); init(); } public MySurfaceView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { //实例SurfaceHolder mSurfaceHolder = getHolder(); //为SurfaceView添加状态监听 mSurfaceHolder.addCallback(this); //实例一个画笔 mPaint = new Paint(); mPaint.setColor(Color.RED); mPaint.setTextSize(30); } /** * 重写SurfaceHolder.Callback接口的三个方法surfaceCreated()、surfaceChanged()、surfaceDestroyed() */ /** * 当SurfaceView被创建完成后响应的方法 */ @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { myDraw(); } /** * 当SurfaceView状态发生改变时响应的方法 */ @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } /** * 当SurfaceView状态Destroyed时响应的方法 */ @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { } /** * 自定义绘图方法 */ private void myDraw() { //使用SurfaceHolder.lockCanvas()获取SurfaceView的Canvas对象,并对画布加锁. Canvas canvas = mSurfaceHolder.lockCanvas(); //得到自定义大小的画布,因为局部绘制,效率更高 // Canvas canvas = mSurfaceHolder.lockCanvas(new Rect(0,0,200,200)); /** * 在绘制之前需要将画布清空,否则画布上会显示之前绘制的内容,以下三种方法效果一致*/ canvas.drawRect(0,0,getWidth(),getHeight(),new Paint()); canvas.drawColor(Color.WHITE); canvas.drawRGB(255, 255, 255); //通过在Canvas上绘制内容来修改SurfaceView中的数据 canvas.drawText("mySurfaceView", textX, textY, mPaint); //用于解锁画布和提交 mSurfaceHolder.unlockCanvasAndPost(canvas); } /** * 重写触屏监听方法 */ @Override public boolean onTouchEvent(MotionEvent event) { textX = (int) event.getX(); textY = (int) event.getY(); myDraw(); return true;// return super.onTouchEvent(event); }}
3.MainActivity代码如下:
package com.cpxiao.surfaceviewdemo;import android.app.Activity;import android.os.Bundle;import android.view.Window;import android.view.WindowManager;public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); MySurfaceView view = new MySurfaceView(this); setContentView(view); }}
到此步骤为止,实现了和ViewDemo一致的效果。但是游戏中不会等用户按键或者触屏之后才绘制画布,往往会每隔一段时间刷新画布,比如游戏中的计时器、背景中的流水、动物等等,这些元素虽然不与用户交互但却是动态的。所以游戏开发中需要有一个线程实时更新游戏元素的状态。
完整的MySurfaceView代码如下:
package com.cpxiao.surfaceviewdemo;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;/** * Created by cpxiao on 15/9/19. */public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable { //SurfaceHolder用于控制SurfaceView的大小、格式等,用于监听SurfaceView的状态。 private SurfaceHolder mSurfaceHolder; private Paint mPaint; //初始化文本坐标 private int textX = 100; private int textY = 100; //声明一个线程 private Thread mThread; //线程消亡的标志位 private boolean flag = false; //声明一个画布 private Canvas mCanvas; //声明屏幕的宽高,获取视图的宽高一定要在视图创建之后才可获取,即surfaceCreated之后获取,否则一直为0 private int screenWidth, screenHeight; public MySurfaceView(Context context) { super(context); init(); } public MySurfaceView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { //实例SurfaceHolder mSurfaceHolder = getHolder(); //为SurfaceView添加状态监听 mSurfaceHolder.addCallback(this); //实例一个画笔 mPaint = new Paint(); mPaint.setColor(Color.RED); mPaint.setTextSize(30); //设置焦点 setFocusable(true); } /** * 重写SurfaceHolder.Callback接口的三个方法surfaceCreated()、surfaceChanged()、surfaceDestroyed() */ /** * 当SurfaceView被创建完成后响应的方法 */ @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { screenWidth = getWidth(); screenHeight = getHeight(); Log.d("CPXIAO", "screenWidth = " + screenWidth); Log.d("CPXIAO", "screenHeight = " + screenHeight); flag = true; //实例线程 mThread = new Thread(this); mThread.start(); } /** * 当SurfaceView状态发生改变时响应的方法 */ @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } /** * 当SurfaceView状态Destroyed时响应的方法 */ @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { flag = false; } /** * 自定义绘图方法 */ private void myDraw() { try { //使用SurfaceHolder.lockCanvas()获取SurfaceView的Canvas对象,并对画布加锁. mCanvas = mSurfaceHolder.lockCanvas(); //得到自定义大小的画布,因为局部绘制,效率更高 // Canvas canvas = mSurfaceHolder.lockCanvas(new Rect(0,0,200,200)); if (mCanvas != null) { /** * 在绘制之前需要将画布清空,否则画布上会显示之前绘制的内容,以下三种方法效果一致*/ mCanvas.drawRect(0, 0, getWidth(), getHeight(), new Paint()); mCanvas.drawColor(Color.WHITE); mCanvas.drawRGB(255, 255, 255); //通过在Canvas上绘制内容来修改SurfaceView中的数据 mCanvas.drawText("mySurfaceView", textX, textY, mPaint); } } catch (Exception e) { e.printStackTrace(); } finally { if (mSurfaceHolder != null) { //用于解锁画布和提交 mSurfaceHolder.unlockCanvasAndPost(mCanvas); } } } /** * 重写触屏监听方法 */ @Override public boolean onTouchEvent(MotionEvent event) { textX = (int) event.getX(); textY = (int) event.getY(); myDraw(); return true; // return super.onTouchEvent(event); } private int moveX = 10; private int moveY = 10; /** * 程序逻辑代码 */ private void logic() { if (textX < 0) { moveX = 10; } else if (textX > screenWidth) { moveX = -10; } if (textY < 0) { moveY = 10; } else if (textY > screenHeight) { moveY = -10; } textX += moveX; textY += moveY; } //设置刷新时间为50毫秒 private static final int REFRESH_TIME = 50; @Override public void run() { while (flag) { long start = System.currentTimeMillis(); myDraw(); logic(); long end = System.currentTimeMillis(); try { long use_time = end - start; if (use_time < REFRESH_TIME) { mThread.sleep(REFRESH_TIME - use_time); } } catch (Exception e) { e.printStackTrace(); } } }}
代码说明:
1)线程标志位flag
- 便于消亡线程
- 防止重复创建线程,避免程序异常
2)获取视图的宽高
- getWidth()和getHeight()
- 获取视图的宽高一定要在视图创建之后才可获取,即surfaceCreated之后获取,否则一直为0。因为视图还未创建之前是没有宽高值的
3)绘制时try catch finally
- 判断Canvas是否为null
- 为防止绘制出错无法运行到解锁提交这一步,将unlockCanvasAndPost放在finally中执行,执行前先判断一下SurfaceHolder是否为空
4)刷新时间尽可能保持一直,保证帧数
- 根据逻辑处理用时,计算出每次绘制休眠时间
Demo下载
- Android游戏开发中常用的三种视图
- Android游戏开发中常用的三种视图
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的数学公式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- hihoCoder#1052 基因工程
- HDU 5459 Jesus Is Here
- HDU 5451 Best Solver
- 难
- jmeter(二)测试思维
- Android游戏开发中常用的三种视图
- Android FrameWork中的SP、RefBase、weakref_impl,Thread类
- 快速排序
- 文件管理神器TC8.5特别定制版
- 软件测试重点内容
- 快拷神器ExtremeCopy
- 使用Nginx+Lua搭建AB测试平台
- Minimum Cut(2015年吉林网络赛)
- 用两个栈实现队列