Learning XNA 3.0翻译连载--第5章 声音和音效

译者:林公子

出处:木木的二进制人生

转载请注明作者和出处,谢谢!

第五章 声音和音效


好了,您已经有了一个可靠的设计并准备继续前进了。在上一章的末尾,您的成果看起来已经像一个游戏了:您有一个可以受用户控制的在屏幕上移动的精灵,并且一旦它和某一个"敌人"精灵接触,游戏将结束。缺陷就是敌方精灵不会移动或干些什么,所以这个游戏并不是那么棒——但虽然如此,是一个好的开始。


现在,让我们集中精力到另一个问题上:您的游戏中没有声音。哪种游戏没有声音或音效呢?我可以告诉您:一个差劲的游戏。我们对傻瓜般的应用程序不感兴趣——我们是XNA开发者,这意味着我们将做出一些很酷的东西。那么让我们做吧。在这一章里,您将会为您的程序添加一些声音和音效。


对于XNA Framework 3.0,有好几种方法来实现声音效果。在之前的XNA版本中,开发者使用一个名为Microsoft Cross-Platform Audio Creation Tool(XACT)的专有声音工具。使用XACT,开发者可以汇集音乐文件来被内容管线处理并且使用XNA Framework的声音API来实现声音效果。在XNA 3.0中,仍然可以使用XACT为PC和XBox360实现声音。不过,因为Zune不支持XACT引擎,XNA小组添加了一组独立的API来进行Zune的开发。这种简化的声音API同样也支持PC和XBox360。在这一章里,我会向您展示如何用两种方法实现声音效果。


既然简化的声音API支持所有的平台,为什么还要用更复杂的XACT呢?在许多方面,XACT为您提供了一个迷你的"录音室",您可以简单的编辑声音的音量,音调,循环和其他属性而不用处理任何代码。另外,还有一些很棒的XACT特性您会在本书中用到。


  XACT的实现比简化声音API提供了更多的特性,代价就是它更加复杂。为了让您更好的学习它,这一章中的大部分例子和本书剩下的部分都会使用XACT进行声音处理。不过,简化的声音API也会在本书的例子中使用。您可以随意的在本书接下来的部分使用简化声音API而不是XACT,但是请注意您声音部分的代码将会和这些例子中使用的不同。


使用XACT


当为PC和Xbox360开发游戏的时候,开发者可以使用XACT引擎或Zune兼容API中的一个。不过,用XACT实现声音有一些独有的优势,比如在代码之外创建自定义音轨,编辑音质,创建循环和其他效果。


这一章使用第4章结尾的代码。打开解决方案并添加一个新目录来存放本章中用到的所有声音文件。右键点击解决方案浏览器中的Content节点,添加->新建文件夹,命名文件夹为Audio。


要用XACT处理声音,您需要一些.Wav文件。下载本章的代码并存到您的硬盘中。您会在代码文件夹中找到两个.Wav文件(start.Wav, track.Wav)。位于AnimatedSprites\AnimatedSprites\Content\Audio目录。


拷贝start.Wav, track.Wav到您项目的Content\Audio文件夹下。在之前的例子中,当您拷贝资源到项目目录的Content文件夹之后,还需要在Visual Studio的解决方案管理器中将资源添加到项目中,以便内容管线可以获取和处理这些资源。不过现在您不用这样做。内容管线对待声音文件比起其他资源有些微的区别。当使用XACT处理声音文件时,您可能希望有实际的声音文件放置在项目的目录中,但是实际中您会通过XACT工具创建一个由那些声音文件组成的声音项目文件,这是唯一一个将实际添加到您项目中的文件。内容管线将只会处理XACT声音项目文件;它会通过您的XACT声音项目文件处理您的声音文件。


在这个例子中,您将添加一个在游戏启动时播放的声音,另一个将用作游戏过程中循环播放的音轨。start.Wav将在游戏开始时播放,track.Wav文件会作为音轨循环。


一旦您拷贝这两个文件到您项目的Content\Audio目录,点击Windows开始菜单->所有程序->Microsoft XNA Game Studio 3.0->Tools->Microsoft Cross-Platform Audio Creation Tool(XACT)。

 

图片

