转眼间就2015年了,时间过得真快,基本在找资料的时候很多都在CSDN的博客里找到。现在,也自己开始写了,希望自己能在这条路上坚持下去吧。

一开始是看着老师的视频一点点打的,整个看完了以后,整理了一下思路,重新自己打了一遍,也是遇到了很多的问题,看似是理解了,但是实际操作起来还是有很多的问题,最后还是完成了。老师写的只算是 个半成品,还有许多地方可以完善,这篇文章先写下来,趁热打铁嘛,这样自己以后也方便温习。然后一些知识点,都是我学到的,都加了淡色背景,可能排版还是有点糟,就先这样吧。

首先,先把工程下的几个包列一下

XXX为工程包名

      XXX.entity   这个包用来放所有的实体集合

XXX.global 这个包用来放所有的静态全局变量

XXX.model这个包用来放父类(用于实体的extends)和一些接口

XXX.tools    这个包用来放图像处理类的工具

XXX.view     这个包用来放视图类的文件

先在.view包下新建GameView,让其extends   SurfaceView,实现接口SurfaceHolder.Callbak和Runnable

关于SurfaceView

一、什么是SurfaceView?

可以直接从内存或者DMA等硬件接口取得图像数据,是个非常重要的绘图容器。它的特性是:可以在主线程之外的线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。

二、SurfaceView和其他View的区别?

SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。可以理解为Surfaceview的更新不需要在主线程中进行,这样就可以避免主线程来做大量的界面更新操作,引起ANR(主线程的界面更新的消息队列当中存在大量的更新界面请求)。

三、SurfaceView的使用

首先继承SurfaceView并实现SurfaceHolder.Callback接口使用接口的原因:因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始,而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。

上面提到了SurfaceHolder这个类

关于SurfaceHolder

可以把SurfaceHolder当成surface的控制器,用来操纵surface。处理它的Canvas上画的效果和动画,控制表面,大小,像素等。几个需要注意的方法:

(1)、abstract void addCallback(SurfaceHolder.Callback callback);
// 给SurfaceView当前的持有者一个回调对象。

(2)、abstract Canvas lockCanvas();
// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了

(3)、abstract Canvas lockCanvas(Rect dirty);
// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。

// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。

(4)、abstract void unlockCanvasAndPost(Canvas canvas);
// 结束锁定画图,并提交改变。

四、Surfaceview 的生命周期

在SurfaceView的派生类中,使用getHolder方法来获取SurfaceHolder对象。同时还需要addCallback方法来添加回 调函数。
surfaceChanged :在surfaceview的大小发生改变的时候调用。
surfaceCreated  : 在创建Surface时激发。
surfacedestroyed:在销毁Surface时激发。

以上,是我找到的一些帮助理解的资料,因为之前没有接触过SurfaceView,不过我觉得吧。根据Android里的消息队列的处理机制,还是能找相似处的。其实,SurfaceView就可以看成是一个绘图类的线程(因为有run()方法),但是他是VIP级别的,所以不需要遵循Handler   Message的机制,即队列机制,就是不需要排队。(纯属个人理解)

这边给个链接,是之前看的关于handler的处理机制的一篇文章,写的挺好的,网址如下:

http://www.cnblogs.com/codingmyworld/archive/2011/09/14/2174255.html

先定义画笔,画布,以及surfaceHolder还有上下文环境context

再定义一个boolean型的游戏运行标志

<span style="font-size:18px;"><span style="white-space:pre">   </span>private Canvas canvas;private Paint paint;private SurfaceHolder surfaceHolder;private Context mContext;private boolean gameRunFlag;</span>

在构造方法里,配置好

<span style="font-size:18px;">public GameView(Context context) {super(context);this.mContext = context;paint = new Paint();surfaceHolder = getHolder();surfaceHolder.addCallback(this);gameView = this;gameRunFlag = true;}</span>

在run()方法里,先判断游戏是否运行,加上同步锁synchronized

用一个try   catch  finally结构,记得之前提到的,先给画布上锁,画完了,再解锁

还有就是每次执行,给个休眠

<span style="font-size:18px;">public void run() {while (gameRunFlag) {synchronized (surfaceHolder) {try {canvas = surfaceHolder.lockCanvas();} catch (Exception e) {} finally {surfaceHolder.unlockCanvasAndPost(canvas);}}try {Thread.sleep(50);} catch (Exception e) {}}}</span>

