本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi )

转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/361.html

由于写书的缘故,博文更新缓慢,大家体谅,今天针对群内常提出动画实现的问题来进行一个详细讲述;

此章节适合没有做过游戏开发的同学学习!

做过Android软件的童鞋们,在学习游戏开发的时候,思维总是被固定在了Android系统组件上!比如动画实现总想着利用BitmapDrawable、Animation等系统提供的类和方法来实现!

其实在本人以前做J2me开发的时候,J2me Api从MIDP2.0开始提供和封装了Sprite类,通名:精灵类!这个类的几种构造的时候只需要提供图片的大小、宽高、等,就可以生成一个精灵了,因为精灵类提供了碰撞检测、动画播放等方法,让开发者在开发游戏中很是方便。那么其实在制作一些较为复杂的、或者网游开发中,公司内都不会利用这个精灵类来去做,抛开机型不说,因为每个公司都会有其引擎和各种编辑器等等、那么肯定需要扩展,如果利用sprite来开发不仅扩展不方便、不灵活之外而且和编辑器、引擎搭配开发也不适合。但是一般而言,精灵类足够用!但是一般还是利用MIDP1.0自定义完成这个2.0提供的Spirte类,这样更容易维护和自定义扩展!

而且J2me提供的游戏开发包也是一个现成好用的引擎!所以这也可以理解为什么在Android游戏开发中,大家很多时候还总会看到Sprite类的影子!还有很多做过me的同学会看到类似的代码,总说“你这Android游戏开发不还是J2me的那套东西么!”,呵呵,没错,但是请童鞋们先想一下,Android现在SDK 升级到了2.3 了,有听说哪个版本中提供了类似meAPi中的“Game”专用于开发游戏的开发包?答案是肯定没有。而且能把自己在me中的游戏框架拿到android来,更快的进入开发也是很好的,当然这里不是推荐把j2me的那几个游戏扩展包直接拿来用,这种属于移植 – -。反而更加浪费游戏的效率!

总结一句:不是大家不想抛开me的架构来做原生态的Android游戏!而是Android现在没有更好的适合游戏的开发包;

不多说别的了,今天主要为各位童鞋讲解在游戏中如何实现动画!

实现动画,我们一般都是自己去利用图片数组、切片的变换形成的动画。那么下面给大家简单介绍两种实现方式:

第一种: 利用图片数组,不断改变画在画布上的图片数组下标,从而实现动画的形成!(每张图片是动画的一帧)

注意:下面这一段写的是演示代码!请自行整理;

变量:  Bitmap bmp0,bmp1,bmp2;  Bitmap[] bmp_array = new Bitmap[3];  int bmpIndex;  初始化中:
bmp0 = BitmapFaxxxxxxxx;
bmp1 = BitmapFaxxxxxxxx;
bmp2 = BitmapFaxxxxxxxx;
bmp_array[0] =bmp0;
bmp_array[1] =bmp1;
bmp_array[2] =bmp2;  画布中://一直在刷新画布
canvas.drawBitmap(bmp_array[bmpIndex]);  逻辑中: //线程中一直在执行逻辑
bmpIndex++;
if(bmpIndex>=bmp_array.length)  bmpIndex = 0;

逻辑中一直让bmpIndex++,为了让图片数组下标能向着下一张图片索引,这样一来在画布中,就形成了动画了。

有的童鞋说如何控制动画的播放速度呢?有的说改变线程的休眠时间!!?

游戏开发中一般都只要一个线程来控制,那么如果你为了控制动画的快慢而轻率的去改变线程的休眠时间,那就大错特错了。我们不应该去动主线程的刷新时间(休眠时间)而是想着去针对动画去想办法,这样别的地方不会受到影响!

一般情况下,刷新时间(线程休眠时间)很快,童鞋们肯定是嫌动画播放太快,那么我们可以自定义一个计时器。 比如我们定义一个变量去消耗掉一些时间!看以下代码:

此段代码仍然是演示代码,请注意自行整理;

变量:  Bitmap bmp0,bmp1,bmp2;  Bitmap[] bmp_array = new Bitmap[3];  int bmpIndex;  int time;
初始化中:
bmp0 = BitmapFaxxxxxxxx;
bmp1 = BitmapFaxxxxxxxx;
bmp2 = BitmapFaxxxxxxxx;
bmp_array[0] =bmp0;
bmp_array[1] =bmp1;
bmp_array[2] =bmp2;  画布中://一直在刷新画布
canvas.drawBitmap(bmp_array[bmpIndex]);  逻辑中: //线程中一直在执行逻辑
time++;
if(time%10==0){  bmpIndex++;
}
if(bmpIndex>=bmp_array.length)  bmpIndex = 0;

