andriod游戏音效

简介: 同学们在玩游戏的时候应该都会发现游戏中会有两种形式来播放音乐 ,一般设置选项中会明确标明 设置游戏音乐 与设置游戏音效。 客观的分析一下这两种形式的音乐,游戏背景音乐同时只会播放一首也就是说两首背景音乐不会同时播放,除非一首播放完毕或者切换场景等 才会播放下一首。而游戏音效 比如主角与敌人挥动武器的声音 被攻击中的声音等,这些声音比较短而且播放很频繁很有可能会同时播放游戏音效。1.使用Me

同学们在玩游戏的时候应该都会发现游戏中会有两种形式来播放音乐 ,一般设置选项中会明确标明 设置游戏音乐 与设置游戏音效。 客观的分析一下这两种形式的音乐,游戏背景音乐同时只会播放一首也就是说两首背景音乐不会同时播放,除非一首播放完毕或者切换场景等 才会播放下一首。而游戏音效 比如主角与敌人挥动武器的声音 被攻击中的声音等,这些声音比较短而且播放很频繁很有可能会同时播放游戏音效。

1.使用MediaPlayer播放游戏音乐


创建MediaPlayer对象 将Context与资源文件传入。 

 
 
  1. /**创建MediaPlayer对象**/  
  2.  MediaPlayer mMediaPlayer = MediaPlayer.create(mContext, R.raw.v3);  
  3.  /**设置为循环播放**/  
  4.  mMediaPlayer.setLooping(true); 

