3.7其他辅助类
Helpers 命名空间中还包括其他一些辅助类,大多数都像 RandomHelper 类一样简单,没有必要把它们都讲一遍,所以请你们自己看一下本章没有讲到的那些辅助类,如果想进一步了解它们可以使用其中的单元测试进行一些测试。
在介绍 Breakout 游戏之前,先简要地看看这样几个辅助类,它们在下面几章中会被反复地使用: SpriteHelper 、 EnumHelper 和 ColorHelper 。
SpriteHelper类
上一章已经讲了很多渲染 sprite 的内容,当时为了配合单元测试而不得不使用一种简单的方式来处理 sprite 。很多时候需要把反复使用的有用代码放进可复用的类中,于是就产生了这样一个 SpriteHelper 类(如图 3-10 所示)。它提供了一个构造函数创建 SpriteHelper 实例,存储 texture 和 Graphic Rectangle 数据,还提供了一些渲染方法更方便地把 sprite 渲染输出到屏幕上,就像上一章中使用 SpriteToRender 类一样。
图3-10
这里的大多数方法的操作都不是很多,构造函数初始化变量的值, Render 方法向 sprite 列表中添加 SpriteToRender 实例, RenderCentered 方法在指定位置居中显示 sprite ,最后 DrawSprites 方法把所有 sprite 画到屏幕上。看一下其中的 DrawSprites 方法,它和前一章中的 DrawSprites 方法很像,不过有一些改进:
public
static
void
DrawSprites(
int
width,
int
height)
{
// No need to render if we got no sprites this frame
if (sprites.Count == 0 )
return ;
// Create sprite batch if we have not done it yet.
// Use device from texture to create the sprite batch.
if (spriteBatch == null )
spriteBatch = new SpriteBatch(sprites[ 0 ].texture.GraphicsDevice);
// Start rendering sprites
spriteBatch.Begin(SpriteBlendMode.AlphaBlend,
SpriteSortMode.BackToFront, SaveStateMode.None);
// Render all sprites
foreach (SpriteToRender sprite in sprites)
spriteBatch.Draw(sprite.texture,
// Rescale to fit resolution
new Rectangle(
sprite.rect.X * width / 1024 ,
sprite.rect.Y * height / 768 ,
sprite.rect.Width * width / 1024 ,
sprite.rect.Height * height / 768 ),
sprite.sourceRect, sprite.color);
// We are done, draw everything on screen with help of the end method.
spriteBatch.End();
// Kill list of remembered sprites
sprites.Clear();
} // DrawSprites()
{
// No need to render if we got no sprites this frame
if (sprites.Count == 0 )
return ;
// Create sprite batch if we have not done it yet.
// Use device from texture to create the sprite batch.
if (spriteBatch == null )
spriteBatch = new SpriteBatch(sprites[ 0 ].texture.GraphicsDevice);
// Start rendering sprites
spriteBatch.Begin(SpriteBlendMode.AlphaBlend,
SpriteSortMode.BackToFront, SaveStateMode.None);
// Render all sprites
foreach (SpriteToRender sprite in sprites)
spriteBatch.Draw(sprite.texture,
// Rescale to fit resolution
new Rectangle(
sprite.rect.X * width / 1024 ,
sprite.rect.Y * height / 768 ,
sprite.rect.Width * width / 1024 ,
sprite.rect.Height * height / 768 ),
sprite.sourceRect, sprite.color);
// We are done, draw everything on screen with help of the end method.
spriteBatch.End();
// Kill list of remembered sprites
sprites.Clear();
} // DrawSprites()
在调用该方法的时候,传递当前窗口分辨率的宽度和高度,并根据当前分辨率对所有 sprite 进行比例缩放,这对于支持 Xbox 360 的多分辨率非常重要。方法首先检查是否有东西要渲染,然后确保 SpriteBatch 类的静态实例(就是这里的 spriteBatch 变量)是否已被创建,调用 Begin 方法之后,在当前帧中遍历所有的 sprite 并重新调整它们的尺寸以适应当前屏幕的大小,最后当把所有 sprite 画到屏幕上之后再调用 End 方法。另外还要把 sprite 列表清空,为下一帧的渲染做准备。可以研究本章最后的 Breakout 游戏来看看这个类是如何工作的。
EnumHelper类
EnumHelper 类(如图 3-11 所示)对于遍历枚举项以及获取枚举值的个数等操作非常有用。在 Pong 和 Breakout 游戏中没有用到任何枚举类型,但下一章的游戏在遍历 block 类型的时候使用 Enum 类( System.Enum )有很大帮助。注意, EnumHelper 类用到了 Enum 类的几个方法,这些方法在 .Net Compact Framework 中并没有被实现。为了避免编译错误,在 Xbox 360 项目中通常排除整个 EnumHelper 类,不过在 Windows 平台上可以使用它。
图3-11
单元测试的 TestGetAllEnumNames 方法如下所示,该测试说明了 GetAllEnumNames 方法是如何工作的,它借助 EnumHelper 类内部定义的 EnumEnumerator 辅助类来遍历所有的枚举值。
[Test]
public void TestGetAllEnumNames()
{
Assert.AreEqual(
" Missions, Highscore, Credits, Help, Options, Exit, Back " ,
EnumHelper.GetAllEnumNames( typeof (MenuButton)));
} // TestGetAllEnumNames()
public void TestGetAllEnumNames()
{
Assert.AreEqual(
" Missions, Highscore, Credits, Help, Options, Exit, Back " ,
EnumHelper.GetAllEnumNames( typeof (MenuButton)));
} // TestGetAllEnumNames()
GetAllEnumNames 方法则使用了之前讨论的 StringHelper 类中的 WriteArrayData 方法:
public
static
string
GetAllEnumNames(Type type)
{
return StringHelper.WriteArrayData(GetEnumerator(type));
} // GetAllEnumNames(type)
{
return StringHelper.WriteArrayData(GetEnumerator(type));
} // GetAllEnumNames(type)
ColorHelper类
ColorHelper 类如图 3-12 所示,原本它还有更多的方法,但 XNA 中新的 Color 类比托管 DirectX 中使用的 System.Drawings 中的 Color 类的功能更加强大,所以有很多方法就不再需要了,不过它还是包含了一些对颜色操作非常有用的方法。
图3-12
例如, ColorHelper.Empty 字段可以用来把 shader 效果参数设置为空值—— 0,0,0,0 通常不是有效颜色值,它是完全透明的,而黑色的 Alpha 值是 255 。
///
<summary>
/// Empty color, used to mark unused color values.
/// </summary>
public static readonly Color Empty = new Color( 0 , 0 , 0 , 0 );
/// Empty color, used to mark unused color values.
/// </summary>
public static readonly Color Empty = new Color( 0 , 0 , 0 , 0 );