关闭

Chapter 4(1): Game Components游戏组件

942人阅读 评论(0) 收藏 举报
 

Chapter 4: Game Components游戏组件

Overview

This chapter talks about the concept behind the Game class and the game components you can add to it. To get your graphic engine up and running in the next chapter you still need some new helper classes before starting with 3D concepts. The BaseGame class is used to implement more features and to include all the other classes you have written so far. It is derived from the Game class to take advantage of all the existing XNA features. In the same way our main test class TestGame is derived from BaseGame to help you execute static unit tests in your game. Then you will add the TextureFont class to your Helpers namespace to allow you to draw text on the screen, which is not possible out of the box in XNA. Finally, you also add some of the existing functionality from the previous chapters such as input, controller handling, and sound output into special classes to make it much easier to write a new game. Instead of just making some general assumptions, this chapter takes the game you are going to develop later in this chapter as a prime example.

本章讲述Game类背后的概念和你可以添加的游戏组件。在你开始建立图像引擎并运行之前你仍然需要一些新的辅助类。BaseGame类用来实现更多的特性并包括你至今所写的所有辅助类。它是从Game类发展来的,并将利用XNA 的所有特性。同样方法,我们主测试类TestGame是从BaseGame发展来的,帮助你运行游戏的静态单元测试。然后你要添加TextureFont类到你的Helpers辅助类命名空间中,用来在屏幕上绘制文字。最后,你还要添加一些在前面内容中已经存在的功能,例如输入、挡板操作和声音输出,利用这些特别的类可以刚容易的编写新游戏。本章后面要开发的游戏只是作为最初的例子,你可以自己改进。

In contrast to the previous chapter you are not going to write any helper classes first, but instead you are going to write the unit tests and the game class first and then add all the game components you need to your project. In the last few projects the problems were fairly simple and once you resolved them there was no need to go through them again. For the game you are going to develop in this chapter many improvements can be made and you will see this becomes even more true the bigger the game projects become. Refactoring is still the most important thing you have to remember when working over existing code and improving your game. Sometimes you will even see the code used in the unit tests ending up somewhere else in the final game code.

和前面章不同的是本章一开始你不需要写任何辅助类,但是要写单元测试和游戏类,然后向项目中添加游戏需要的组件。在后面的几个项目中,问题都很简单,一旦你解决了以后就不用再解决了。本章要开发的游戏还有很多你可以自己改进的余地,如此一来你可以看到项目会慢慢变大。当你工作在以往代码基础上改进游戏时候,重构是你需要记住的一样很重要的事。甚至有时候你会看到最终游戏代码是以一段单元测试中的代码结束的。

As an example game a simple Tetris clone is used. It will feature a big play field with colored blocks falling down, support for keyboard and gamepad input, a next block field showing you what comes next, and a little scoreboard containing the current level, score, highscore, and lines you destroyed. If you are a Tetris fan like me and like to play it every once in a while this game is great fun. Tetris is one of the most popular puzzle arcade games ever. It was invented by the Russian Alexey Pazhitnov in 1985 and became very popular ever since Nintendo released it on the Game Boy system in 1989.

我们使用Tetris的克隆版来作为游戏示例。这个游戏的特点是有一个很大的场地,期中有不同颜色的砖块不断下落,游戏支持键盘和手柄输入,另外一个区域显示下一个要落下的砖块信息,还有一个小的分数板,里面有当前等级、分数、最高分和你消掉的行数。如果你像我一样喜欢玩Tetris,你会再写这个游戏的时候感到更有趣。Tetris曾经是最流行的一款益智游戏。是俄罗斯的Alexey Pazhitnov1985年发明的,然后由任天堂1989年在Game Boy上发布。

The Game Class

You already used the class in the previous chapters, but other than starting the game by calling the Run method from the Program class and your unit tests and using the Initialize, Update, and Draw methods, those chapters did not talk about the underlying design. Well, you don’t really need to know anything else if you are just creating a few simple games, but as games become bigger and have more features you might want to think about the class overview and class design of your game.