用finally的理由是,不管是否出现异常,你必须给画布解锁(总不能因为你出问题了就不解锁了吧)

关于Synchronized

synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法,有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,直接运行。它包括两种用法:synchronized 方法和 synchronized 块。

synchronized 方法
1.方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时,线程获得的是成员锁,即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入.
例如:
public synchronized void synMethod(){
  //方法体
  }
2.对某一代码块使用,synchronized后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块.此时,线程获得的是成员锁.例如:
public int synMethod(int a1){
  synchronized(a1){
  //一次只能有一个线程进入
  }
很明显,这边用的是第二种方法,以前自己写了一个倒计时的东西,启动的时候,因为没用这个东西,多点了,倒计时跑的飞起。当然,这里,很自然的,传入的自然是总控制surfaceHolder。
这时候,回到MainActivity,定义新的GameView类,实例化后,将布局设为GameBView的实例。并补上一个init()方法,这个是之后用来配置图片资源的。
<span style="font-size:18px;">private GameView gameview;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);gameview = new GameView(this);init();setContentView(gameview);}private void init() {}
</span>

然后,在Mainfest文件里,修改MainActivity的主题以及屏幕方向为

<span style="font-size:18px;"><span style="font-size:18px;">android:screenOrientation="landscape"android:theme="@android:style/Theme.NoTitleBar.Fullscreen"</span></span>

接下来,在XXX.tools包下新建DeviceTools类,该类主要用来获得屏幕的信息,以及变换图片

里面写入3个方面
<span style="font-size:18px;"><span style="font-size:18px;">public static Bitmap resizeBitmap(Bitmap bitmap)public static Bitmap resizeBitmap(Bitmap bitmap, int w, int h)public static int[] getDeviceInfo(Context context)</span></span>

涉及到方法的重载,一个根据已定好的缩放比来处理图片,一个是按自定义的缩放比来处理图片,还有一个是获取设备的屏幕参数。一个个说吧,先定义一个int[2]的数组,分别获得宽,高放入数组中。

<span style="font-size:18px;">public static int[] getDeviceInfo(Context context) {if (DeviceWidthHeight[0] == 0 && DeviceWidthHeight[1] == 0) {DisplayMetrics metrics = new DisplayMetrics();((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metrics);DeviceWidthHeight[0] = metrics.widthPixels;DeviceWidthHeight[1] = metrics.heightPixels;}return DeviceWidthHeight;}</span>

关于DisplayMetrics

这位老兄给的资料很给力
http://blog.csdn.net/zhangqijie001/article/details/5894872
然后,简单的理解一下,就是DisplayMetrics给的是一些显示用的通用信息。
<span style="font-size:18px;"><span style="background-color: rgb(255, 204, 255);">DisplayMetrics metrics = new DisplayMetrics();((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metrics);</span></span>

通过这几句话就可以获得绝对像素(pixels)

再说resizeBitmap方法

<span style="font-size:18px;">public static Bitmap resizeBitmap(Bitmap bitmap) {if (bitmap != null) {int width = bitmap.getWidth();int height = bitmap.getHeight();Matrix matrix = new Matrix();matrix.preScale(Config.scaleWidth, Config.scaleHeight);Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width,height, matrix, true);return resizedBitmap;} else {return null;}}</span>

首先,记得在XXX.global包下新建Config类,里面用来存放所有的静态全局变量(这之后提到定义Config.XXX即是先定义再用)    这个方法就是先获得传入 图片的宽,高。通过矩阵Matrix变换,通过定义好的缩放比(scale)来完成变换。最后新建一个bitmap,通过createBitmap方法将其变换好的导进去。这边有个要注意的

第7个参数filter只有在仅有translation时设为false(这个我根据Eclipse提供的英文自己翻译的,仅供参考)
关于Matrix
这篇文档关于,Matrix的变换讲的比较详细
http://www.360doc.com/content/11/1215/11/7635_172396706.shtml
简单的说一下呢,就是3个主要方法(9种搭配)
(set,pre,post)+(Scale,Traslate,Rotate)
第二个括号内对应的分别是(大小还变,平移变换,旋转变换),前两个传入两个参数(宽,高)
第一个括号内对应的呢,一开始我没搞明白,查了一些资料,大致了解了一下。

后调用的pre操作先执行,而后调用的post操作则后执行。set方法一旦调用即会清空之前matrix中的所有变换。

这里不作过多深入研究,了解一下就好。

另一个resizeBitmap类似,只不过,这个变换的参数不是在Config里配置的,而是自己传入,width和height来计算出的,方法具体如下:

<span style="font-size:18px;">public static Bitmap resizeBitmap(Bitmap bitmap, int w, int h) {if (bitmap != null) {int width = bitmap.getWidth();int height = bitmap.getHeight();int newWidth = w;int newHeight = h;float scaleWidth = (float) newWidth / width;float scaleHeight = (float) newHeight / height;Matrix matrix = new Matrix();matrix.preScale(scaleWidth, scaleHeight);Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width,height, matrix, true);return resizedBitmap;} else {return null;}}</span>