Windows Vista中,您应该用管理员权限启动XACT,右键点击上面提到的开始菜单项,选择"以管理员身份运行"


XACT窗口打开后,选择File->New Project,您需要创建一个Wave Bank(波形库)Sound Bank(音色库)。右键点击窗口左边的Wave Banks节点,选择New Wave BankXACT将会为您的wave bank打开一个新的窗口,并且您可以编辑Wave Banks节点下面的名称。敲回车接受默认的wave bank名字,"Wave Bank"


接下来,您需要创建一个Sound Bank,和您刚才创建Wave Bank一样,右键点击窗口左边的Sound Banks节点,选择New Sound Bank,敲回车接受默认的Sound bank名字,"Sound Bank"


XACT会为您打开两个窗口(一个wave bank,一个sound bank)。您可以重新排列它们以便工作,选择菜单项Windows->Tile Horizontally。结果应该看起来和图5-1类似。

图5-1

      图5-1 XACT中的Wave BankSound Bank窗口。

  

现在看看Sound Bank窗口。它被分成了两个部分:上面的部分包含了一个Sound名称的列表,下面的部分包含了cue(清单)名称列表。在XNA中用XACT处理声音的时候,您使用称为cue的东西来访问声音和音效。在一个XACT项目文件中,cue由一个或多个声音(Sound)组成,而声音由一个或多个波形(Wave)组成。声音和Cue列在Sound Bank窗口的两个区域中,Wave Bank条目列在Wave Bank窗口中。


您需要为start.wavtrack.wav创建一个cuesound条目。拖拽Wave Bank窗口中的两个条目到Sound Bank窗口的Cue Name区域。


译注:cue不太好翻译,又因为XACT界面是英文,所以这个词就以原文出现。作用类似于清单,或者说播放列表,不过有更高的可控性。如果哪位朋友有好的翻译建议可以提出:)。

P.S: 大天使在留言中提到了MSDN中对Cue的定义,这里引用他的留言,感谢:

Cue主要就是为了实现这样一个功能:
当有很多音效对应同一个事件的时候,不需要程序员手动替换各种音效,Cue会自动随机播放,已达到模拟现实的效果。比如,枪声都很类似,但开机枪 时如果始终是一种音效会显得很假,开发者应该实现数种音效,然后在播放时随机交替,如果手写代码是很痛苦的,Cue自动完成了这个功能。


  图5-2

  图5-2 添加到Wave Bank中的wave文件。


    图片

如果您拖动Wave条目到Sound Bank窗口的Sound Name区域中,XACT只会为您的wave bank创建一个sound name。每一个wave bank都需要一个soundcue条目,将wave bank拖动到Cue Name区域将会为您创建这两者。


  当您添加好后,XACT项目窗口看起来应该和图5-3类似:

    图5-3.

    图5-3 您的XACT项目现在有了一个Cue


   

您现在准备保存项目然后开始在Visual Studio中进行XNA代码编写了,不过在那之前,让我们谈谈XACT的几个特性。您可以在XACT中播放sound,cue,wave确保您有正确的声音文件,并且听起来如您所期望的那样。不过,想要在XACT中播放声音,您需要启动XACT Auditioning Utility


XACTXACT Auditioning Utility通讯来播放声音。要启动XACT Auditioning Utility(试音工具), 选择开始菜单->所有程序->Microsoft XNA Game Studio 3.0->Tools->XACT Auditioning Utility

图片XACT工具一样,当您使用vista时,需要以管理员身份启动XACT Auditioning Utility(右键点击程序项并选择"以管理员身份运行")



图片2

如果您有程序运行在端口80上,试音工具将不会工作,因为它使用那个端口和XACT通讯。另外,如果您的PC上安装了IIS,要注意IIS运行会阻碍XACTXACT Auditioning Utility之间的通讯。您需要停止IIS服务,以使您能够通过XACT Auditioning Utility播放声音文件。


一旦您启动了XACT Auditioning Utility, 它会处于"Waiting for the XACT authoring tool to connect"状态(见图5-4),直到您从XACT里播放声音。

图5-4

图5-4  XACT Auditioning Utility等待XACT进行连接。