在前面的章节中你已经用到了Game类,但是从Program类中调用Run方法来开始游戏和单元测试还有InitializeUpdateDraw方法等底层的设计在前面章节中都没有涉及。当然,如果你只是创建一些简单的游戏,你不需要清楚每一样东西,但是当你的游戏变大并拥有了更多的特性后,你会想考虑清楚你游戏中的类和设计。

The Game class itself is used to hold the graphics device in the GraphicsDeviceManager instance and the content manager in the content field. From the Program class you just have to create an instance of your game class and call the Run method to get everything started. Unlike in the old days with Managed DirectX or OpenGL you don’t have to manage your own window, create your game loop, handle Windows messages, and so on. XNA does all that for you, and because it is handled in such a way it is even possible to run your game on the Xbox 360 platform where no window classes or Windows events are available.

Game类本身是用于在GraphicsDeviceManager实例中保存图像设备和素材管理器。从Program类中你只需要创建一个用来代替game类的方法,然后调用Run方法来开始。不像以前在MDXOpenGL中那样,你不需要管理你的窗体、创建你的循环、操控你的窗体消息之类。XNA已经帮你做好了这些,因为在Xbox360中没有窗体类或窗体事件可用,这些都已经在后台操作好了。

It is still possible to access the window of the game through the Window property of the game class. It can be used to set the window’s title, specify if the user is allowed to resize the window, get the under lying Windows handle for interop calls, and so on. All these methods do nothing on the Xbox 360 platform. There is no window, there is no window title, and it can certainly not be resized. As you already saw in the previous game, you used the Window.Title property to set some simple text to the title for showing the current level and score to the user. The reason you did that is because there is no font support in XNA; to render text on the screen you have to create your own bitmap font and then render every letter yourself. In the next games and even for the Tetris game you will need that feature, and therefore the TextureFont class is introduced in a few minutes.

通过游戏类的Window属性你仍然可以连接到游戏的窗体。这可以用于设置窗体的标题,指定是否允许用户改变窗体大小,为【interop】调用获取底层窗体操作,如此等等。所有这些方法在Xbox360平台上是没有的。没有窗体,也就没有窗口标题,当然也不能调整窗体大小。就像你在前面游戏中看到的那样,使用Window.Title属性来显示一些简单的文本到标题栏上,来显示用户当前等级和分数。那样做的原因就是在XNA中没有字体的支持;要渲染文本到屏幕上你就不得不使用你的bitmap字体然后你要自己渲染每一个字母。在下一个游戏中,包括Tetris中你需要这个特性,因此马上就需要介绍TextureFont类。

Additionally, it is worth mentioning that it is possible to set the preferred resolution in the game class constructor by setting the graphics properties like in the following example, which tries to use the 1024×768 resolution in fullscreen mode:

再多说一点,很有必要提到像下面的例子那样在游戏类的构造器中设置图像属性来设置分辨率,tries将要使用1024×768分辨率的全屏模式:

 

graphics.PreferredBackBufferWidth = 1024;

graphics.PreferredBackBufferHeight = 768;

graphics.IsFullScreen = true;

There is no guarantee that the game will actually run in that mode; for example, setting 1600×1200 on a system that just supports up to 1024×768 will only use the maximum available resolution.

不能保证游戏将会在这个模式下运行;例如,在只支持1024×768的系统上运行1600×1200的设置,游戏最终只会运行在可利用的最大分辨率下。

You already know that and Draw are called every frame, but how do you incorporate new game components without overloading the game class itself? It’s time to look at the game classes and components overview of the Tetris clone game (see Figure 4-1).

你已经知道了UpdateDraw方法是每一帧都要调用的,但是你要如何结合新的游戏组件而不重载游戏类本身呢?现在让我们来看看Tetris游戏类及其组件:


Figure 4-1

