




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第四章 Android游戏开发之图形界面4.1 图片图片是游戏的必备元素之一。4.1.1 drawable对象游戏所使用到的图片资源,我们都把它放置到res文件夹中的drawable中,当增加了drawable对象后,Android SDK会为该图片资源在R清单文件中创建一个索引项,该索引的名字为R.drawable.fileName。生成了该资源的索引后,在XML资源文件中就可以通过drawable/fileName来访问该图片资源,也可以在代码中R.drawable.fileName来访问该drawable对象。而R.drawable.fileName只是一个int类型的常量,它只是代表了
2、drawable对象的ID,程序代码当中需要获取到实际的drawable对象,需要调用Resource的getDrawable(int id)方法来获取。4.1.2 BitmapBitmap即位图,Bitmap类中欧那个提供了一些静态方法来创建新的Bitmap对象,如下是常用的方法。 static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) 从源Bitmap source的制定坐标x,y开始取width和height宽高的矩形块,并且制定变换矩
3、阵创建新的Bitmap对象。static Bitmap createBitmap(int width, int height, Bitmap.Config config) 创建一个制定宽高的可变位图。static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) 从源Bitmap source的制定坐标x,y开始取width和height宽高的矩形块创建新的Bitmap对象。static Bitmap createBitmap(int colors, int offset, int stride, i
4、nt width, int height, Bitmap.Config config) 利用到colors资源数组的指定数据部分创建一个width宽和height高的位图static Bitmap createBitmap(Bitmap src) 以src为数据源创建一个新的Bitmap对象。static Bitmap createBitmap(int colors, int width, int height, Bitmap.Config config) 利用到colors资源数组的数据部分创建一个width宽和height高的位图 开发者也可以把一个Bitmap对象包装成一个BitmapD
5、rawable对象,如:BitmapDrawable drawable = new BitmapDrawable(bitmap);获取BitmapDrawable所包装的Bitmap对象可以调用该类的getBitmap()方法,如Bitmap bitmap = drawable.getBitmap();。 BitmapFactory是一个Bitamap的工具类,它共提供了多种方法以便于从不同的数据源来解析和创建Bitmap对象,如下。static Bitmap decodeByteArray(byte data, int offset, int length, BitmapFactory.Op
6、tions opts) 从指定的字节数组的offset位置开始将长度为length的字节数据解析成Bitmap对象static Bitmap decodeByteArray(byte data, int offset, int length) 从指定的字节数组的offset位置开始将长度为length的字节数据解析成Bitmap对象static Bitmap decodeFile(String pathName) 从pathName制定的文件中解析创建Bitmap对象static Bitmap decodeFile(String pathName, BitmapFactory.Options
7、opts) 从pathName制定的文件中解析创建Bitmap对象static Bitmap decodeFileDescriptor(FileDescriptor fd) 从FileDescriptor对应的文件中解析和创建Bitmap对象。static Bitmap decodeResource(Resources res, int id, BitmapFactory.Options opts) 根据给定的资源id从制定的资源中解析创建Bitmap对象。static Bitmap decodeResource(Resources res, int id) 根据给定的资源id从制定的资源中解
8、析创建Bitmap对象。static Bitmap decodeStream(InputStream is) 从指定输出流中解析创建Bitmap对象。 在开发的过程中,大部分时候,只需要将图片放置到res的drawable目录中,而程序代码中通过该图片对应的资源ID来获取封装该图片的drawable对象即可。但手机系统的内存是有限的,如果不停的创建Bitmap对象,就会导致内存不够用的情况,所以Bitmap有各两个非常重要的方法来判断图片资源的是否回收和强制Bitmap进行回收。一下都是一些Bitmap常用到的方法。final int getHeight() 返回图片的高度int getPix
9、el(int x, int y) 获取到指定像素的颜色void getPixels(int pixels, int offset, int stride, int x, int y, int width, int height) 获取图片的部分像素信息到pixels数组中final int getWidth() 获取到图片的宽度final boolean hasAlpha() 判断是否支持颜色的Alpha混合final boolean isMutable() 是否为可变图片final boolean isRecycled() 是否已经被回收void recycle() 强制立刻回收自己4.2
10、绘图了解了图片后,游戏当中最重要的一部分操作就是图片的绘制了。本节主要来介绍Android当中的绘图。Android当中的绘图组件都是继承自View组件,并且重写onDraw(Canvas canvas)方法即可。关于View前面的章节当中已经讲解过了,本节主要来看看涉及到绘图onDraw方法当中的Canvas对象,以及相关的Paint类的使用。4.2.1 Canvas类 Canvas可以理解为一张画布,而该画布是属于它所在的View对象的。Canvas当中提供了一系列的方法用于绘制,如下。void drawArc(RectF oval, float startAngle, float swe
11、epAngle, boolean useCenter, Paint paint) 绘制弧void drawBitmap(int colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint) 绘制Bitmap从数据源colors中。void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) 绘制一个设置置顶matrix变化的Bitmapvoid drawBitmap(int colors, in
12、t offset, int stride, int x, int y, int width, int height, boolean hasAlpha, Paint paint) 绘制Bitmap void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) 绘制从指定点获取的部分块void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) 在指定点绘制Bitmapvoid drawCircle(float cx, float cy, float rad
13、ius, Paint paint) 绘制一个圆在指定点void drawColor(int color) 填充canvas的颜色为colorvoid drawLine(float startX, float startY, float stopX, float stopY, Paint paint) 绘制线条void drawLines(float pts, Paint paint) 绘制一组线void drawLines(float pts, int offset, int count, Paint paint) 绘制一组线void drawOval(RectF oval, Paint pa
14、int) 绘制椭圆void drawPath(Path path, Paint paint) 沿着指定Path绘制任意形状void drawPoint(float x, float y, Paint paint) 绘制点void drawPoints(float pts, int offset, int count, Paint paint) 绘制多个点void drawPoints(float pts, Paint paint) 绘制多个点void drawRect(float left, float top, float right, float bottom, Paint paint)
15、绘制矩形框void drawRect(RectF rect, Paint paint) 绘制矩形框void drawRect(Rect r, Paint paint) 绘制矩形框void drawRoundRect(RectF rect, float rx, float ry, Paint paint) 绘制圆角矩形框void drawText(String text, float x, float y, Paint paint) 绘制字符串void drawText(String text, int start, int end, float x, float y, Paint paint)
16、 绘制字符串void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) 沿着指定的path路径绘制字符串final Rect getClipBounds() 获取到剪切矩形boolean getClipBounds(Rect bounds) 获取到剪切矩形,如果没有返回falseint getHeight() 获取到canvas高度int getWidth() 获取到canvas宽度boolean clipRect(int left, int top, int right, int
17、 bottom) 剪切一个矩形区域boolean clipRect(float left, float top, float right, float bottom) 剪切一个矩形区域boolean clipRect(RectF rect) 剪切一个矩形区域boolean clipRect(Rect rect) 剪切一个矩形区域void rotate(float degrees) 对canvas进行旋转void restore() 取出当前画布保存的状态与save方法匹配使用void scale(float sx, float sy) 对canvas进行缩放int save() 保存当前的画布
18、状态void translate(float dx, float dy) 移动canvas,设置canvas的相对坐标4.2.2 Paint类 从Canvas的绘制方法可以看到,所有的绘制方法都需要一个Paint参数,Paint是Canvas上的画笔,Paint主要用于设置绘制的一些属性,比如画笔的颜色,画笔的笔触粗细,填充的风格等。 如下是Paint类中的常用方法。 void setARGB(int a, int r, int g, int b) 设置画笔颜色void setAlpha(int a) 设置画笔透明度void setAntiAlias(boolean aa) 设置是否抗锯齿vo
19、id setColor(int color) 设置颜色void setFlags(int flags) 设置标记PathEffect setPathEffect(PathEffect effect) 设置绘制路径时的路径效果Shader setShader(Shader shader) 设置画笔的填充效果void setShadowLayer(float radius, float dx, float dy, int color) 色织阴影void setStrokeWidth(float width) 设置画笔的笔触宽度void setStyle(Paint.Style style) 设置填
20、充样式void setTextAlign(Paint.Align align) 设置文本的对齐方式void setTextSize(float textSize) 设置字体大小void setUnderlineText(boolean underlineText) 设置是否绘制文本是添加下划线4.2.3 绘制实例上面介绍了Android中的各种绘制,本节中我们通过实例来具体了解绘制过程。1. 创建一个名为TestCanvas的项目。2. 将要绘制的图片资源拷贝到res当中drawable路径中。3. 打开string.xml文件设置要绘制的字符串,如下。4. 新建一个类继承View,实现onD
21、raw方法如下。5. 在Activity类中显示MyView对象,如下。6. 最后运行显示结果如下图。4.3 View与 SurfaceView前面的介绍中绘图主要使用的是View组件,但实际的游戏开发中,我们一般使用的都是SurfaceView,使用SurfaceView的原因是因为View当中没有双缓冲的机制,当程序需要更新View上的图像时,程序必须重绘View上显示的整张图片,所以通过自定义View来实现绘图尤其是游戏中的绘图效率并不高,而使用Android当中提供的SurfaceView来进行游戏的绘制比View更加出色,所以一般推荐使用SurfaceView,SurfaceView
22、是从View基类中派生出来的显示类,所以View当中所有的SurfaceView当中也有。SurfaceView可以控制表面的格式,比如大小,显示在屏幕中的位置,最关键是的提供了SurfaceHolder类,使用getHolder方法获取,相关的有Canvas lockCanvas()、Canvas lockCanvas(Rect dirty) 、void removeCallback(SurfaceHolder.Callback callback)、void unlockCanvasAndPost(Canvas canvas) 控制图形以及绘制,而在SurfaceHolder.Callbac
23、k 接口回调中可以通过重写下面方法实现。使用的SurfaceView的时候,一般情况下要对其进行创建,销毁,改变时的情况进行监视,这就要用到 SurfaceHolder.Callback。 class xView extends SurfaceView implements SurfaceHolder.Callback /在surface的大小发生改变时激发 public void surfaceChanged(SurfaceHolder holder,int format,int width,int height) /在创建时激发,一般在这里调用画图的线程。public void surfa
24、ceCreated(SurfaceHolder holder) /销毁时激发,一般在这里将画图的线程停止、释放。public void surfaceDestroyed(SurfaceHolder holder) 对于Surface相关的,Android底层还提供了GPU加速功能,所以一般实时性很强的应用中主要使用SurfaceView而不是直接从View构建,同时后来做android 3d OpenGL中的GLSurfaceView也是从该类实现。 SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更
25、新画面。 那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。 当使用surfaceView ,由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。 所以基于以上,根据游戏特点,一般分成两类。 1 .被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch
26、 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。 2.主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。 Android中的SurfaceView类就是双缓冲机制。因此,开发游戏时尽量使用SurfaceView而不要使用View,这样的话效率较高,而且SurfaceView的功能也更加完善。 考虑以上几点,所以一般选用SurfaceView 来进行游戏开发。 4.3.1 View以及
27、双缓冲实现View中常用的方法如下。onFinishInflate()用于被重写,此方法为回调方法,当应用从xml布局文件加载该组件并利用它构建界面之后被调用。onMeasure(int, int)用于被重写,检测View组件及它所包含的所有自组建的大小。onLayout(boolean, int, int, int, int)用于被重写,当该组件需要分配其自组件的位置、大小时,该方法就会被回调。onSizeChanged(int, int, int, int)用于被重写,当组件的大小被改变时回调。onDraw(Canvas)用于被重写,当该组件将要绘制它的内容时回调该方法进行绘制。onKey
28、Down(int, KeyEvent)用于被重写,当某个按键被按下时触发该方法。onKeyUp(int, KeyEvent)用于被重写,当松开某个按键时触发该方法。onTrackballEvent(MotionEvent)用于被重写,当触发轨迹球事件时触发该方法。onTouchEvent(MotionEvent)用于被重写,当发生触摸屏事件时触发该方法。onWindowFocusChanged(boolean)用于被重写,当该组件得到、失去焦点时触发该方法。onAttachedToWindow()用于被重写,当把该组件放入某个窗口时触发该方法。onDetachedFromWindow()用于被
29、重写,当把该组件从某个窗口上分离时触发该方法。onWindowVisibilityChanged(int)用于被重写,当包含该组件的窗口的可见性发生改变时触发该方法。invalidate(Rect dirty) 刷新指定区域的View,调用onDraw方法invalidate(int l, int t, int r, int b)刷新指定区域的View,调用onDraw方法invalidate() 刷新View,调用onDraw方法postInvalidate(int left, int top, int right, int bottom) 刷新指定区域的ViewpostInvalidate
30、() 刷新View 前面介绍过View中不包含双缓冲,下面通过简单的实例来看View当中如何实现双缓冲。1. 创建一个名为TestView的项目。2. 创建一个MyView的类继承View类,内容如下。3. 在Activity中设置显示MyView对象,如下。4. 运行如下图。从上述的例子代码中可以看出,双缓冲即先在内存中创建一幅图片,所有的绘制是绘制在该内存图片当中,在屏幕上的时候只负责显示内存当中图片,这样绘制显然优于从外部设备直接绘制到屏幕上的图片,同时可以减少屏幕闪烁等问题。接下来看一个View的应用实例,实现游戏的菜单。1. 创建一个名为TestMenu的项目。2. 将要使用的图片资
31、源导入到res的drawable当中。3. 实现一个MyView的类继承View,并实现代码如下。4. 在Activity中,显示MyView对象。5. 运行效果如下图。该案例当中用触屏时间来判断按下的是哪个菜单选项。4.3.2 SurfaceView中的绘制 SurfaceView是View的子类,但SurfaceView自带双缓冲,它一般与SurfaceHolder结合使用,SurfaceHolder用于向与之关联的SurfaceView上绘图,SurfaceView的getHolder()函数可以获取SurfaceHolder对象,SurfaceView就在SurfaceHolder对象
32、内。虽然SurfaceView保存了当前窗口的像素数据,但是在使用过程中是不直接和SurfaceView打交道的,由SurfaceHolder的Canvas lockCanvas()或则Canvas lockCanvas()函数来获取Canvas对象,通过在Canvas上绘制内容来修改SurfaceView中的数据。如果SurfaceView不可编辑或则尚未创建调用该函数会返回null,在 unlockCanvas() 和 lockCanvas()中SurfaceView的内容是不缓存的,所以需要完全重绘SurfaceView的内容,为了提高效率只重绘变化的部分则可以调用lockCanvas(
33、Rect rect)函数来指定一个rect区域,这样该区域外的内容会缓存起来。在调用lockCanvas函数获取Canvas后,SurfaceView会获取SurfaceView的一个同步锁直到调用unlockCanvasAndPost(Canvas canvas)函数才释放该锁,这里的同步机制保证在SurfaceView绘制过程中不会被改变。 SurfaceHolder提供的获取Canvas对象的方法。Canvas lockCanvas(Rect dirty) 锁定SurfaceView上的rect划分的区域,获取该SurfaceView的Canvas对象。Canvas lockCanvas
34、() 锁定整个SurfaceView对象,并获取该SurfaceView的Canvas对象。void unlockCanvasAndPost(Canvas canvas) 释放Canvas对象并提交绘制的图像内容。上面表格当中的第一个和第二个方法返回的都是Canvas对象,但第一个方法之将Rect所指定的区域提取出来进行更新,这种方式可以提高画面的更新速度,而最后一个方法,当调用之后该方法前的绘制内容还存储于缓冲之中,下一次lockCanvas的时候,该方法锁定的区域可能会遮挡住前面的内容,所以如果不想被遮挡,可以选择重新lockCanvas一次,而lock的区域为0,再释放,保证下次lock
35、的时候被遮挡。 实际的游戏开发当中,我们会为SurfaceHolder添加一个Callback的实例,SurfaceHolder.Callback当中提供了如下方法。void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 当一个SurfaceView的格式或者大小发生改变的时候回调该方法。void surfaceCreated(SurfaceHolder holder) 当surfaceView被创建时回调该方法。void surfaceDestroyed(SurfaceHolder holder
36、) 当SurfaceView要被销毁时回调该方法。 surfaceCreated(SurfaceHolder holder):当SurfaceView第一次创建后会立即调用该函数。程序可以在该函数中做些和绘制界面相关的初始化工作比如获取到屏幕的宽高等,一般情况下都是在另外的线程来绘制界面,所以不要在这个函数中绘制SurfaceView,而屏幕的宽高等初始化也只能在该方法或者该方法调用后方能初始化,因为当我们继承callback接口后,会重写它的surfaceChanged()、surfaceCreated()、surfaceDestroyed()方法,而这几个方法是在当surfaceCreated()被执行的时候,真正的view才被创建,所以如果在之前去获取那么获取到的值也就是0 ,是因为在surfaceCreated()方法执行以前执行,view没有的时候我屏幕宽高肯定是0。 下面通过实例了解如何在SurfaceView中进行绘制。1. 创建一个名为TestSurfaceView的项目。2. 将要绘制的图片资源导入到drawable当中。3. 创建一个MySurfaceView类继承SurfaceView并实现Runnable接口和CallBack接口,内容如下。4. 在Activity当中设置显示。5. 显示结
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 乐理考试题及答案小学
- 消防安全生产人考试题库及答案解析
- 矿山电工考试题及答案
- 课件显示不完整问题
- 教师招聘之《小学教师招聘》考前自测高频考点模拟试题及完整答案详解(典优)
- 课件时间修改
- 铝及铝合金熔铸工晋升考核试卷及答案
- 2025年中国纸浆模包装制品数据监测报告
- 轻冶沉降工技能操作考核试卷及答案
- 经济政治考试题及答案
- 成人高考专升本医学综合考试真题及答案
- 《小猪变形记》一年级
- 青海2023届高校毕业生就业报告出炉:医学和法学就业率最高
- 生理学 第九章 感觉器官的功能
- 急救车必备药品和物品 急救车物品药品管理
- GB/T 15065-2009电线电缆用黑色聚乙烯塑料
- 静脉血栓栓塞症预防与护理课件
- 西门子低压电器快速选型手册
- 养羊与羊病防治技术课件
- 蔬菜大棚项目计划书
- 医学资料品管圈十大步骤的运用
评论
0/150
提交评论