XACT Auditioning Utility,运行后,您可以右键点击XACT中的任何一个sound,cue,wave选择Play命令来试听声音。


除了试听声音外,您还可以修改声音本身的属性。当您在Sound Bank中选中一个声音的名字时,XACT会在项目窗口的左下角显示这个声音的属性。您会注意到一些可以修改音量,音调,优先级和循环的选项。关于目前的项目,start.wav文件对于某些人的喜好来说有些安静了,因此随意改变音量并试听直到让您满意。


  您想要track.wav文件在程序中无限循环播放,那么您可以在XACT中改变设置来完成而不用在XNA进行额外的编码。为了设置track声音的属性,选中Sound Bank窗口的Sound Name区域中的track项。在左下角的属性面板中选中Loop区域的Infinite复选框(见图5-5)。这样设置后当您用XNA代码启动和这个声音关联的cue时声音就会无限循环。

  图5-5

    5-5 track声音设置无限循环。


最后,当您点击cue name而不是sound name的时候,您会在左下角的属性面板中看到一些不同的属性。这面板允许您修改和cue关联的声音的播放方式。目前您只有一个声音和这个cue相关,但是您可以添加任意个。如果您的cue关联了多个声音,每次您在XNA代码中调用特定的cue时,XACT会选择不同的声音播放。这对爆炸或撞击这类相似但又有些微不同的声音很有用。举个例子,在现实生活中,所有的爆炸声都有些区别,这就给了您一个途径来模仿它。在属性面板中您还可以指定当选中的cue被调用时,一个特定的声音将被播放的权重或可能性(译注:即被播放的几率)


一旦您调整声音到满意了,保存您的项目。关闭XACTAuditioning Utility,然后回到Visual Studio的游戏项目中。


在代码中使用XACT声音文件


在您的XNA项目中使用XACT声音项目的第一步是把之前在XACT中保存的文件包含到您的项目中。记得之前您将.wav文件拷贝到项目的Content\Audio目录下了,但是您还没有将它们包含到Visual Studio项目中。像我之前所说,您实际上需要包含到项目中的是之前在XACT中创建的项目文件。如果顺利,您已经将XACT项目文件命名为GameAudio.xap并且将它保存在项目的Content\Audio目录下了。如果是这样那么点击解决方案管理器中的Content\Audio文件夹,选添加->现有项,选择GameAudio.xap然后将它添加到项目中。


要从XACT项目文件中读取数据到对象中让您可以在XNA中播放声音,您需要添加以下成员变量到Game1类的顶部:

1    AudioEngine audioEngine;
2    WaveBank waveBank;
3    SoundBank soundBank;
4    Cue trackCue;

 

第一个变量代表一个称为声音引擎(sound engine)的东西。这个对象会用来创建Wave BankSound Bank对象,并且是XNA声音的核心对象。或许您已经猜到了,WaveBankSoundBank对象相当于XACT文件的sound bankwave bank部分。Cue对象用来从Sound Bank中取出独立的cue来播放。您可以播放一个cue而不用持有那个特定cue的变量,不过如果您没有持有cue本身,一旦声音开始播放,您不能够暂停/恢复/停止/开始播放或与其交互。


一旦您添加了这些变量,就需要初始化它们。添加以下代码到Game1LoadContent方法中:

1      audioEngine  =   new  AudioEngine( @" Content\Audio\GameAudio.xgs " );
2      waveBank  =   new  WaveBank(audioEngine,  @" Content\Audio\Wave Bank.xwb " );
3      soundBank  =   new  SoundBank(audioEngine,  @" Content\Audio\Sound Bank.xsb " );

 

这是内容管线对待声音文件不同于其他大多数资源的一个方面。加载声音到内存中,您不用到目前为止加载资源时用到的Content.Load方法,而是用更普通的构造方法来实例化每个对象。


不过内容管线仍然参与到解析音频数据中来。在编译时,内容管线获取XACT创建的文件,解析它,将其分解成不同的文件让您的代码在运行时使用。编译您的游戏之后,在Windows资源管理器中看一看项目的bin\x86\Debug\Content\Audio文件夹,您可以看到在上面得构造方法中引用到得文件。