The first thing you will notice is that you have now three game classes instead of just one like in the previous game examples. The reason for that is to make the main game class shorter and simpler. The BaseGame class holds the graphics manager with the graphics device, the content manager, and it stores the current width and height values of the current resolution you use in the game. The Update and Draw methods also handle the new Input, Sound, and TextureFont classes to avoid having to update them in the main game class. Then the TetrisGame class is used to load all the graphics from the content pipeline and initialize all sprites and game components, which you learn about in a second.

你首先注意到的是现在你有了三个游戏类而不像之前的例子一样只有一个。这样做的原因就是让游戏类更短并更简单。BaseGame类中有图形设备的图像管理器、素材管理器和保存着当前分辨率的宽和高的值。UpdateDraw方法同样用来操作新的InputSoundTextureFont类而不让这些类放在主游戏类中更新。接着是TetrisGame类,它用来从素材管线中加载所有的图像,并初始化所有的精灵和接下来你要学到的游戏组件。

Finally, the TestGame class derives itself from the TetrisGame class to have access to all the textures, sprites, and game components, and it is only used in debug mode to start unit tests. The functionality of the TestGame class is very similar to the previous chapters, but this time it is organized in a nice way and separate from your main game class. The TetrisGame class uses several unit tests to make sure each part of the game works as you have planned.

最后TestGame类是从TetrisGame类中发展来的,它用来【储存/连接】所有的纹理、精灵和游戏组件,这个类只是用来进行单元测试调试的。TestGame类的功能和前面章的是很相似的,但是这一次用了更好的方法来组织,从主游戏类中分离了出来。TetrisGame类使用了几个单元测试来保证游戏的每一部分都按计划工作。

 

Game Components

The TetrisGame class also holds all game components in the Components property derived from the game class. You can add any class that is derived from the GameComponent class to this list and it will automatically be called when your game is started and when it is updated. It will not be called when you draw your game because the GameComponent does not have a Draw method. You can, however, implement your own drawing methods or just use the DrawableGameComponent class, which does have a Draw method. XNA does not have a direct Draw support for the game components; you have to call it yourself to make sure all components are called in the correct order. Because of this and for several other reasons (forcing you to use this model with almost no advantages, makes unit tests harder, your own game classes might be more effective or specific, and so on), you will not use many game components later in this book. It is generally a nice idea, but you can live without it because you have to create game components yourself anyway and you have to call Draw for them yourself too. Just for the Update method, it does not make much sense to use them.

TetrisGame类保存着Components属性中的所有游戏组件,它是从游戏类中派生来的。你可以从GameComponent类中派生出你想添加的类,当你的游戏开始或更新的时候它就会被自动调用。当你绘制游戏的时候他却不会被调用,因为GameComponent类中没有包含Draw方法。然而你可以执行你自己的绘制方法或者使用DrawableGameComponent类,这个类有一个Draw方法。XNA没有为游戏组件直接提供Draw方法的支持;你必须自己调用它,保证所有的组件都被按正确的顺序调用。因为这个和其他的原因(强制你使用这个模型几乎没有什么好处,要做的是使单元测试更强健,游戏类可能会更有效),在本书的后面你不会用到很多游戏组件。它是一个好想法,但是你可以不用它而照样继续你的工作,因为你要自己创建游戏组件并同样要为它们调用Draw方法。只有对于Update方法来说,使用组件没多大意义。

As I mentioned in Chapter 1 the basic idea is to have users collaborate and share their game components to allow others to use parts of their game engine. For example, a frame counter component or even a fullblown 3D landscape rendering engine could be implemented as a game component, but just because someone does not use a game component does not mean it is harder to copy over. For example, if you have a complicated game component like a landscape rendering module, it will probably involve some other classes too and use its own rendering engine, which might not work out of the box in your engine if you just copy one file over. Either way, plugging in external code often requires quite a bit of refactoring until it is usable in your own game engine. In beta 1 of the XNA Framework a graphical designer was available in XNA Game Studio Express for the game components and you could easily drag and drop components into your game class or even into other game components to add features to your game without writing a single line of code. Because this feature was very complicated, buggy, and did not work on the Xbox 360, it was abandoned in the beta 2 release of the XNA Framework.

