【Android游戏开发二十二】(图文详解)游戏中灵活实现动画播放!

简介:

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

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

    做过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现在没有更好的适合游戏的开发包;

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

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

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

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

 

   
   
  1.  变量:  
  2.  Bitmap bmp0,bmp1,bmp2;  
  3.  Bitmap[] bmp_array = new Bitmap[3];  
  4.  int bmpIndex;  
  5.    
  6. 初始化中:  
  7. bmp0 = BitmapFaxxxxxxxx;  
  8. bmp1 = BitmapFaxxxxxxxx;  
  9. bmp2 = BitmapFaxxxxxxxx;  
  10. bmp_array[0] =bmp0;  
  11. bmp_array[1] =bmp1;  
  12. bmp_array[2] =bmp2;  
  13.       
  14. 画布中://一直在刷新画布  
  15. canvas.drawBitmap(bmp_array[bmpIndex]);  
  16.      
  17. 逻辑中: //线程中一直在执行逻辑  
  18. bmpIndex++;  
  19. if(bmpIndex>=bmp_array.length)  
  20.    bmpIndex = 0

 

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

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

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

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

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

 

   
   
  1.  变量:  
  2.  Bitmap bmp0,bmp1,bmp2;  
  3.  Bitmap[] bmp_array = new Bitmap[3];  
  4.  int bmpIndex;  
  5.  int time;  
  6. 初始化中:  
  7. bmp0 = BitmapFaxxxxxxxx;  
  8. bmp1 = BitmapFaxxxxxxxx;  
  9. bmp2 = BitmapFaxxxxxxxx;  
  10. bmp_array[0] =bmp0;  
  11. bmp_array[1] =bmp1;  
  12. bmp_array[2] =bmp2;  
  13.       
  14. 画布中://一直在刷新画布  
  15. canvas.drawBitmap(bmp_array[bmpIndex]);  
  16.      
  17. 逻辑中: //线程中一直在执行逻辑  
  18. time++;  
  19. if(time%10==0){  
  20.   bmpIndex++;  
  21. }  
  22. if(bmpIndex>=bmp_array.length)  
  23.    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,但是关于细节代码当时没有做特别注释和说明,今天正好用在这里,为各位童鞋详解讲解下:

 先上段代码: 


  
  
  1. /**  
  2.  *@author Himi  
  3.  *   
  4.     //为了让童鞋们更容易理解,我这里是把图片分割出来,  
  5.     //分为上下左右四个人物方向的数组  
  6.     private int animation_up[] = { 3, 4, 5 };      
  7.     private int animation_down[] = { 0, 1, 2 };      
  8.     private int animation_left[] = { 6, 7, 8 };      
  9.     private int animation_right[] = { 9, 10, 11 };   
  10. public void draw() {      
  11.         canvas = sfh.lockCanvas();      
  12.         canvas.drawRect(0, 0, SW, SH, p);    
  13.         canvas.save();    
  14.         canvas.drawText("Himi", bmp_x-2, bmp_y-10, p2);      
  15.          //这里的clipRect是设置可视区域,记得要 canvas.save();   canvas.restore();  
  16.         //如果不懂请看【Android游戏开发之四】 ,这里我主要介绍canvas.clipRect()   
  17.         //以及canvas.drawBitmap()两个方法中的几个参数!  
  18.         canvas.clipRect(bmp_x, bmp_y, bmp_x + bmp.getWidth() / 13, bmp_y+bmp.getHeight());   
  19.         //bmp_x:图片的x坐标  
  20.         //bmp_y:图片的y坐标  
  21.         //bmp_x + bmp.getWidth() / 13 :图片的x坐标+每一帧的宽度  
  22.         //bmp_y+bmp.getHeight()  :图片的y坐标+每一帧的高度   
  23.         if (animation_init == animation_up) {      
  24.             canvas.drawBitmap(bmp, bmp_x - animation_up[frame_count] * (bmp.getWidth() / 13), bmp_y, p);   
  25.             //bmp:有很多帧在一起的这张图片(图1)  
  26.             //bmp_x - animation_up[frame_count] * (bmp.getWidth() / 13) :  
  27.             //图片的x坐标 - 每一帧的X坐标(这里看备注1)  
  28.             //bmp_y:图片的y坐标  
  29.             //p:画笔  
  30.         } else if (animation_init == animation_down) {      
  31.             canvas.drawBitmap(bmp, bmp_x - animation_down[frame_count] * (bmp.getWidth() / 13), bmp_y, p);      
  32.         } else if (animation_init == animation_left) {      
  33.             canvas.drawBitmap(bmp, bmp_x - animation_left[frame_count] * (bmp.getWidth() / 13), bmp_y, p);      
  34.         } else if (animation_init == animation_right) {      
  35.             canvas.drawBitmap(bmp, bmp_x - animation_right[frame_count] * (bmp.getWidth() / 13), bmp_y, p);      
  36.         }      
  37.         canvas.restore();  //备注3    
  38.         sfh.unlockCanvasAndPost(canvas);      
  39.     }      
  40.     public void cycle() {      
  41.         if (DOWN) {      
  42.             bmp_y += 5;      
  43.         } else if (UP) {      
  44.             bmp_y -5;      
  45.         } else if (LEFT) {      
  46.             bmp_x -5;      
  47.         } else if (RIGHT) {      
  48.             bmp_x += 5;      
  49.         }      
  50.         if (DOWN || UP || LEFT || RIGHT) {      
  51.             if (frame_count < 2) {      
  52.                 frame_count++;      
  53.             } else {      
  54.                 frame_count = 0;      
  55.             }      
  56.         }      
  57.         if (DOWN == false && UP == false && LEFT == false && RIGHT == false) {      
  58.             frame_count = 0;      
  59.         }      
  60.     }     
  61.     */  

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