内容管线为每个.xap文件(XACT项目文件)产生了一个.xgs文件。为项目文件中的每个sound bank产生一个.xsb文件,为每个wave bank产生一个.xwb文件。这些文件通过代码加载到各自对应的对象中。注意sound bankwave bank对象同样需要声音引擎对象传入到它们的构造方法中。最后,注意传入构造方法的参数是实际的路径和文件名,而不是XNA中大多数资源用到的资源名。


一旦这些对象被初始化,您就准备好用它们播放声音了。声音由XACT文件中的标识cue和播放cue来进行播放。当您将start.wav条目从wave bank拖入sound bankcue区域时,XACT创建了一个名为startcue并将其关联到要播放的特定.wav文件。要播放cue,用SoundBank.GetCue方法从SandBank对象中获取Cue对象。然后调用Cue对象的Play方法。举个例子,下面这段代码将播放start cue:

1     trackCue  =  soundBank.GetCue( " track " );
2     trackCue.Play();

 

如果您播放cue并且持有cue实例的对象,就像这个例子中的一样,您可以访问CueStopPause和其他方法,允许您在声音播放的时候修改它。如果您不需要这种功能,您可以直接从SoundBank对象中播放声音而不用Cue对象:

1    soundBank.PlayCue( " track " );

 

就现在而言,您想要持有一个音轨的Cue对象以便您能在需要时暂停它,但是您不需要为start声音这样做(一旦start声音播放完,您不需要去停止或暂停它)。

游戏一开始这两种声音您都将需要播放。您可以在Game1类的LoadContent中初始化对象后立即就开始播放这两个声音。将以下代码添加到LoadContent方法的末尾:

1       //  开始播放音轨。
2      trackCue  =  soundBank.GetCue( " track " );
3      trackCue.Play();
4 
5       //  播放start声音。
6      soundBank.PlayCue( " start " );

 

注意如果您在播放声音时持有一个Cue对象,您需要确保Cue对象在您需要时一直存在于作用域中。否则,垃圾回收装置会拾取它,声音将变得不可用。


您需要做的最后一个修改是每帧调用AudioEngine对象的Update方法来保持和游戏同步。您可以在Game1类的Update方法中做这个。如果忽略AudioEngine.Update会导致声音变得不同步而产生问题。添加以下代码到Game1类的Update方法中的base.Update调用之上:

1    audioEngine.Update();

 

编译并运行游戏,您应该可以听到开场声音和背景音乐。并且背景音乐会循环直到游戏结束。如您所见,XACT是一个可以让您在设计时修改声音文件属性的强大工具。这是一个可以加速开发和微调您的声音和音效的好方法。


使用简化声音API


当为Xbox360PC平台做开发时,利用XACT提供的好处是明智的选择。不过,Zune不支持XACT,所以XNA3.0框架提供了一组简化的声音API让开发者可以在Zune上播放声音。您同样也可以在Xbox360PC项目中使用简化API,如果您不需要XACT提供的额外特性的话。


关闭您现在的XNA游戏项目并创建一个新的XNA Windows Game项目,命名为SimpleSounds


要用简化声音API播放声音首先您要添加一个声音文件到项目中。记得当使用XACT时,真正的声音文件没有添加到项目中,不过当使用声音API的时候就不同了,声音文件和其他资源一样被内容管线同等对待,需要添加到项目中,就像之前您对待2D图像那样。


XNA 3.0声音API支持.wav, .wma.mp3类型的文件。在这个例子中,您将使用本章之前例子中的start.wav文件。现在您的硬盘上应该已经有这个文件了,如果没有,您可以在第5章代码的SimpleSounds\Content\Audio文件夹找到它。


为项目添加一个新的内容目录,右键点击解决方案管理器中的Content节点选择添加->新建文件夹,命名文件夹为Audio。然后,添加start.wav文件到项目中。


和其他资源一样,当您将文件添加到项目中,您能够查看它的属性,会发现内容管线为它赋予了一个资源名称和其他的属性。


一旦您将文件添加到项目中,您需要创建SoundEffect类型的变量来通过内容管线加载声音,添加下面的成员变量到Game1类中:

1  SoundEffect soundEffect;

 

  一旦您创建好SoundEffect变量,添加以下代码到LoadContent方法将文件加载到变量中:

1  soundEffect  =  Content.Load < SoundEffect > ( @" Audio\start " );

 

要播放声音,您要调用SoundEffect对象的Play方法。SoundEffect.Play返回一个SoundEffectInstance类型的对象,您可以用它来暂停,停止和开始播放声音,也可以调整音量和声音的其他方面。


  要在游戏开始时播放声音,添加以下代码到LoadContent方法末尾:

1  SoundEffectInstance soundEffectInstance  =  soundEffect.Play();

 

就像之前提到的,本书剩下部分的大多数例子都使用XACT使读者可以熟悉这个工具。不过如果您喜欢,可以随意使用简化声音API


添加更多声音到您游戏中


现在让我们花一点时间添加另一个声音特性到您的游戏中。关闭SimpleSounds项目,打开之前的项目。


在您创建的游戏中,一个受用户控制的精灵会在屏幕上移动,目标是躲避屏幕上四处飞行的自动精灵(没错,留下您的钞票,这将是一个惊人的游戏)


即使目前游戏中的自动精灵还没有移动,您仍然可以添加一些当用户精灵和自动精灵碰撞时的音效。


您要在碰撞事件中将要播放的cue的名字传递给每个精灵,因此您要做的第一件事就是打开Sprite.cs文件,添加一个成员变量来持有要使用的cue的名字。另外,您会用到C#3.0的自动实现属性特性来为这个变量创建一个publicget访问器和一个privateset访问器:

1  public   string  collisionCueName {  get private   set ; }

 

如果您是C#3.0新手,而且不熟悉这个特性,自动实现属性允许开发者在变量定义的地方为其创建访问器。这样提高了编码效率,使其易于实现和阅读。(您可以随意在Internet上深入了解自动实现属性或其他C# 3.0新增的特性)。


最后,添加一个string类型的变量到两个构造方法的参数列表中。在第一个构造方法中,传递这个新变量到对第二个构造方法的调用中。在第二个构造方法的方法体中,将这个新参数的值赋给collisionCueName。您的新构造方法看起来应该是这样:

 1    public  Sprite(Texture2D textureImage, Vector2 position, Point frameSize,
 2                         int  collisionOffset,  Point currentFrame, Point sheetSize, 
 3                        Vector2 speed,  string  collisionCueName)
 4                       :  this (textureImage, position, frameSize, collisionOffset, 
 5                              currentFrame, sheetSize, speed, defaultMillisecondsPerFrame, collisionCueName)
 6          {
 7 
 8          }
 9 