就像我在第一章中提到的,基本的想法是和用户沟通,共享他们的游戏组件给其他人用到他们的游戏引擎中。例如,一个帧计数器组件或者甚至是一个完善的3D风景渲染引擎都可以作为一个组件运行,但是并不是说某人不使用组件游戏就变得困难。例如,如果你有一个像风景渲染模块那样复杂的游戏组件,它将可能会和其它的类有关并使用到那些类自己的渲染引擎,如果你只是单纯的拷贝一个文件到你的引擎中这就没什么创造性了。【使用外部代码经常需要大量的重构单元,在你的游戏引擎中是有用的】。在XNAbeta1版时,在XNA GSE中图像设计器是可用的,你可以简单的拖拽组件到你的游戏引擎中,或者甚至是拖到其它游戏组件中添加特性到你的游戏,而不用写任何一行代码。因为这个特性非常复杂,并有很多漏洞,而且不能在Xbox360上运作,因此在XNABeta2版中被放弃了。

It is not a sure thing that game components will not be used, and maybe it does not matter to most programmers that the designer is missing and you have to call the Draw methods yourself. Then a lot of game components might be available and it would be useful to know all the basics about them. In the case of the Tetris game a few components come to mind:

游戏逐渐并不一定没用,可能只是没有引起大多数程序员的注意,设计器丢失,需要自己调用Draw方法。接着很多游戏组件可能可以利用,认识组件的基本构想是有用的。在Tetris中需要一些组件的思想:

§  The grid itself with all the colored blocks and the current falling block

包含带有各色砖块和正在下落砖块的网格

§  The scoreboard with the current level, score, highscore, and number of lines you destroyed

一个分数板,包含当前等级、分数、高分和销毁的行数

§  The next block type box for the game

显示下一个砖块的类型

§  More simple things like a frame counter, handling the input, and so on

更多简单的东西,例如一个帧计数器、输入操作等等

I decided to just implement the Tetris grid and the next block feature as game components; all the code is just way too simple for implementing several new classes just for them. If you will reuse the scoreboard, for example, you could always put it in a game component, but I cannot think of any other game I would like to write that uses that scoreboard.

我决定只使用Tetris网格和下一个砖块特性作为游戏组件;所有的代码都很简单只是用来执行几个新的类。例如如果你要复用分数板,你可以把它放到游戏组件里去,但是我想不到还有什么我想写的游戏能用到这个分数板的了。

Take a closer look at the Game class and the components that were added to it (see Figure 4-2).

来仔细看看Game类和添加到其中的组件:


Figure 4-2

The gray arrows indicate that these methods are called automatically through the fact that TetrisGrid and NextBlock were added to the Components list of the Game class. In TetrisGame.Draw the Draw method of TetrisGrid is called, which again calls the NextBlock.Draw method. TetrisGame itself holds just an instance of TetrisGrid. The NextBlock instance is only used inside of the TetrisGrid class.

灰色的箭头表示这些方法被自动调用,由于TetrisGridNextBlock被添加到了Game类的Components列表中。在TetrisGame.DrawTetrisGridDraw方法被调用,它会再一次调用NextBlock.Draw方法。TetrisGame本身保存着TetrisGrid的一个实例。NextBlock实例仅用在TetrisGrid类中。

You can see that using the game components for these three classes forced you to think about the calling order and it made your game more organized just by the fact that you did not put everything into one big class. This is a good thing and, though you can do all this by yourself if you are an experienced programmer, it might be a good idea for beginners to anticipate the idea of the game components in XNA.

你可以看到为这三个类使用游戏组件会要你考虑调用的顺序,和根据实际情况来组织游戏而不是把所有东西都放在一个很大的类里。这是好东西,并且即使你是一个老道的程序员可以自己完成这些工作,这对初学者来说仍然是一个好的想法,在XNA中去预测游戏的思路。

 

