今天终于把主菜单做好了,虽然可能还有些小bug,不过在以后实现栏目功能的时候,应该都能处理好。
今天讲的是添加背景音乐和音效,做游戏怎么能没有声音呢,对不对。
一般添加声音是靠两种方法实现的。一种是MediaPlayer,一种是SoundPool。这两种方法的区别是MediaPlayer可以存储较大的音频文件,载入稍慢,不支持同时播放。而SoundPool只能存储较小的音频文件,载入较快,支持同时播放。这样就很显然了,MediaPlayer用来实现背景音乐,而SoundPool用来实现音效。
下面是我写的两个类,直接加到游戏中就可以用了,由于我开发的是小型的游戏,对声音处理的要求不高,更多的功能也没有写,不过基本功能都在了。
package my.Game.audio;
import java.io.IOException;
import com.threed.jpct.Logger;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
public class MyMusic {
protected static MediaPlayer mediaPlayer;
protected static boolean mustResume = false;
private static Activity act;
public MyMusic(Activity act){
mediaPlayer = new MediaPlayer();
MyMusic.act=act;
}
public static void prepareMediaPlayer(String file) {
if(mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
}
AssetFileDescriptor afd = null;
try {
afd = act.getAssets().openFd("sound/"+file+".ogg");
} catch (Exception e) {
e.printStackTrace();
Logger.log("Tried creating Music with missing asset ... " + file);
System.exit(0);
return;
}
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
afd.close();
} catch (IOException e) {
e.printStackTrace();
Logger.log("Error setting data source in Music.play, IO exception");
System.exit(0);
return;
} catch (IllegalStateException e) {
e.printStackTrace();
Logger.log("Error setting data source in Music.play, fail ...");
return;
}
try {
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
Logger.log("Error preparing MediaPlayer");
System.exit(0);
return;
}
}
public static void play(boolean loop) {
if(mediaPlayer == null) {
Logger.log("error:MediaPlayer hasn't prepared.");
return;
}
mediaPlayer.setLooping(loop);
mediaPlayer.start();
}
public static void stop() {
if(mediaPlayer == null) {
Logger.log("error:No mediaPlayer is playing.");
return;
}
mediaPlayer.stop();
}
public static void pause() {
if(mediaPlayer == null) {
Logger.log("error:No mediaPlayer is playing.");
return;
}
mediaPlayer.pause();
}
public static void start(){
if(mediaPlayer == null) {
Logger.log("error:No mediaPlayer is prepared.");
return;
}
mediaPlayer.start();
}
public static void onPause() {
if(mediaPlayer == null) {
Logger.log("error:No mediaPlayer is playing.");
return;
}
if(mediaPlayer.isPlaying()) {
mediaPlayer.pause();
mustResume = true;
}
}
public static void onResume() {
if(mediaPlayer == null) {
Logger.log("error:No mediaPlayer is playing.");
return;
}
if(mustResume) {
mediaPlayer.start();
mustResume = false;
}
}
public static MediaPlayer getMediaPlayer() {
return mediaPlayer;
}
}
对了有一点要注意了,我有用到JPCT这个引擎,所以想用的这些类的话需要把该引擎中的方法删掉,这并不影响其中功能的实现。
以上是自己写的类似于MediaPlayer功能的类,使用的方法与MediaPlayer相近。
首先要实例化一个对象,构造时要传入Activity对象,这样做主要是为了后面获取资源。
然后是准备,即
prepareMediaPlayer(String file)
这个用来加载音频文件的
afd = act.getAssets().openFd("sound/"+file+".ogg");
这个地方要改成你存放音频文件的文件夹和文件类型。
剩下的一些处理也不用管他了。
最后就是放音了
public static void play(boolean loop)
loop用来控制是否循环播放。
下面讲下SoundPool的方法。
首先要先认识什么是SoundPool,我个人理解就是一个声音池,你可以在里面放一定数量的音频,这些音频是用数字表示的,也就是他们都有一个ID,这个ID是1、2、3.。。。一直往上排的,然后这个SoundPool还提供播放、暂停等功能。下面是我写的两个类。
package my.Game.audio;
public class MySound {
protected int ID;
static public int volumn;
public MySound(int volumn){
ID=0;
MySound.volumn=volumn;
}
//播放音效,不循环//
public void play(){
MySoundPool.getInstance().soundPool.play(ID, volumn, volumn, 1, 0, 1f);
}
//释放音效资源/
public void unLoad(){
MySoundPool.getInstance().soundPool.unload(ID);
}
//设置音量///
public void setVolumn(int vol){
volumn=vol;
}
//获得音量//
public int getVolumn(){
return volumn;
}
}
这个类很简单吧,你可以认为他就是一个音频。然后把SoundPool里面的播放功能赋予它,这样更好理解。
package my.Game.audio;
import java.io.IOException;
import com.threed.jpct.Logger;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.media.AudioManager;
import android.media.SoundPool;
import android.util.Log;
public class MySoundPool {
/最大存10音效资源///
private final int MaxNumOfSound=10;
private MySound[] soundArr=new MySound[MaxNumOfSound];
protected SoundPool soundPool;
private int top=-1; ///soundArr栈顶指针
static private MySoundPool Instance;
public MySoundPool(){
MySoundPool.Instance=this;
//最多4个音效同时播放,0为音质,该参数无效
soundPool=new SoundPool(4,AudioManager.STREAM_MUSIC, 0);
}
/getInstance常见用法,^_^//
static public MySoundPool getInstance(){
return Instance;
}
//生成音效资源,需要用SoundPool来加载
public MySound create(Resources res,String filename) {
MySound sound=new MySound(MySound.volumn);
AssetFileDescriptor afd = null;
try {
afd=res.getAssets().openFd("sound/"+filename+".ogg");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
Logger.log("error:Load soundfile with failing assets");
}
sound.ID=MySoundPool.getInstance().soundPool.load(afd,1);
Log.v("SoundID","SoundID="+sound.ID);
/load的第二个参数0代表优先级,现在是无效的//
addSound(sound);
return sound;
}
添加音效资源//
public void addSound(MySound sound){
top++;
soundArr[top]=sound;
if(top==MaxNumOfSound){
Logger.log("warning:SoundArray is already full");
}
}
释放音效资源//
public void releasePool(){
while(top!=-1){
soundArr[top].unLoad();
top--;
}
soundPool.release();
}
//清空soundPool///
public void emptyPool(){
while(top!=-1){
soundArr[top]=null;
top--;
}
}
}
这个就是类似于SoundPool的类了,不过他可以存放多个音频,即之前创建的MySound类的对象。
先讲下实现,再说使用方法。
soundPool=new SoundPool(4,AudioManager.STREAM_MUSIC, 0);
这个是实例一个SoundPool,方便其他类调用SoundPool中的方法,我们看到这个构造函数有3个参数,第一个是允许同时播放的音频数量,第二个是音频类型,第三个是音质,第三个参数现在还没有效果,是为了以后扩展用的。好像其他的也没啥好说的。
那讲下使用方法吧:
首先要创建一个MySoundPool对象,它用来管理你的所有的音频文件,这是一对多的关系,不要试图去创建多个SoundPool,很容易有问题的。
然后创建MySound对象
MySound(int volumn)
就是这个方法,参数是你想要的音量,当然这里为了实现对游戏音量的控制,所以把volumn设置为静态的,这样所有音效是同一个音量,另外值得说的是Android手机音量最大值是15,大家可以试一下。
然后用MySoundPool对象加载音频文件,将返回值赋给MySound对象,只有这样才能放音的
create(Resources res,String filename)
与MediaPlayer的prepare差不多了。不在解释了。
最后就是放音了
play()
这是在MySound类中实现的。其根源是
play(ID, volumn, volumn, 1, 0, 1f)
第一个参数就是你音频的ID,第二、三个参数是音量左右线,不懂有啥区别,也没试验过,又兴趣的朋友可以试验一下,第四个是优先级,现在是无效的,待扩展。第五个是是否循环,第六个是rate,不懂啥意思。
好了这样两个类,以后使用声音的时候就更加简单了。