判断声音是否正在播放,如果没有播放则开始播放游戏音乐。 

 
 
  1. if(!mMediaPlayer.isPlaying()) {  
  2.     mMediaPlayer.start();  
 
判断声音是否正在播放,如果正在播放则停止播放游戏音乐。 
  
  
  1. /**关闭音乐**/  
  2. if(mMediaPlayer.isPlaying()) {  
  3.     mMediaPlayer.stop();  
这里强调一下MediaPlayer同一时间只能播放一个音乐

2.使用SoundPool播放游戏音效


Soundpool的加载:

int load(Context context, int resId, int priority) //从资源中载入 比如 R.raw.id
int load(FileDescriptor fd, long offset, long length, int priority) //从FileDescriptor 对象载入
int load(AssetFileDescriptor afd, int priority) //从AssetFileDescriptor 对象载入
int load(String path, int priority) //从完整文件路径名载入 第二个参数为优先级。

创建音效

 
  
  
  1. /**创建一个声音播放池**/  
  2. //参数1为声音池同时播放的流的最大数量   
  3. //参数2为播放流的类型  
  4. //参数3为音乐播放效果  
  5. mSoundPool = new SoundPool(2,AudioManager.STREAM_MUSIC,100);  
  6. //读取音效  
  7. mSound_0 = mSoundPool.load(mContext, R.raw.voic_p1, 0);  
  8. mSound_1 = mSoundPool.load(mContext, R.raw.voic_p1, 0); 
播放音效
play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
leftVolume 表示对左音量设置 rightVolume 表示右音量设置 , loop 表示 循环次数 rate表示速率最低0.5最高为2,1代表正常速度

 
  
  
  1. mSoundPool.play(mSound_0, 1, 1, 0, 0, 1); 
这里强调一下SoundPool可以同时播放多个音乐。

下面向大家介绍一下这个DEMO中的重点,太鼓达人游戏开发的原理,图片资源全部源于互联网。
进入游戏界面 使用MediaPlayer来播放背景声音, 玩家击打鼓盘使用soundpool播放游戏音效。配合这下面的DEMO 请大家继续阅读。

 
菜单界面 

游戏界面

1.处理触摸点与鼓盘的碰撞

我们先分析一下鼓盘的组成结构,它是由两个圆形组成的一个大圆形中间一个小圆形。玩家触摸屏幕后会拿到触摸的X,Y坐标 然后利用数学公事 (x1 – x2)2 + (y1 – y2)2 < (r1 + r2)2 计算出点与大圆形的距离与小圆形的距离,根据两点之间的距离就可以计算出当前触摸的点是在蓝色的鼓盘中 还是红色的鼓盘中,判断一下X坐标在圆形左边还是右边就可以拿到触摸的是左边的鼓盘还是右边的鼓盘。

检测碰撞的部分源代码
     
     
  1. private void Collision(int x, int y) {
  2. //在这里进行碰撞检测
  3. //检测的原理是点与圆形的碰撞
  4. //利用数学公事 (x1 – x2)2 + (y1 – y2)2 < (r1 + r2)2
  5. //判断点是在蓝盘中还是红盘中
  6. int Condition = ((x - mDrumCenterX) * (x - mDrumCenterX)) +((y - mDrumCenterY) * (y - mDrumCenterY)) ;
  7. int Result = mBlueRadius * mBlueRadius;
  8. if(Condition < Result) {
  9. int redResoult = mRedRadius*mRedRadius;
  10. if(Condition<redResoult) {
  11. //表明点在红盘区域
  12. if(x <mDrumCenterX) {
  13. //红盘左边
  14. mRedClipX = mDrumCenterX;
  15. mRedClipWidth = (mRed.getWidth() >> 1);
  16. mmDrumRedPosX = mDrumCenterX;
  17. mPonitState = POINT_RED_LEFT;
  18. }else {
  19. //红盘右边
  20. mRedClipX = 0;
  21. mRedClipWidth = (mRed.getWidth() >> 1);
  22. mmDrumRedPosX=0;
  23. mPonitState = POINT_RED_RIGHT;
  24. }
  25. }else {
  26. //表明点在蓝盘区域
  27. if(x <mDrumCenterX) {
  28. //蓝盘左边
  29. mBlueClipX = mDrumCenterX;
  30. mBlueClipWidth = (mBlue.getWidth() >> 1);
  31. mmDrumBluePosX = mDrumCenterX;
  32. mPonitState = POINT_BLUE_LEFT;
  33. }else {
  34. //蓝盘右边
  35. mBlueClipX = 0;
  36. mBlueClipWidth = (mBlue.getWidth() >> 1);
  37. mmDrumBluePosX=0;
  38. mPonitState = POINT_BLUE_RIGHT;
  39. }
  40. }
  41. CheckCollision();
  42. }
  43. }
  44. /**检测玩家击鼓是否碰撞**/
  45. private void CheckCollision() {
  46. Note mNoteTemp = null;
  47. for (int i = 0; i < NOTE_COUNT; i++) {
  48. // 利用绝对值的方式寻找一个大概击中的范围
  49. if (Math.abs(mNote[i].m_posX - mItemposX) <= mItemposW) {
  50. mNotemNoteTemp = mNote[i];
  51. }
  52. }
  53. boolean isCollision = false;
  54. if (mNoteTemp != null) {
  55. switch (mPonitState) {
  56. case POINT_RED_LEFT:
  57. case POINT_RED_RIGHT:
  58. if (mNoteTemp.getType() == Note.NOTE_STATE_RED) {
  59. //表明击中了红圆形
  60. isCollision = true;
  61. }
  62. break;
  63. case POINT_BLUE_LEFT:
  64. case POINT_BLUE_RIGHT:
  65. if (mNoteTemp.getType() == Note.NOTE_STATE_BLUE) {
  66. //表明击中了蓝圆形
  67. isCollision = true;
  68. }
  69. break;
  70. }
  71. }
  72. if(isCollision) {
  73. //设置状态 UI根据这个状态显示击打成功还是击打失败
  74. mCollisionState = COLLISION_GREAT;
  75. //播放游戏音效
  76. mSoundPool.play(mSound_0, 1, 1, 0, 0, 1);
  77. }else {
  78. mCollisionState = COLLISION_BAD;
  79. //播放游戏音效
  80. mSoundPool.play(mSound_1, 1, 1, 0, 0, 1);
  81. }
  82. }
2 .音符的移动

游戏中我们可以发现各种音符会从屏幕左边向右移动,我觉得原作肯定是有一个音符编辑器 在开发中策划来编辑这个音符包括 位置 出现的是频率 时间 音符的类型 等等 最后编辑器会把数据生成出来 在程序中去读取这些数据并显示出来,作为学习来说我们没必要想那么多我强调的还是开发的原理 任何平台的游戏它使用的算法 数据结构 基本都是一样的,今后我会在教程中陆续向大家贯穿这些思想。
代码实现上我把音符一样封成一个音符类,和上节教程类似每一个音符由又向左移动 根据随机数 来设置音符的类型 为红色还是蓝色。 程序中一样只申请了5块 音符的对象,玩家点击鼓盘后然后以音符对象检测它的XY坐标是是否在点击区域 如果在点点击区域 在判断玩家敲打的鼓盘音符与当前音符是否类型一样如果一样则表示击打成功 屏幕中显示good图片,如果失败则显示bad图片。被击中的鼓点 或者没有击中向左超过击打范围 直接重置它们的坐标 让它们进入下一个轮回判定中。

简单的音符类实现 现在只有两种音符 一个是红色 一个是蓝色

 
 
 
  1. public class Note {  
  2.  
  3.     /** 音符的X轴速度 **/  
  4.     static final int NOTE_STEP_X = 15;  
  5.       
  6.     /** 红色音符**/  
  7.     static final int NOTE_STATE_RED = 0;  
  8.       
  9.     /** 蓝色音符**/  
  10.     static final int NOTE_STATE_BLUE = 1;  
  11.  
  12.     /** 音符的XY坐标 **/  
  13.     public int m_posX = 0;  
  14.     public int m_posY = 0;  
  15.  
  16.       
  17.     /**音符类型**/  
  18.     private int mType = 0;  
  19.       
  20.     /** 音符的动画 **/  
  21.     private Animation mAnimation = null;  
  22.     Context mContext = null;  
  23.  
  24.     /**控制**/  
  25.     private boolean mFauce = false;  
  26.     public Note(Context context) {  
  27.     mContext = context;  
  28.     mFauce = false;  
  29.     }  
  30.       
  31.     /**重置音符**/  
  32.     public void initStart(Bitmap[] frameBitmap, int type,int x, int y) {  
  33.     mAnimation = new Animation(mContext, frameBitmap, true);  
  34.     mType = type;  
  35.     m_posX = x;  
  36.     m_posY = y;  
  37.     mFauce = true;  
  38.     }  
  39.  
  40.     /** 绘制音符 **/  
  41.     public void DrawNote(Canvas Canvas, Paint paint) {  
  42.     if (mFauce) {  
  43.         mAnimation.DrawAnimation(Canvas, paint, m_posX, m_posY);  
  44.     }  
  45.     }  
  46.  
  47.     /** 更新音符的坐标点 **/  
  48.     public void UpdateNote() {  
  49.     if (mFauce) {  
  50.         m_posX -NOTE_STEP_X;  
  51.     }  
  52.     }  
  53.       
  54.     //获得音符类型  
  55.     public int getType(){  
  56.     return mType;  
  57.     }  
  58.       
  59.     /**是否显示**/  
  60.     public void setFacus(boolean facus) {  
  61.     mFauce = facus;  
  62.     }  

玩家击打某个鼓盘后 瞬间鼓点图片会消失 然后在显示这样会让玩家感觉自己已经点中鼓盘。 这个效果可以根据clipRext来把图片切割出来显示在屏幕中。
 

 

 

 
 
  1. /** * 绘制图片中的一部分图片 *  
  2. * @param bitmap  
  3. * @param x  
  4. * @param y  
  5. * @param src_x  
  6. * @param src_y  
  7. * @param src_width  
  8. * @param src_Height  
  9. */  
  10. private void DrawClipImage(Bitmap bitmap, int x, int y, int src_x, int src_y, int src_xp, int src_yp) {  
  11.     mCanvas.save();  
  12.     mCanvas.clipRect(x, y, x + src_xp, y + src_yp);  
  13.     mCanvas.drawBitmap(bitmap, x - src_x, y - src_y, mPaint);  
  14.     mCanvas.restore();  

                           游戏效果图 

游戏的更新
 
   
   
  1. private void updateGame() {  
  2.     if (mPlayID < NOTE_COUNT) {  
  3.     Long now = System.currentTimeMillis();  
  4.     if (now - mStartTime >= START_TIME) {  
  5.         mStartTime =now;  
  6.         int random = UtilRandom(0, 2);  
  7.         int type = 0;  
  8.         if (random == 0) {  
  9.         type = Note.NOTE_STATE_RED;  
  10.         } else {  
  11.         type = Note.NOTE_STATE_BLUE;  
  12.         }  
  13.         mNote[mPlayID].initStart(  
  14.             new Bitmap[] { mNoteBitmap[random] }, type,  
  15.             mNotePosX, mNotePosY);  
  16.         mPlayID++;  
  17.     }  
  18.     } else {  
  19.     mPlayID = 0;  
  20.     }  
  21.       
  22.     for(int i =0 ; i <NOTE_COUNT; i ++) {  
  23.     mNote[i].UpdateNote();  
  24.     if(mNote[i].m_posX <= mItemposX) {  
  25.         mNote[i].setFacus(false);  
  26.     }  
  27.     }  
游戏的绘制

 
 
 
  1. public void renderGame() {  
  2.     /** 绘制游戏菜单 **/  
  3.     mCanvas.drawBitmap(mBitGameBG, 0, 0, mPaint);  
  4.       
  5.     /**绘制小人动画**/  
  6.     mNpcAnim.DrawAnimation(mCanvas, mPaint, mNpcPosX, mNpcPosY);  
  7.       
  8.     /**绘制鼓盘**/  
  9.     mCanvas.drawBitmap(mDrum, 0, mDrumPosY, mPaint);  
  10.      
  11.     /**蓝**/  
  12.     DrawClipImage(mBlue,mmDrumBluePosX,mmDrumEffectPosY,mBlueClipX,0,mBlueClipWidth,mBlueClipHeight);  
  13.       
  14.     /**红**/  
  15.     DrawClipImage(mRed,mmDrumRedPosX,mmDrumEffectPosY,mRedClipX,0,mRedClipWidth,mRedClipHeight);  
  16.    
  17.     /**击打区域**/  
  18.     mCanvas.drawBitmap(mBitGameItem, mItemposX, mItemposY, mPaint);  
  19.       
  20.     /**绘制音符**/  
  21.     for(int i =0 ; i <NOTE_COUNT; i ++) {  
  22.     mNote[i].DrawNote(mCanvas, mPaint);  
  23.     }  
  24.       
  25.     /**播放点击动画**/  
  26.     if(mCollisionState == COLLISION_GREAT ) {  
  27.     mCanvas.drawBitmap(mGreat, 0,0, mPaint);  
  28.     }else if(mCollisionState == COLLISION_BAD) {  
  29.     mCanvas.drawBitmap(mBad, 0,0, mPaint);  
  30.     }  
  31.     setDrumPoint();  
以后写教程每个demo的代码量会越来越多 所以贴代码在博客中可能大家看的就不是很清楚,不过我会尽量在博客中把原理说清楚 还是建议大家都去下载我的源码来阅读学习。源代码中我会写详细的注释,还是那句老话在漂亮的语言不如普通实用的代码片段,老规矩每篇文章都会附带源代码,最后如果你还是觉得我写的不够详细 看的不够爽 不要紧我把源代码的下载地址贴出来 欢迎大家一起讨论学习雨松MOMO希望可以和大家一起进步。
目录
相关文章
|
JSON 网络协议 Java
图文详解压力测试工具JMeter的安装与使用
压力测试是目前大型网站系统的设计和开发中不可或缺的环节,通常会和容量预估等工作结合在一起,穿插在系统开发的不同方案。压力测试可以帮助我们及时发现系统的性能短板和瓶颈问题,在这个基础在上再进行针对性的性能优化,也可以帮助我们预估系统的承载能力,使我们能根据其做出一些应对措施。
1906 0
图文详解压力测试工具JMeter的安装与使用
|
8月前
|
人工智能 API 开发者
用Qwen3+MCPs实现AI自动发布小红书笔记!支持图文和视频
魔搭自动发布小红书MCP,是魔搭开发者小伙伴实现的小红书笔记自动发布器,可以通过这个MCP自动完成小红书标题、内容和图片的发布。
2797 41
|
Java 关系型数据库 MySQL
Spring事务失效,我总结了这7个主要原因
本文详细探讨了Spring事务在日常开发中常见的七个失效原因,包括数据库不支持事务、类不受Spring管理、事务方法非public、异常被捕获、`rollbackFor`属性配置错误、方法内部调用事务方法及事务传播属性使用不当。通过具体示例和源码分析,帮助开发者更好地理解和应用Spring事务机制,避免线上事故。适合所有使用Spring进行业务开发的工程师参考。
360 2
|
机器学习/深度学习 自然语言处理 搜索推荐
智能语音交互:技术原理与应用前景####
【10月更文挑战第25天】 一句话概括本文主旨,并引发读者兴趣。 智能语音交互技术,作为人工智能领域的重要分支,正以前所未有的速度融入我们的生活,从简单的语音助手到复杂的多轮对话系统,它不仅重塑了人机交互的方式,还为多个行业带来了革命性的变化。本文将深入浅出地探讨智能语音交互的技术原理、当前主流技术路线、面临的挑战及未来发展趋势,为读者揭开这一高科技领域的神秘面纱。 ####
|
11月前
|
人工智能 运维 Cloud Native
【技术产品】DS三剑客:DeepSeek、DataSophon、DolphineSchduler浅析
在大数据与云原生技术快速发展的时代,开源技术成为推动行业进步的重要力量。本文深入探讨了三个备受瞩目的开源产品组件:DeepSeek、DataSophon 和 DolphinScheduler。DeepSeek 是专注于自然语言处理的大语言模型,具备多模态交互和高效推理功能;DataSophon 是大数据云原生平台的智能管家,提供快速部署和智能化运维;DolphinScheduler 则是分布式任务调度系统,支持复杂工作流的编排与执行。三者分别在大语言模型、大数据管理和任务调度领域展现了强大的技术实力,并通过技术互补共同推动AI与大数据技术的深度融合。
1386 2
【技术产品】DS三剑客:DeepSeek、DataSophon、DolphineSchduler浅析
|
11月前
|
JSON API 开发者
闲鱼商品详情API接口(闲鱼API系列)
闲鱼商品详情API为开发者提供便捷、高效且合规的途径,获取闲鱼平台上特定商品的详细信息,如标题、价格、描述和图片等。该接口采用GET请求方式,需传入app_key、item_id、timestamp和sign等参数,返回JSON格式数据。示例代码展示了如何使用Python调用此API,包括生成签名和处理响应。开发者需替换实际的app_key、app_secret和商品ID,并关注官方文档以确保接口使用的准确性。
3382 1
|
Docker 容器 文件存储
蓝易云 - 使用WSL修改docker文件存储位置
注意:你需要确保新的文件存储路径存在,且Docker有权限访问和写入。
494 3
|
人工智能 IDE 开发工具
给IntelliJ IDEA添加AI功能
这篇文章讲解了如何在IntelliJ IDEA中安装和使用阿里云开发的通义灵码插件,以增强IDE的人工智能辅助编程功能。
5323 0
给IntelliJ IDEA添加AI功能
|
消息中间件 分布式计算 负载均衡
软件体系结构 - 架构风格(6)进程通信架构风格
【4月更文挑战第21天】软件体系结构 - 架构风格(6)进程通信架构风格
473 0
|
运维 网络协议 Linux
【运维系列】Centos7安装并配置postfix服务
安装CentOS7的Postfix和Dovecot,配置Postfix的`main.cf`文件,包括修改完全域名、允许所有IP、启用邮箱等。然后,配置Dovecot的多个配置文件以启用auth服务和调整相关设置。重启Postfix和Dovecot,设置开机自启,并关闭防火墙进行测试。最后,创建邮箱账户并在Windows邮箱客户端中添加账户设置。
695 0

热门文章

最新文章