More Helper Classes更多的辅助类

Didn’t talk enough about helper classes in the last chapter? Yes we did. The two new classes you are going to use for the Tetris game are not discussed here in great detail and they are just stripped-down versions of the real classes you use later in this book. But they are still useful and help you to make the programming process of your game easier.

在上一章讲的辅助类还不够吗?是的。接下来你要在Tetris中学习两个新的辅助类,这两个类还没有详细讨论过并且是你在本书后面要使用的类的主要版本。不过它们还是会帮助你更容易地开展你的编码进程的。

TextureFont Class

You already learned about the missing font support in XNA and you know that using bitmap fonts is the only option to display text in XNA (apart from using some custom 3D font rendering maybe). In the first games of this book you just used some sprites to display fixed text in the game or menu. This approach was very easy, but for your scoreboard you certainly need a dynamic font allowing you to write down any text and numbers the way you need it in the game.

你已经知道了在XNA中没有字体支持,而且位图字体是现在唯一的显示文本的方法(除了渲染一些3D字体外)。在本书的之前的一些游戏中或目录中使用了一些精灵来显示固定的文字。这个手段非常简单,但是分数板需要的是动态的字体,可以让你在游戏中显示任何的文本和数字。

Let’s go a little bit ahead and take a look at the TestScoreboard unit test in the TetrisGame class, which renders the background box for the scoreboard and then writes down all the text lines to display the current level, score, highscore, and number of lines you destroyed in the current game:

让我们再前进一点,看看TetrisGame 类中的TestScoreboard单元测试,这个用来渲染分数板的背景边框和显示所有的文本行告知当前的等级、分数、最高分和消除的行数。