大家先看下图:

 

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

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

 Thx everybody! 娃哈哈~










本文转自 xiaominghimi 51CTO博客,原文链接:http://blog.51cto.com/xiaominghimi/606930,如需转载请自行联系原作者
目录
相关文章
|
5月前
|
存储 缓存 Android开发
安卓Jetpack Compose+Kotlin, 使用ExoPlayer播放多个【远程url】音频,搭配Okhttp库进行下载和缓存,播放完随机播放下一首
这是一个Kotlin项目,使用Jetpack Compose和ExoPlayer框架开发Android应用,功能是播放远程URL音频列表。应用会检查本地缓存,如果文件存在且大小与远程文件一致则使用缓存,否则下载文件并播放。播放完成后或遇到异常,会随机播放下一首音频,并在播放前随机设置播放速度(0.9到1.2倍速)。代码包括ViewModel,负责音频管理和播放逻辑,以及UI层,包含播放和停止按钮。
|
3月前
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
79 2
基于Android P,自定义Android开机动画的方法
|
29天前
|
Android开发 UED
Android 中加载 Gif 动画
【10月更文挑战第20天】加载 Gif 动画是 Android 开发中的一项重要技能。通过使用第三方库或自定义实现,可以方便地在应用中展示生动的 Gif 动画。在实际应用中,需要根据具体情况进行合理选择和优化,以确保用户体验和性能的平衡。可以通过不断的实践和探索,进一步掌握在 Android 中加载 Gif 动画的技巧和方法,为开发高质量的 Android 应用提供支持。
|
5月前
|
存储 数据库 Android开发
安卓Jetpack Compose+Kotlin,支持从本地添加音频文件到播放列表,支持删除,使用ExoPlayer播放音乐
为了在UI界面添加用于添加和删除本地音乐文件的按钮,以及相关的播放功能,你需要实现以下几个步骤: 1. **集成用户选择本地音乐**:允许用户从设备中选择音乐文件。 2. **创建UI按钮**:在界面中创建添加和删除按钮。 3. **数据库功能**:使用Room数据库来存储音频文件信息。 4. **更新ViewModel**:处理添加、删除和播放音频文件的逻辑。 5. **UI实现**:在UI层支持添加、删除音乐以及播放功能。
|
3月前
|
Android开发
Android 利用MediaPlayer实现音乐播放
本文提供了一个简单的Android MediaPlayer音乐播放示例,包括创建PlayerActivity、配置AndroidManifest.xml和activity_player.xml布局,以及实现播放和暂停功能的代码。
27 0
Android 利用MediaPlayer实现音乐播放
|
3月前
|
编解码 网络协议 开发工具
Android平台如何实现多路低延迟RTSP|RTMP播放?
本文档详细介绍了大牛直播SDK在Android平台上实现RTSP与RTMP流媒体播放及录像功能的技术细节。早在2015年,SDK的第一版就已经支持了多实例播放,并且通过简单的实例封装就能轻松实现。文档中提供了代码示例,展示了如何开启播放、停止播放以及开始和停止录像等功能。此外,SDK还提供了丰富的配置选项,例如设置录像目录、文件大小限制、转码选项等。总结部分列出了该SDK的关键特性,包括但不限于高稳定性和低延迟的播放能力、多实例支持、事件回调、硬解码支持、网络状态监控以及复杂的网络环境处理等。这些功能使得SDK能够应对各种应用场景,特别是在对延迟和稳定性有极高要求的情况下表现优异。
|
3月前
|
编解码 网络协议 vr&ar
Android平台下VR头显如何低延迟播放4K以上超高分辨率RTSP|RTMP流
这段内容讲述了VR头显中实现高分辨率视频播放的技术背景与实现方法,并强调了其重要性。高分辨率对于提升VR体验至关重要,它能提供更清晰的画面、增强沉浸感、补偿透镜放大效应,并维持宽广视场角下的图像质量。文中提到的大牛直播SDK具备极低的延迟(200-400ms),支持多种协议与格式,并具有丰富的功能特性,如多实例播放、事件回调、视频及音频格式支持等。此外,提供了基于Unity的播放器示例代码,展示了如何配置播放参数并开始播放。最后,作者指出此类技术在远程控制、虚拟仿真等应用场景中的重要意义。
|
4月前
|
XML Android开发 数据格式
Android 中如何设置activity的启动动画,让它像dialog一样从底部往上出来
在 Android 中实现 Activity 的对话框式过渡动画:从底部滑入与从顶部滑出。需定义两个 XML 动画文件 `activity_slide_in.xml` 和 `activity_slide_out.xml`,分别控制 Activity 的进入与退出动画。使用 `overridePendingTransition` 方法在启动 (`startActivity`) 或结束 (`finish`) Activity 时应用这些动画。为了使前 Activity 保持静止,可定义 `no_animation.xml` 并在启动新 Activity 时仅设置新 Activity 的进入动画。
121 12
|
4月前
|
XML Android开发 UED
Android动画之共享元素动画简单实践
本文介绍Android共享元素动画, 实现两Activity间平滑过渡特定UI元素。通过设置`transitionName`属性和使用`ActivityOptions.makeSceneTransitionAnimation`启动目标Activity实现动画效果。可自定义过渡动画提升体验。
70 0
下一篇
无影云桌面