从零开始Android游戏编程(第二版) 第十二章 音乐与音效

第十二章 音乐与音效

广告说的好“没有声音再好的戏也出不来”,下面就让我们为程序加入声音效果。

一般情况下,游戏中的声音分为音乐和音效两个部分。直观上的区别,音乐播放的时间较长,资源文件较大。音效播放时间较短,资源文件比较小。在Android中,我们使用两种不同的方法播放音乐和音效。

播放音乐需要用到MediaPlayer类,MediaPlayer本身比较复杂,这里我们只做一个简单的介绍,满足播放音乐的基本要求即可,读者可以参考帮助文档中的内容深入研究。

为了调用方便,我们创建一个Util类,将播放背景音乐的方法封装到Util中

public class Util {

static MediaPlayer mp;

static void playBGM(String path, boolean looping) {

if(mp == null) {

mp = new MediaPlayer();

}

mp.reset();

try {

mp.setDataSource(path);

mp.prepare();

} catch (IllegalArgumentException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IllegalStateException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

mp.setLooping(looping);

mp.start();

}

}

让我们分析一下这段代码:首先,我们需要一个MediaPlayer实例,然后重置MediaPlayer到Idle状态。注意,这个操作是必需的,如果当前正在播放,不重置状态直接调用setDataSource会抛出异常。然后指定我们要播放的文件,并调用prepare方法进行准备。如果你想指定开始时间(seekTo)必须在prepare之后进行。还可以设定是否循环,最后就是调用start播放了。

封装好后,我们可以方便的使用这个函数,我们在SceneStartMenu中重载start方法

public void start(SurfaceHolder surfaceHolder){

Util.playBGM("/sdcard/sample.mid", false);

}

这样,程序运行后就开始播放音乐了。还要注意的是,我们应该在适当的时候释放MediaPlayer占用的资源。

运行一下编辑好的代码看看效果吧。sample.mid在res/raw目录下。

下面让我来学习如何播放音效,它将使用完全不同的方法SoundPool。SoundPool虽然是基于MediaPlayer的,但是他被优化用来同时播放多个文件,而且不适合播放较大的文件,可以说,他就是为播放音效定制的。下面就让我们看一下播放音效的代码:

private static int MAX_CHANNEL = 6;

private static SoundPool soundPool;

private static HashMapsoundPoolMap;

private static AudioManager audioManager;

首先设定声道数,如果同时播放的音频超过这个数量,最先播放的音频就会被关闭。然后定义SoundPool变量。大家注意soundPoolMap这个变量,下面会重点讲解。

public static void playSE(String path, float volume, int loop, float rate) {

if(soundPool == null) {

soundPool = new SoundPool(MAX_CHANNEL, AudioManager.STREAM_MUSIC, 10);

}

if(soundPoolMap == null) {

soundPoolMap = new HashMap();

}

if(!soundPoolMap.containsKey(path)) {

soundPoolMap.put(path, soundPool.load(path, 1));

}

这里我们要讲解一下soundPoolMap。在音频被播放前需要先将它载入到内存,载入后,会得到一个streamID,SoundPool中的很多函数都使用这个ID来控制特定的音频流。所以,我们将这个ID保存到map中,并与音频文件的路径相对应。后面就可以通过路径来找到这段音频流了。

if(volume < 0) {

if(audioManager == null)

audioManager = (AudioManager)Main.getInstance()

.getSystemService(Context.AUDIO_SERVICE);

volume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

}

while(soundPool.play(soundPoolMap.get(path),

volume, volume, 0, loop, rate) == 0);

}

这个方法并不是很科学,最好还是在初始化的时候载入音频,大家可以另行撰写一个load方法。

public void playSE(String path) {

playSE(path, -1f, 0, 1f);

}

public void stopSE(String path) {

if(soundPool != null && soundPoolMap != null

&& soundPoolMap.containsKey(path)) {

soundPool.stop(soundPoolMap.get(path));

}

}

修改SceneStartMenu中的start函数测试一下吧

public void start(SurfaceHolder surfaceHolder){

// Util.playBGM("/sdcard/sample.mid", false);

Util.playSE("/sdcard/system11.ogg");

Util.playSE("/sdcard/system12.ogg");

}

现在,这部教程终于可以告一段落了,虽然有点虎头蛇尾,但我大概已经讲解了制作一个简单游戏所用到的各方面的知识。如果还有不足,请读者留言补充,大家互相学习,一起提高。最终我在教程中没有完成坦克大战,不过我会基于坦克大战设计一个新的游戏,不再使用Java,而是一个全新的跨平台框架,到时候再与大家分享我的心得。

本章示例程序 http://u.115.com/file/f1435ee7e8

你可能感兴趣的:(从零开始Android游戏编程(第二版) 第十二章 音乐与音效)