这段代码和之前那一段唯一的差别就是新增加了一个变量 time ,我们假定我们刷新时间(线程休眠时间)为 100毫秒,那么time++;

当if(time%10==0)成立的时候理论上肯定就是正好是一秒钟,【10(time)*100(线程休眠时间)=1000(正好1秒)】这样一来就OK,解决了!

第二种:利用切片来实现动画;(所有帧数都放在同一张图片中)

开发过游戏的肯定很熟悉下面这两张图:

图1 :

图2 :

图1,是个规则的帧数组成的一张图片,图2则是动作编辑器生成的图片。

游戏中一般常用的是规则的如图1一样的图片,这样的图片比我们第一种实现动画的方式为内存剩下了不少,那么图2由动作编辑器生成的当然更省! 这里针对图2这个我就先不多讲了。因为关联到编辑器等、大家可以自行百度下;

我们来看图1,如果经常看我博客的会发现图1很熟悉,嘿嘿,对的,这个是《【Android游戏开发之四】Android简单游戏框架》中一个人物行走的demo,第四章我讲解的是一个人物行走的demo,但是关于细节代码当时没有做特别注释和说明,今天正好用在这里,为各位童鞋详解讲解下:

先上段代码:

/** *@author Himi *  //为了让童鞋们更容易理解,我这里是把图片分割出来, //分为上下左右四个人物方向的数组 private int animation_up[] = { 3, 4, 5 };     private int animation_down[] = { 0, 1, 2 };     private int animation_left[] = { 6, 7, 8 };     private int animation_right[] = { 9, 10, 11 };
public void draw() {     canvas = sfh.lockCanvas();     canvas.drawRect(0, 0, SW, SH, p);   canvas.save();   canvas.drawText("Himi", bmp_x-2, bmp_y-10, p2);     //这里的clipRect是设置可视区域,记得要 canvas.save();   canvas.restore(); //如果不懂请看【Android游戏开发之四】 ,这里我主要介绍canvas.clipRect()  //以及canvas.drawBitmap()两个方法中的几个参数! canvas.clipRect(bmp_x, bmp_y, bmp_x + bmp.getWidth() / 13, bmp_y+bmp.getHeight());  //bmp_x:图片的x坐标 //bmp_y:图片的y坐标 //bmp_x + bmp.getWidth() / 13 :图片的x坐标+每一帧的宽度 //bmp_y+bmp.getHeight()  :图片的y坐标+每一帧的高度  if (animation_init == animation_up) {     canvas.drawBitmap(bmp, bmp_x - animation_up[frame_count] * (bmp.getWidth() / 13), bmp_y, p);  //bmp:有很多帧在一起的这张图片(图1) //bmp_x - animation_up[frame_count] * (bmp.getWidth() / 13) : //图片的x坐标 - 每一帧的X坐标(这里看备注1) //bmp_y:图片的y坐标 //p:画笔 } else if (animation_init == animation_down) {     canvas.drawBitmap(bmp, bmp_x - animation_down[frame_count] * (bmp.getWidth() / 13), bmp_y, p);     } else if (animation_init == animation_left) {     canvas.drawBitmap(bmp, bmp_x - animation_left[frame_count] * (bmp.getWidth() / 13), bmp_y, p);     } else if (animation_init == animation_right) {     canvas.drawBitmap(bmp, bmp_x - animation_right[frame_count] * (bmp.getWidth() / 13), bmp_y, p);     }     canvas.restore();  //备注3   sfh.unlockCanvasAndPost(canvas);     }     public void cycle() {     if (DOWN) {     bmp_y += 5;     } else if (UP) {     bmp_y -= 5;     } else if (LEFT) {     bmp_x -= 5;     } else if (RIGHT) {     bmp_x += 5;     }     if (DOWN || UP || LEFT || RIGHT) {     if (frame_count < 2) {     frame_count++;     } else {     frame_count = 0;     }     }     if (DOWN == false && UP == false && LEFT == false && RIGHT == false) {     frame_count = 0;     }     }    */

备注1:解释为什么要 “图片的x坐标 – 每一帧的X坐标”:

大家先看下图:

假设:我们现在把可视区域设定在(0,0)点,可是区域大小正好是图片每一帧的宽高;那么此时我们先在可视区域中显示下标为0的帧,我们只要把整张图片画在(0,0)即可,如上图中画的一样,现在只有第一帧能看到,那么我们如果想看第二张呢?当然是用图片的x坐标 – 每一帧的X坐标,就能看到下标为1的这一帧!如下图;

OK,这里我要强调一下:一定要理解这种思路,因为我们这里图1的高正好是每帧的高,可能以后有高宽都不一样!所以这里我在向大家介绍这种思路,千万要学以致用!!!OK,今天就讲到这,继续忙着写书啦。谢谢大家一直的支持!