10           public  Sprite(Texture2D textureImage, Vector2 position, Point frameSize,
11                         int  collisionOffset, Point currentFrame, Point sheetSize,
12                        Vector2 speed,  int  millisecondsPerFrame,  string  collisionCueName)
13          {
14               this .textureImage  =  textureImage;
15               this .position  =  position;
16               this .frameSize  =  frameSize;
17               this .collisionOffset  =  collisionOffset;
18               this .currentFrame  =  currentFrame;
19               this .sheetSize  =  sheetSize;
20               this .speed  =  speed;
21               this .millisecondsPerFrame  =  millisecondsPerFrame;
22               this .collisionCueName  =  collisionCueName;
23          }

 

  接下来,打开AutomatedSprite.cs文件。您需要为AutomatedSprite类的两个构造方法添加一个string类型的参数用来表示碰撞时要播放的cue的名称。每个构造方法都会接受cue名称参数并且传递给基类构造方法。您的AutomatedSprite构造方法看起来应该是这样:

 1    public  AutomatedSprite(Texture2D textureImage, 
 2                                 Vector2 position, 
 3                                 Point frameSize, 
 4                                  int  collisionOffset,
 5                                 Point currentFrame,
 6                                 Point sheetSize,
 7                                 Vector2 speed, 
 8                                  string  collisionCueName)
 9                                 :  base (textureImage, 
10                                          position, 
11                                          frameSize, 
12                                          collisionOffset, 
13                                          currentFrame, 
14                                          sheetSize, 
15                                          speed,
16                                          collisionCueName)
17                                 
18          {
19 
20          }
21 
22           public  AutomatedSprite(Texture2D textureImage,
23                         Vector2 position,
24                         Point frameSize,
25                          int  collisionOffset,
26                         Point currentFrame,
27                         Point sheetSize,
28                         Vector2 speed,
29                          int  millisecondsPerFrame,
30                          string  collisionCueName)
31              :  base (textureImage,
32                       position,
33                       frameSize,
34                       collisionOffset,
35                       currentFrame,
36                       sheetSize,
37                       speed,
38                       millisecondsPerFrame,
39                       collisionCueName)
40          {
41 
42          }

 

  您的UserControlledSprite类不会使用碰撞音效,因为当玩家和一个精灵碰撞时,您将会播放和玩家碰撞的那个精灵的声音,而不是玩家本身。因此,您不需要为UserControlledSprite类的构造方法添加collisionCueName参数,不过您需要为基类的那个参数传递null值。UserControlledSprite类的构造方法看起来应该像这样:


 1    public  UserControlledSprite(Texture2D textureImage,
 2                                      Vector2 position,
 3                                      Point frameSize,
 4                                       int  collisionOffset,
 5                                      Point currentFrame,
 6                                      Point sheetSize,
 7                                      Vector2 speed)
 8                                      :  base (textureImage,
 9                                             position,
10                                             frameSize,
11                                             collisionOffset,
12                                             currentFrame,
13                                             sheetSize,
14                                             speed, 
15                                              null )
16          {
17          }
18 
19           public  UserControlledSprite(Texture2D textureImage,
20                                      Vector2 position,
21                                      Point frameSize,
22                                       int  collisionOffset,
23                                      Point currentFrame,
24                                      Point sheetSize,
25                                      Vector2 speed,
26                                       int  millisecondsPerFrame)
27                                      :  base (textureImage,
28                                             position,
29                                             frameSize,
30                                             collisionOffset,
31                                             currentFrame,
32                                             sheetSize,
33                                             speed,
34                                             millisecondsPerFrame,
35                                              null )
36          {
37          }

 

  您将在Game1类中通过SpriteManager来播放cue。在Game1类中添加下面的公共方法,您将会在SpriteManager类中调用它:

1       public   void  PlayCue( string  cueName)
2      {
3          soundBank.PlayCue(cueName);
4      }   

 

目前您还没有一个用来和头骨精灵碰撞时播放的Cue。之前您只添加了开始声音和背景音乐到XACT项目中。第5章代码的AnimatedSprite\Content\Audio文件夹下有一个名为skullcollision.wav的文件。拷贝这个文件到项目的Content\Audio目录下。同样,因为您要使用XACT播放这个声音文件,不用将这个文件添加到Visual Studio中。

打开XACT,右键点击Wave Bank窗口的空白处,选Insert Wave File(s)...skullcollision.wav添加到Wave Bank中。然后拖动新添加的skullcollision放到Sound BankCue Name区域来为这个声音产生一个Cue名。

您的XACT Sound Bank窗口看起来应该和图5-6一样:

图5-6

      图5-6 头骨精灵碰撞音效的soundcue创建好了。

您可能想要调整头骨碰撞音效的音量,看样子它默认的音量稍微有点小。要这么做在Sound Name区域选择skullcollision,然后编辑左下角面板的Volume属性。

保存XACT文件然后回到Visual Studio

  最后需要修改代码的地是时SpriteManager类。首先,您将需要为每个AutomatedSprite实例的构造方法传递一个用于碰撞音效的cue名称。每个AutomatedSprite都是在SpriteManager类的LoadContent方法中创建的。添加cue名称作为这些构造方法的最后一个参数,如下:

  

 1      spriteList.Add( new  AutomatedSprite(Game.Content.Load < Texture2D > ( @" Images/skullball " ),
 2                                          new  Vector2( 150 150 ),
 3                                          new  Point( 75 75 ),
 4                                          10 ,
 5                                          new  Point( 0 0 ),
 6                                          new  Point( 6 8 ),
 7                                         Vector2.Zero, 
 8                                          " skullcollision " ));
 9 