接下来,回到MainActivity,在init()方法里,通过之前获得的屏幕宽,高和背景图片比对,来计算缩放比(记得在Config里配置好需要的全局静态参量)

例:public static int DeviceWidth;

<span style="font-size:18px;">Config.DeviceWidth = DeviceTools.getDeviceInfo(this)[0];Config.DeviceHeight = DeviceTools.getDeviceInfo(this)[1];Config.bkGround = BitmapFactory.decodeResource(getResources(),R.drawable.bk);Config.scaleWidth = Config.DeviceWidth/ (float) Config.bkGround.getWidth();Config.scaleHeight = Config.DeviceHeight/ (float) Config.bkGround.getHeight();</span>

计算完毕了,接下来就可以配置图片了(这边相当于配置相当于肉腌好,等会儿画相当于炒菜,原谅喜欢烹饪的我拿这个作比方)

<span style="font-size:18px;">Config.bkGround = DeviceTools.resizeBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.bk));</span>

这边获得Bitmap对象,一定要用BitmapFactory的decodeResource来解析图像资源,才能得到

肉腌好了,可以炒了,哈哈

回到GameView,在run()里,写上canvas.drawBitmap(Config.bkGround, 0, 0, paint);

这里0,0是因为背景图片嘛。再定义两个方法 ondraw(用于添加具体的有生命的实体)   updataData(用于判定有生命的实体的死亡)再以同样的方法,画上seedbank(那个放植物卡片的棕色栏)

canvas.drawBitmap(Config.seedBank, Config.sunDisapperX, 0,paint);

最后的run()如下:

<span style="font-size:18px;">public void run() {while (gameRunFlag) {synchronized (surfaceHolder) {try {canvas = surfaceHolder.lockCanvas();canvas.drawBitmap(Config.bkGround, 0, 0, paint);canvas.drawBitmap(Config.seedBank, Config.sunDisapperX, 0,paint);updataData();ondraw(canvas);} catch (Exception e) {// TODO: handle exception} finally {surfaceHolder.unlockCanvasAndPost(canvas);}}try {Thread.sleep(50);} catch (Exception e) {// TODO: handle exception}}}</span>

这里的Config.sunDisappearX需要计算一下,方便之后写阳光的运动。新建一个createElement方法(该方法主要是用来创建有生命的实体的)  在里面计算好Config.sunDisappearX

Config.sunDisapperX = (Config.DeviceWidth - Config.seedBank.getWidth()) / 2;

到此为止,所有的没有生命的背景都写好了,我休息一下,继续打字。

Android植物大战僵尸教程学习总结(一)相关推荐

  1. Android植物大战僵尸教程学习总结(三)

    植物都处理好了,那接下来先是阳光. 阳光,是由向日葵产生的.所以,我们回到Flower类.这边的话,跟之前的思考方式是一样的,不过加了一个时间的限定,毕竟,阳光产生要冷却的. private long ...

  2. Android植物大战僵尸附源码

    本文介绍cocos2d-android实现的Android植物大战僵尸,最后附源码 内容介绍: 一.游戏最原始的开发框架. 主要会介绍 a)  SurfaceView+SurfaceHolder.Ca ...

  3. 植物大战僵尸经典android,植物大战僵尸经典版

    植物大战僵尸经典版即植物大战僵尸最原始最经典的版本,也是玩家们最开始接触到的版本,在这个植物大战僵尸经典版中,所有的植物僵尸都是最开始的模样,一点都没有变,也不会像现在有着各种各样奇奇怪怪的植物和僵尸 ...

  4. C语言实现植物大战僵尸----学习过程

    大一下学期c语言课程设计要我们用c语言制作一款游戏,之前网上冲浪时候发现了c语言实现植物大战僵尸的教程,就想来跟着教程做一遍,并记录下自己的学习过程与经验. 前排分享我所学习的视频和文章: [可能是B ...

  5. 远程代码注入及DLL注入教程(InlineHook)---植物大战僵尸为例

    远程代码注入及DLL注入教程 说明 ​ 本人刚开始学习逆向,不知道有没有动力学下深去,这一块也没有详细的实战教学,学多少就上传多少,希望能给想学的朋友一点帮助吧,本教程想通过植物大战僵尸这一经典游戏来 ...

  6. 部分 CM11 系统 Android 平板执行植物大战僵尸 2 黑屏的解决的方法

    原文 http://forum.xda-developers.com/showthread.php?t=2755197 部分 CM11 系统的 Android 平板(比如三星 GT-P5110 )执行 ...

  7. 【转】Android Studio安装配置学习教程指南 Gradle基础--不错

    原文网址:http://www.linuxidc.com/Linux/2015-02/113890p4.htm 其实很早之前也写了一篇Gradle的基础博客,但是时间很久了,现在Gradle已经更新了 ...

  8. 学习逆向知识之用于游戏外挂的实现.第二讲,快速寻找植物大战僵尸阳光基址.以及动态基址跟静态基址的区别...

    通过游戏外挂,学习逆向技术之快速寻找植物大战僵尸阳光基址.以及动态基址跟静态基址的区别 一丶静态基址. 动态基址. 基址的区别 通过上一讲超级马里奥的游戏外挂技术制作.我们学习到了静态基址.以及观看内 ...

  9. 使用Python对植物大战僵尸学习研究

    根据上一篇 使用使用Python学习win32库进行内存读写 中,使用Python win32库,对一款游戏进行了读内存 操作. 今天来写一下对内存进行写的操作 正文 要进行32位的读写,首先了解一下 ...

最新文章

  1. Fiddler 获取、安装与浏览器代理设置,Fiddler的第一次使用
  2. 政策定价风控审批策略
  3. keytool安装tls证书_TLS使用指南(一):如何在Rancher 2.x中进行TLS终止?
  4. Nodejs学习事件模块
  5. 这次是真香了!iPhone 11一个月卖出1200万部 苹果加大产量
  6. ZH奶酪:自然语言处理工具LTP语言云调用方法
  7. 小程序入门学习19--springboot之HelloWorld
  8. FlashDevelop 3.0.0 Beta2 released
  9. VC双缓冲画图技术介绍
  10. 互联网支付系统整体架构详解
  11. windows 搭建kms服务器激活_搭建kms服务器,自建KMS激活服务器的两种方法
  12. 小型项目的微服务架构指南
  13. java研发手机归属地批量查询
  14. 小学听力测试英语软件,小学英语听力测试
  15. 使用ISO镜像制作适用于OpenStack的云镜像
  16. python调用谷歌地图api_python显示地图与谷歌地图
  17. 中国科学院计算机研究所上级单位,陈援非(中国科学院计算技术研究所高工)_百度百科...
  18. excel 2010 删除重复行(按某一列重复)
  19. Kafka KSQL安装
  20. ArduinoIDE + STM32Link烧录调试

热门文章

  1. 安卓修改大师v3.1.0.0:傻瓜式安卓反编译逆向修改工具
  2. 网吧无盘服务器游戏盘,网吧有盘无盘轻松自由切换
  3. 电脑编程用的是什么c语言吗,学电脑编程里的C语言什么意思
  4. 五轴数控转台_有人说先学会三轴,再去搞四轴、五轴加工中心,这几种机床有何区别呢?...
  5. 如何提取处理网页视频中的字幕
  6. HTML文件保存时关闭自动换行,如何禁止html自动换行
  7. 大厂对话系统实践文章链接
  8. JS逆向之Webpack(二)
  9. web前端-特殊背景自适应结构(上中下)
  10. 清理优化mac苹果磁盘空间的方法