Thx everybody! 娃哈哈~

【Android游戏开发二十二】(图文详解)游戏中灵活实现动画播放!简述J2me的游戏类库与Android游戏开发!相关推荐

  1. qt on android qml,Qt on Android: Qt Quick 之 Hello World 图文详解

    在上一篇文章,<Qt on Android:QML 语言基础>中,我们介绍了 QML 语言的语法,在最后我们遗留了一些问题没有展开,这篇呢,我们就正式开始撰写 Qt Quick 程序,而那 ...

  2. php中继承过来的类初始化顺序,java_图文详解Java中class的初始化顺序,class的装载 在讲class的初始化 - phpStudy...

    图文详解Java中class的初始化顺序 class的装载 在讲class的初始化之前,我们来讲解下class的装载顺序. 以下摘自<Thinking in Java 4> 由于Java ...

  3. 前端中全部盒子靠左对齐_图文详解ul中li内容垂直居中和水平居中的方法

    在页面布局时,经常会用到li标签,它可用于列表,导航,选项卡等等,那你知道如何让ul中的li居中吗?这篇文章就和大家讲讲如何让ul中的li水平居中以及如何让li内容垂直居中.感兴趣的朋友继续往下看吧. ...

  4. 图文详解Unity3D中Material的Tiling和Offset是怎么回事

    图文详解Unity3D中Material的Tiling和Offset是怎么回事 Tiling和Offset概述 Tiling表示UV坐标的缩放倍数,Offset表示UV坐标的起始位置. 这样说当然是隔 ...

  5. 面渣逆袭:Redis连环五十二问,图文详解,这下面试稳了

    大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis--不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的NoSQL数据库. ...

  6. C++语法学习笔记二十九: 详解decltype含义,decltype主要用途

    实例代码 // 详解decltype含义,decltype主要用途#include <iostream> #include <functional> #include < ...

  7. 系统学习NLP(二十四)--详解Transformer (Attention Is All You Need)

    转自:https://zhuanlan.zhihu.com/p/48508221 推荐:http://jalammar.github.io/illustrated-transformer/ 前言 注意 ...

  8. LoRa节点开发:5、代码详解LoRaWAN中的几种数据包(发送与接收数据)

    本文来源微信公众号[物联网思考] 本文主要结合LoRaNode SDK v4.4.2和LoRaWAN规范1.0.3来展开. 1.数据包类型 LoRaWAN规范中有不同的数据包,通过MType字段区分, ...

  9. 图文详解jvm中的线程状态

    本文使用下面这张图详细介绍JAVA线程的六种状态 JAVA线程的六种状态详解 在java.lang.Thread类中,定义了线程的以下六种状态(同一个时刻线程只能有一种状态)  NEW(新建) 这个状 ...

最新文章

  1. Java爬虫--json数据处理:JSONObject的使用
  2. qemu-kvm部分流程/源代码分析
  3. Web前端学习-第三课JavaScript篇
  4. logo下方显示技术支持信息_艺术与实用性的结合,iQunix Spider 屏幕显示器支架评测...
  5. 中加减乘除_【泓泰花园】精雕细琢的好房子,加减乘除里都是幸福
  6. 成功解决ValueError: cannot assign without a target object
  7. xp计算机知识点,全国职称计算机考试Windowsxp知识点
  8. c#sort升序还是降序_c# List的sort排序方法详解
  9. [改善Java代码]若有必要,使用变长数组
  10. 【Flink】Flink 源码之Buffer Debloating
  11. VS2010 工具箱组件添加重复
  12. 安卓ttf格式的字体包_字体 | 新游黑体(游)精巧的日系字体~
  13. NVIDIA Jetson之OTA远程升级Jetpack
  14. C/C++项目:谁都爱玩的4399小游戏黄金矿工教程
  15. 易共享android工具下载,EasyShare app
  16. Swift获取当前连接WIFI名称,IOS获取当前连接WIFI名称
  17. 高级软件工程师必备的五大技能
  18. 本周总结:为图片标签<img>加上 alt属性的好处
  19. 面试题:两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
  20. 专题教程——选队长游戏

热门文章

  1. Logistic 损失函数
  2. Archlinux安装xfce4桌面及美化流程
  3. virtio,vhost 和vhost-user
  4. 小米支付SDK接入注意事项
  5. python入门教程廖雪峰-Python教程
  6. Java 17的这些新特性不看后悔
  7. 使用gftp将ubuntu生成的可执行文件copy到开发板
  8. wifi常用的调制技术
  9. 为什么花大钱买来的BI还不如免费的Excel
  10. python类特列方法使用