int level = 3, score = 350, highscore = 1542, lines = 13;
TestGame.Start(
"TestScoreboard",
  
delegate
  
{
    
// Draw background box
    TestGame.game.backgroundSmallBox.Render(new Rectangle(
      (
512 + 240- 1540 - 10290 - 30190));

    
// Show current level, score, etc.
    TextureFont.WriteText(512 + 24050"Level: ");
    TextureFont.WriteText(
512 + 42050, (level + 1).ToString());
    TextureFont.WriteText(
512 + 24090"Score: ");
    TextureFont.WriteText(
512 + 42090, score.ToString());
    TextureFont.WriteText(
512 + 240130"Lines: ");
    TextureFont.WriteText(
512 + 420130, lines.ToString());
    TextureFont.WriteText(
512 + 240170"Highscore: ");
    TextureFont.WriteText(
512 + 420170, highscore.ToString());
}
);

 

You might notice that you are now using the TestGame class to start your unit test. For this test you use a couple of variables (level, score, and so on), which are replaced by the real values in the game code. In the render loop you first draw the background box and display it immediately to avoid display errors with sprites you draw later. Then you write down four lines of text with help of the WriteText method in the new TextureFont class at the specified screen positions. You actually call WriteText eight times to properly align all the numbers at the right side of your background box, which looks much nicer than just writing down everything in four lines.

你可能已经意识到了你现在正在使用TestGame来开始你的单元测试。在这个测试里你使用个几个变量(等级、分数等等),这些在游戏中使用真实值来替代。在渲染循环中你首先要绘制背景框然后立即显示以避免之后你绘制精灵会产生的错误。接着你要在指定位置上写四行文字,则会用到新的TextureFont类中的WriteText方法。你要调用WriteText八次来使所有数字在你的背景框的右边排成一列,这样看起来更美观。

After writing this unit test you will get a compiler error telling you that the TextureFont class does not exist yet. After creating a dummy class with a dummy WriteText method you will be able to compile and start the test. It will just show the background box, which is drawn in the upper-right part of the screen with help of the SpriteHelper class you learned about in the last chapter.

在你写完这个测试之后系统会告知你有一个编译错误——TextureFont类不存在。在创建一个带有挂名的WriteText方法的一个挂名的类之后你就可以编译和运行你的测试了。屏幕上只会显示背景框,被绘制在屏幕的右上角,由上一章中学到的SpriteHelper类来完成。

Before you even think about implementing the TextureFont class you will need the actual bitmap texture with the font in it to render text on the screen. Without a texture you are just doing theoretical work, and unit testing is about practical testing of game functionality. You will need a texture like the one in Figure 4-3 to display all the letters, numbers, and signs. You can even use more Unicode letters in bigger textures or use multiple textures to achieve that, but that would go too far for this chapter. Please check out the websites I provided at the top of the TextureFont class comment in the source code to learn more about this advanced topic.

在你考虑执行TextureFont类之前你需要带有需要的字体的位图纹理文件。没有这个纹理你做的只是理论上的工作,单元测试是关于游戏功能的实践测试。你需要像图4-3那样带有所有字母、数字和符号的纹理。你可能甚至需要更大的带有Unicode字母的纹理,或者使用多个纹理来实现这个。但是这不是本章讨论的重点。在网站上你可以看到TextureFont类源代码的注释,可以学到这个主题的高级内容。


Figure 4-3

Take a look at the implementation of the TextureFont class (see Figure 4-4). Calling the TextureFont class is very easy; you just have to call the WriteText method like in the unit test shown earlier. But the internal code is not very easy. The class stores rectangles for each letter of the GameFont.png texture, which is then used in WriteAll to render text by drawing each letter one by one to the screen. The class also contains the font texture, which is GameFont.png, a sprite batch to help render the font sprites on the screen, and several helper variables to determine the height of the font. For checking how much width a text will consume on the screen you can use the GetTextWidth method.

来看看TextureFont类的实现调用。调用TextureFont类很容易;你只需要像在单元测试里面那样调用WriteText方法。但是内部的代码就不是很容易了。类里面为GameFont.png纹理中的每一个字母保存了一个矩形,这个等下会用在WriteAll里来在屏幕上逐一渲染绘制文字。这个类也包含了字体纹理,在GameFont.png里,一个精灵组在屏幕上渲染字体精灵,还有几个辅助变量来决定字体的高。要检查文本多长会超出屏幕范围可以使用GetTextWidth方法。


Figure 4-4

The internal FontToRender class holds all the text you want to render each frame, which is very similar to the process the SpriteHelper class uses to render all sprites on the screen at the end of each frame. In the same way SpriteHelper.DrawAll is called by BaseGame, TextureFont.WriteAll is also called and flushes everything on the screen and clears all lists. To learn more about the TextureFont class, check out the source code and run the unit tests or try stepping through the WriteAll method.

内部的FontToRender类保存所有每一帧你想渲染的文本,这个和SpriteHelper类在每一帧结束的时候将所有精灵绘制到屏幕上过程是相似的。同样方法,SpriteHelper.DrawAllBaseGame调用,TextureFont.WriteAll也被调用,然后把所有东西都绘制到屏幕上并清空列表。要了解更多关于TextureFont类的信息,请参见源代码并运行单元测试或者试着跟踪WriteAll方法。

Input Class

Another new class that is used in the Tetris game is the Input class, which encapsulates all the input handling, checking, and updating you did in the previous chapters yourself. Chapter 10 talks about the Input class in greater detail and some nice classes that really need all the features from the Input class (see Figure 4-5).

另一个Tetris要使用到的新类是Input类,这个类封装了所有关于输入的操作、检查和前面章节的更新。第十章里还要更详细的讨论Input类,一些好的类也需要Input类的特性。


Figure 4-5

As you can see, the Input class has quite a lot of properties and a few helper methods to access the keyboard, the gamepad, and the mouse data. It will be updated every frame with the help of the static Update method, which is called directly from the BaseGame class. For this game you are mainly going to use the key press and gamepad press methods like GamePadAJustPressed or KeyboardSpaceJustPressed. Similar to the RandomHelper class it is not hard to figure out how this class works, and you already implemented much of the functionally in the previous chapter. For more details and uses you can check out Chapter 10.

就像你看到的,Input类有很多属性和辅助方法来连接到键盘和手柄还有鼠标数据。在静态的Update方法的帮助下Input类每一帧都被更新一次,从BaseGame类中直接调用。对于这个游戏你主要是用到键盘和手柄方法,像GamePadAJustPressedKeyboardSpaceJustPressed方法。类似于RandomHelper类,要知道这个类如何工作并不困难,而且你已经在前面的章节中执行了不少的功能。

Sound Class

Well, you already had sound in the first game in Chapter 2 and you also used it in Chapter 3 for the Breakout game. To keep things simple and to allow you to add more sound functionally later without having to change any of the game classes, the sound management is now moved to the Sound class. Take a quick look at the class (see Figure 4-6). It looks very simple in this version, but in Chapter 9, which also talks about XACT in greater detail, you will extend the Sound class quite a bit and make it ready for your great racing game at the end of this book.

你已经在第二章和第三章使用过了声音。保持事情的简单并允许你添加更多的声音功能而不需要改变任何游戏类,声音管理现在移到了Sound类。来快速浏览一下这个类。这个版本看起来比较简单,但是在第九章中,你将扩展Sound类,为本书最后的一个竞速赛车游戏做好准备,第九章还讲述了关于XACT的详细内容。


Figure 4-6

As you can see, all the sound variables are now in this class and the Game class no longer contains any sound variables. The Sound constructor is static and will be called automatically when you play a sound for the first time with the Play method. The Update method is called automatically from the BaseGame class.

如你所见,所有声音变量现在都在这个类里面,而Game类中不再包含任何的声音变量。Sound构造器是静态的,并且在你第一次使用Play方法播放声音的时候被自动调用。Update方法从BaseGame类中被自动调用。

The Sounds enum values and the TestPlayClickSound unit test depend on the actual content in your current game. These values will change for every game you are going to write from here on, but it is very easy to change the Sounds enum values. You might ask why you don’t just play the sounds with help of the cue names stored in XACT. Well, many errors could occur by just mistyping a sound cue and it is hard to track all changes in case you remove, rename, or change a sound cue. The Sounds enum also makes it very easy to quickly add a sound effect and see which ones are available through IntelliSense.

Sounds枚举值和TestPlayClickSound单元测试由当前游戏的实际素材决定。这些值会根据你写的游戏而不同,但是这些值更改起来很容易。你可能要问为什么我没有使用XACT中的cue名来播放声音。很多错误可能仅仅是因为【mistype】一个声音cue引发的,而且也很难跟踪移除、重命名或者是改变一个声音cueSounds会让这些变得简单容易,可以快速添加一个声音特效并通过IntelliSense来看看哪些是可以利用的。

The Tetris game uses the following sounds:

Tetris使用了下面的声音:

§  BlockMove for moving the block left, right, or down. It is a very silent sound effect.当方块上下左右移动的时候播放。这是一个非常安静的声音效果。。

§  BlockRotate is used when you rotate the current block and it sounds very “whooshy.当你翻转方块的时候播放,这个声音听起来非常的“whooshy”。

§  BlockFalldown is used when the current block reaches the ground and finally lands.当方块下落到底部的时候播放这个声音。

§  LineKill is played every time you manage to kill a line in the game.当你在游戏中消除了一行的时候播放。

§  Fight is played at the start of each game to motivate the player.游戏开始的时候播放。

§  Victory is used when the player reaches the next level and contains an applause sound.当玩家通过这一关到达下一关的时候播放,其中包含了一段喝彩声。

§  Lose is an old school dying sound and is played when the player loses the game.当玩家输掉这一关的时候播放。

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:15953次
    • 积分:267
    • 等级:
    • 排名:千里之外
    • 原创:1篇
    • 转载:0篇
    • 译文:11篇
    • 评论:10条
    文章存档
    最新评论