[翻译]XNA 3.0 Game Programming Recipes之fifty-one


PS:自己翻译的,转载请著明出处

                                                              7-4 循环声音
问题
                                 你想要循环声音去播放背景音乐或者播放一个持续的声音,例如汽车引擎的噪音。
注意:由于Zune不支持XACT,你想要使用三个重载的SoundEffect.Play()方法去循环你的声音,正如7-1节相应的内容。
解决方案
                                 使用XACT声音工具,它是非常的容易去表示一个声音应该持续循环。你想要去创建并跟踪Cue对象在你的XNA代码,因为你需要能够暂停或者停止正在播放的声音。
                                 你同样可以编程的方式检测当一个声音是否已经完成了播放,这是非常有用的,如果你想要选择背景音乐。通过检查Cue的IsStopped成员来实现这个。
它是如何实现的

Looping a Sound Indefinitely(无限循环一个声音)
                                 你可以很容易产生一个循环通过设置它的LoopEvent属性到Infinite在XACT音频工具。为了实现这个,打开你的XACT项目,并且选择在你的sound bank中这个你想要循环的声音。一旦你已经选择这个声音,这Play Wave的条目应该可见在Sound Bank 框架的右上角。点击Play Wave节点,如图7-2显示的。
                                 在点击Play Wave节点,它的属性应该可见在属性合子里在你的XACT窗口的左下角。找到LoopEvent属性,并设置它到Infinite.确保你保存你的XACT属性。

                                 现在,当你重新编译你的XNA项目并且播放cue使用从前面中的代码,它将无限循环。由于你想要某些种类的控制,它允许你去停止cue,你需要创建一个Cue对象去保存一个相关的cue:
1 Cue cue1;
                                 填充这个对象通过调用GetCue方法在你的soundBank变量中。在这个Cue对象,你可以调用这个Play方法去开始一个cue:
1 cue1=soundBank.GetCue("audio1");
2 cue1.Play();
                                 这将开始无限播放cue,正如你定义在XACT音频工具。只在这时,你有一个相关的cue,你可以使用它暂停,重新开始,或者停止这个cue:
1 cue1.Pause();
2 cue1.Resume();
3 cue1.Stop(AudioStopOptions.Immediate);

注意:在你已经停止一个正在播放的cue,你不可以简单的调用Play在cue上。你首先需要从soundBank通过调用它的GetCue方法去加载它

Checking Whether a Sound Has Finished Playing/Changing Background Music
                                 通过它的IsStopped属性,你可以检查一个声音cue是否已经播放:

1 if(currentCue.IsStopped)
2     //do something
                                 如果你想要你的XNA项目去通过一些背景声音来循环,你应该创建一个数组去保留cues的名字,并且不是cues它们自己,一旦它们已经播放,它将是没有用的。你需要这些额外变量去创建一个背景循环系统:

 

1 string[] bgCueNames;
2 Cue currentCue;
3 int currentCueNr=0;
                                 这个数组将保留被播放的背景cues的名字。currentCue将保留这个正在播放的cue,这样你可以检查是否它被完成了,并且currentCueNr变量被需要的,这样你的程序可以激活下一个cue.
                                 这个方法它初始化cue名字的数组,并且开始第一个cue:
 1 private void InitSounds()
 2 {
 3      audioEngine=new AudioEngine("Content/Audio/MyXACTproject.xgs");
 4      waveBank=new WaveBank(audioEngine,"Content/Audio/myWaveBank.xwb");
 5      soundBank=new SoundBank(audioEngine,"Content/Audio/mySoundBank.xsb");
 6      bgCueNames=new string[5];
 7      bgCueNames[0]="bgAudio1";
 8      bgCueNames[1]="bgAudio2";
 9      bgCueNames[2]="bgAudio3";
10      bgCueNames[3]="bgAudio4";
11      bgCueNames[4]="bgAudio5";
12      PlayBGCue(0);
13 }
                                 你首先不得不创建一个XACT项目,如图7-1所示,包含五个cues.这个PlayBGCue方法,他实际上开始一个cue很容易:
1 private void PlayBGCue(int cueNr)
2 {
3     currentCue=soundBank.GetCue(bgCueNames[cueNr]);
4     currentCue.Play();
5 }
                                 它保存一个相关的当前播放的cue在currentCue变量中,这样你可以检查它的IsPlayed属性在一个UpdateSounds方法中,这样你可以从你的主Update方法中调用:
Code

                                 如果当前的cue已经正在播放了,你增加currentCueNr,同时设置它回到0,如果已经比可播放cues的数量大,在这种情况下是5。最后,你调用PlayBGCue,所以下一个音频开始播放。
注意:在currentCueNr之前++表示你想要currentCueNr的值去增加在整个行前得到评估。如果你写了currentCueNr++,这个条件将会是false,如果currentCueNr是4,并且在此之后,这个值增加到5,这将得到一个OutOfRange异常在GetCue方法中。通过写++currentCueNr,如果currentCueNr是4,这个值首先增加到5,这样这个条件将会是true,并且值将重新设置成0。
                                 通过把Update访问在这个方法中的audioEngine,在这个Update方法中所有你不得不调用的是UpdateSounds方法。

代码
                                直到你可以找到所有的代码为本章前面这个背景播放列表的循环,下面的代码开始一个循环默认的声音在这节的第一部分,通过压下空格键并且通过Enter键结束它:

 1 protected override void Update(GameTime gameTime)
 2 {
 3     GamePadState gamePadState=GamePad.GetState(PlayerIndex.One);
 4     if(gamePadState.Buttons.Back==ButtonState.Pressed)
 5            this.Exit(); 
 6     KeyboardState keyState=Keyboard.GetState();
 7     if(keyState.IskeyDown(Keys.Space)||(gamePadState.Buttons.B==ButtonState.Pressed))
 8     {
 9         if((cue1==null)||(cue1.IsStopped))
10         {
11             cue1=soundBank.GetCue("audio1");
12             cue1.Play(); 
13         }
14     }
15     if(keyState.IsKeyDown(Keys.Enter)||(gamePadState.Buttons.A==ButtonState.Pressed))
16             if(cue1!=null)
17                 cue1.Stop(AudioStopOptions.Immediate);
18     audioEngine.Update();
19     base.Update(gameTime);
20 }
                                 首先空格键被压下,这个cue1变量将会是null。当用户压下Enter键,这个cue被停止。当用户再次压下空格键,这个cue被重新设置。
                                 再一次,注意,你需要去重新创建这个cue1变量(通过调用GetCue方法)在cue已经停止之后。
源代码:http://shiba.hpe.cn/jiaoyanzu/WULI/soft/xna.aspx?classId=4
(完)

posted on 2009-09-04 11:07  一盘散沙  阅读(286)  评论(0编辑  收藏  举报

导航