10      spriteList.Add( new  AutomatedSprite(Game.Content.Load < Texture2D > ( @" Images/skullball " ),
11                                          new  Vector2( 300 150 ),
12                                          new  Point( 75 75 ),
13                                          10 ,
14                                          new  Point( 0 0 ),
15                                          new  Point( 6 8 ),
16                                         Vector2.Zero,
17                                          " skullcollision " ));
18 
19      spriteList.Add( new  AutomatedSprite(Game.Content.Load < Texture2D > ( @" Images/skullball " ),
20                                          new  Vector2( 150 300 ),
21                                          new  Point( 75 75 ),
22                                          10 ,
23                                          new  Point( 0 0 ),
24                                          new  Point( 6 8 ),
25                                         Vector2.Zero,
26                                          " skullcollision " ));
27 
28      spriteList.Add( new  AutomatedSprite(Game.Content.Load < Texture2D > ( @" Images/skullball " ),
29                                          new  Vector2( 600 400 ),
30                                          new  Point( 75 75 ),
31                                          10 ,
32                                          new  Point( 0 0 ),
33                                          new  Point( 6 8 ),
34                                         Vector2.Zero,
35                                          " skullcollision " ));

 

最后,您需要修改SpriteManager类的Update方法,当检测到和UserControlledSprited的碰撞时来播放AutomatedSprite的碰撞音效。

修改代码当检测到碰撞时移除AutomatedSprite。因为您在使用foreach语句时不能修改列表中项目的数目,所以您需要将foreach换成for循环。您的SpriteManager类的新Update方法看起来应该像这样:

 1  public   override   void  Update(GameTime gameTime)
 2  {
 3       //  更新玩家。
 4      player.Update(gameTime, Game.Window.ClientBounds);
 5 
 6       //  更新列表中所有的精灵。
 7       for  ( int  i  =   0 ; i  <  spriteList.Count;  ++ i)
 8      {
 9          Sprite s  =  spriteList[i];
10 
11          s.Update(gameTime, Game.Window.ClientBounds);
12 
13           //  碰撞检测。
14           if  (s.CollisionRect.Intersects(player.CollisionRect))
15          {
16               if  (s.CollisionCueName  !=   null )
17              {
18                  ((Game1)Game).PlayCue(s.CollisionCueName);
19              }
20 
21               //  从游戏中移除碰撞的精灵。
22              spriteList.RemoveAt(i);
23               -- i;
24          }
25      }
26 
27       base .Update(gameTime);
28  }

 

干得漂亮!编译并运行游戏,现在当您移动用户控制精灵区和屏幕上其他的精灵碰撞时,您会听到碰撞音效并且被碰到的精灵会从游戏中移除。

不错吧,嗯?项目有进展了。显然您需要添加更多的特性以使游戏更加让人兴奋,不过我们会在接下来的章节中去完成那些。即使这时一个很小的没有清楚的目的游戏,您仍然可以看到声音的添加使游戏的交互性和娱乐性达到了新的高度。


您刚刚做了些什么

让我们回顾一下本章您完成了什么:

Microsoft Cross-Platform Audio Creation Tool(XACT)用来创建XNA游戏中用到的声音。

XACT允许开发者在设计时修改声音的音量,音调,循环和其他更多的属性。

为了支持Zune开发,XNA 3.0框架包含了一组简化的声音API允许开发者实现声音而不用Zune不支持的XACT

My ally is XNA, and a powerful ally it is. Life creates XNA, makes it grow. XNAs energy surrounds us and binds us.... You must feel the XNAaround you, between you, me, the tree, the rock, everywhere....Start Wars, Yoda大师的语录-_-)

======================================================================

知识测试:问答

1.您用什么来引用添加到XACT声音文件中的声音?

2.使用简化声音API代替XACT的优点和缺点是什么?

3.真还是假:要使一个音轨在游戏中循环唯一的方法就是在代码中让它一遍又一遍的播放。

4.当您使用XACT声音文件的时候,怎样去暂停和重新播放一个声音?

5.按照Michael Scott所说,Abraham Lincoln曾经说过的一句什么话成为前者工作中的准则?(If you're a racist, I will attack you with the North.)

知识测试:练习

1.使用XACT尝试不同的声音和声音设置。找一些wav文件然后插入到游戏中,尝试将多个声音组织到一个cue中来试验XACT中不同的设置。


你可能感兴趣的:(翻译)